package com.github.ltsopensource.core.failstore; import com.github.ltsopensource.core.commons.file.FileLock; import com.github.ltsopensource.core.commons.file.FileUtils; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; /** * Robert HG (254963746@qq.com) on 7/5/15. */ public abstract class AbstractFailStore implements FailStore { private static final Logger LOGGER = LoggerFactory.getLogger(FailStore.class); protected FileLock fileLock; private String home; protected File dbPath; private static final String dbLockName = "___db.lock"; public AbstractFailStore(File dbPath, boolean needLock) { try { this.dbPath = dbPath; String path = dbPath.getPath(); this.home = path.substring(0, path.indexOf(getName())).concat(getName()); if (needLock) { getLock(dbPath.getPath()); } init(); } catch (Exception e) { throw new RuntimeException(e); } } protected String getLock(String failStorePath) throws IOException { // get sequence FileUtils.createDirIfNotExist(failStorePath); // 有可能两个进程同时创建这个目录,所以用文件锁来得到控制权 fileLock = new FileLock(failStorePath.concat("/").concat(dbLockName)); boolean locked = fileLock.tryLock(); // 1s if (!locked) { throw new IllegalStateException("can not get current file lock."); } LOGGER.info("Current failStore path is {}", failStorePath); return failStorePath; } public List<FailStore> getDeadFailStores() { File homeDir = new File(home); File[] subFiles = homeDir.listFiles(); List<FailStore> deadFailStores = new ArrayList<FailStore>(); if (subFiles != null && subFiles.length != 0) { for (File subFile : subFiles) { try { if (subFile.isDirectory()) { FileLock tmpLock = new FileLock(subFile.getPath().concat("/").concat(dbLockName)); boolean locked = tmpLock.tryLock(); if (locked) { // 能获得锁,说明这个目录锁对应的节点已经down了 FailStore failStore = getFailStore(subFile); if (failStore != null) { deadFailStores.add(failStore); } tmpLock.release(); } } } catch (Exception e) { // ignore LOGGER.error(e.getMessage(), e); } } } return deadFailStores; } private FailStore getFailStore(File dbPath) { try { Constructor<? extends FailStore> constructor = this.getClass().getConstructor(File.class, boolean.class); return constructor.newInstance(dbPath, false); } catch (Exception e) { LOGGER.error("new instance failStore failed,", e); } return null; } protected abstract void init() throws FailStoreException; protected abstract String getName(); @Override public String getPath() { return dbPath.getPath(); } }