package com.github.ltsopensource.core.failstore.berkeleydb; import com.github.ltsopensource.core.commons.file.FileUtils; import com.github.ltsopensource.core.commons.utils.CollectionUtils; import com.github.ltsopensource.core.json.JSON; import com.github.ltsopensource.core.domain.Pair; import com.github.ltsopensource.core.failstore.AbstractFailStore; import com.github.ltsopensource.core.failstore.FailStoreException; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import com.sleepycat.je.*; import java.io.File; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * Robert HG (254963746@qq.com) on 5/26/15. */ public class BerkeleydbFailStore extends AbstractFailStore { private static final Logger LOGGER = LoggerFactory.getLogger(BerkeleydbFailStore.class); private Environment environment; private Database db; private EnvironmentConfig envConfig; private DatabaseConfig dbConfig; public BerkeleydbFailStore(File dbPath, boolean needLock) { super(dbPath, needLock); } public static final String name = "berkeleydb"; @Override protected void init() throws FailStoreException{ try { envConfig = new EnvironmentConfig(); // 如果不存在则创建一个 envConfig.setAllowCreate(true); // 以只读方式打开,默认为false envConfig.setReadOnly(false); // 事务支持,如果为true,则表示当前环境支持事务处理,默认为false,不支持事务处理 envConfig.setTransactional(true); // Configures the durability associated with transactions. envConfig.setDurability(Durability.COMMIT_SYNC); dbConfig = new DatabaseConfig(); dbConfig.setAllowCreate(true); dbConfig.setSortedDuplicates(false); dbConfig.setTransactional(true); } catch (DatabaseException e) { throw new FailStoreException(e); } } @Override public void open() throws FailStoreException { try { environment = new Environment(dbPath, envConfig); db = environment.openDatabase(null, "lts", dbConfig); } catch (Exception e) { throw new FailStoreException(e); } } @Override public void put(String key, Object value) throws FailStoreException { try { String valueString = JSON.toJSONString(value); @SuppressWarnings("unused") OperationStatus status = db.put(null, new DatabaseEntry(key.getBytes("UTF-8")), new DatabaseEntry(valueString.getBytes("UTF-8"))); } catch (Exception e) { throw new FailStoreException(e); } } @Override public void delete(String key) throws FailStoreException { try { DatabaseEntry delKey = new DatabaseEntry(); delKey.setData(key.getBytes("UTF-8")); @SuppressWarnings("unused") OperationStatus status = db.delete(null, delKey); } catch (Exception e) { throw new FailStoreException(e); } } @Override public void delete(List<String> keys) throws FailStoreException { if (CollectionUtils.isEmpty(keys)) { return; } for (String key : keys) { delete(key); } } @Override public <T> List<Pair<String, T>> fetchTop(int size, Type type) throws FailStoreException { Cursor cursor = null; try { List<Pair<String, T>> list = new ArrayList<Pair<String, T>>(); cursor = db.openCursor(null, CursorConfig.DEFAULT); DatabaseEntry foundKey = new DatabaseEntry(); DatabaseEntry foundValue = new DatabaseEntry(); while (cursor.getNext(foundKey, foundValue, LockMode.DEFAULT) == OperationStatus.SUCCESS) { String key = new String(foundKey.getData(), "UTF-8"); String valueString = new String(foundValue.getData(), "UTF-8"); T value = JSON.parse(valueString, type); Pair<String, T> pair = new Pair<String, T>(key, value); list.add(pair); if (list.size() >= size) { break; } } return list; } catch (Exception e) { throw new FailStoreException(e); } finally { if (cursor != null) { try { cursor.close(); } catch (DatabaseException e) { LOGGER.warn("close cursor failed! ", e); } } } } @Override public void close() throws FailStoreException { try { if (db != null) { db.close(); } if (environment != null && environment.isValid()) { environment.cleanLog(); environment.close(); } } catch (Exception e) { throw new FailStoreException(e); } } @Override public void destroy() throws FailStoreException { try { if (environment != null) { environment.removeDatabase(null, db.getDatabaseName()); environment.close(); } } catch (Exception e) { throw new FailStoreException(e); } finally { if (fileLock != null) { fileLock.release(); } FileUtils.delete(dbPath); } } @Override protected String getName() { return name; } }