聊聊claudb的Database

序 本文主要研究一下claudb的Database
Database claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/Database.java

public interface Database {int size(); boolean isEmpty(); boolean containsKey(DatabaseKey key); DatabaseValue get(DatabaseKey key); DatabaseValue put(DatabaseKey key, DatabaseValue value); DatabaseValue remove(DatabaseKey key); void clear(); ImmutableSet keySet(); Sequence values(); ImmutableSet> entrySet(); default SafeString getString(SafeString key) { return getOrDefault(safeKey(key), DatabaseValue.EMPTY_STRING).getString(); }default ImmutableList getList(SafeString key) { return getOrDefault(safeKey(key), DatabaseValue.EMPTY_LIST).getList(); }default ImmutableSet getSet(SafeString key) { return getOrDefault(safeKey(key), DatabaseValue.EMPTY_SET).getSet(); }default NavigableSet> getSortedSet(SafeString key) { return getOrDefault(safeKey(key), DatabaseValue.EMPTY_ZSET).getSortedSet(); }default ImmutableMap getHash(SafeString key) { return getOrDefault(safeKey(key), DatabaseValue.EMPTY_HASH).getHash(); }default void putAll(ImmutableMap map) { map.forEach(this::put); }default DatabaseValue putIfAbsent(DatabaseKey key, DatabaseValue value) { DatabaseValue oldValue = https://www.it610.com/article/get(key); if (oldValue == null) { oldValue = put(key, value); } return oldValue; }default DatabaseValue merge(DatabaseKey key, DatabaseValue value, BiFunction remappingFunction) { DatabaseValue oldValue = https://www.it610.com/article/get(key); DatabaseValue newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value); if(newValue == null) { remove(key); } else { put(key, newValue); } return newValue; }default DatabaseValue getOrDefault(DatabaseKey key, DatabaseValue defaultValue) { DatabaseValue value = get(key); return (value != null || containsKey(key)) ? value : defaultValue; }default boolean isType(DatabaseKey key, DataType type) { DatabaseValue value = get(key); return value != null ? value.getType() == type : true; }default boolean rename(DatabaseKey from, DatabaseKey to) { DatabaseValue value = remove(from); if (value != null) { put(to, value); return true; } return false; }default void overrideAll(ImmutableMap value) { clear(); putAll(value); }default ImmutableSet evictableKeys(Instant now) { return entrySet() .filter(entry -> entry.get2().isExpired(now)) .map(Tuple2::get1); } }

  • Database接口定义了size、isEmpty、containsKey、get、put、remove、clear、keySet、values、entrySet方法;同时还提供了getString、getList、getSet、getSortedSet、getHash、putAll、putIfAbsent、merge、getOrDefault、isType、rename、overrideAll、evictableKeys这几个default方法
OnHeapDatabase
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/OnHeapDatabase.java
public class OnHeapDatabase implements Database {private final Map cache; public OnHeapDatabase(Map cache) { this.cache = cache; }@Override public int size() { return cache.size(); }@Override public boolean isEmpty() { return cache.isEmpty(); }@Override public boolean containsKey(DatabaseKey key) { return cache.containsKey(key); }@Override public DatabaseValue get(DatabaseKey key) { DatabaseValue value = https://www.it610.com/article/cache.get(key); if (value != null) { if (!value.isExpired(Instant.now())) { return value; } cache.remove(key); } return null; }@Override public DatabaseValue put(DatabaseKey key, DatabaseValue value) { DatabaseValue oldValue = cache.remove(key); cache.put(key, value); return oldValue; }@Override public DatabaseValue remove(DatabaseKey key) { return cache.remove(key); }@Override public void clear() { cache.clear(); }@Override public ImmutableSet keySet() { return ImmutableSet.from(cache.keySet()); }@Override public Sequence values() { return ImmutableSet.from(cache.values()); }@Override public ImmutableSet> entrySet() { return ImmutableSet.from(cache.entrySet()).map(Tuple::from); } }

  • OnHeapDatabase实现了Database接口,它使用Map结构作为cache;其get方法在取出value不为null时会判断该value是否过期,如果过期则移除该key,返回null;其put方法会先执行remove获取oldValue,在put进去新值,最后返回oldValue
OffHeapDatabase
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/OffHeapDatabase.java
public class OffHeapDatabase implements Database {private OHCache cache; public OffHeapDatabase(OHCache cache) { this.cache = cache; }@Override public int size() { return (int) cache.size(); }@Override public boolean isEmpty() { return cache.size() == 0; }@Override public boolean containsKey(DatabaseKey key) { return cache.containsKey(key); }@Override public DatabaseValue get(DatabaseKey key) { DatabaseValue value = https://www.it610.com/article/cache.get(key); if (value != null) { if (!value.isExpired(Instant.now())) { return value; } cache.remove(key); } return null; }@Override public DatabaseValue put(DatabaseKey key, DatabaseValue value) { cache.put(key, value); return value; }@Override public DatabaseValue remove(DatabaseKey key) { DatabaseValue value = get(key); cache.remove(key); return value; }@Override public void clear() { cache.clear(); }@Override public ImmutableSet keySet() { Set keys = new HashSet<>(); try (CloseableIterator iterator = cache.keyIterator()) { while (iterator.hasNext()) { keys.add(iterator.next()); } } catch(IOException e) { throw new UncheckedIOException(e); } return ImmutableSet.from(keys); }@Override public Sequence values() { List values = new LinkedList<>(); for (DatabaseKey key : keySet()) { values.add(cache.get(key)); } return ImmutableList.from(values); }@Override public ImmutableSet> entrySet() { return keySet().map(key -> Tuple.of(key, get(key))); } }

  • OffHeapDatabase实现了Database接口,它使用OHCache作为cache,其get方法在取出value不为null时会判断该value是否过期,如果过期则移除该key,返回null;其put方法直接往cache覆盖该key,返回的是新值
DatabaseFactory claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/DatabaseFactory.java
public interface DatabaseFactory { Database create(String name); void clear(); }

  • DatabaseFactory接口定义了create、clear方法
OnHeapDatabaseFactory
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/OnHeapDatabaseFactory.java
public class OnHeapDatabaseFactory implements DatabaseFactory {@Override public Database create(String name) { return new OnHeapDatabase(new HashMap<>()); }@Override public void clear() { // nothing to clear } }

  • OnHeapDatabaseFactory实现了DatabaseFactory接口,其create使用HashMap创建OnHeapDatabase
OffHeapDatabaseFactory
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/data/OffHeapDatabaseFactory.java
public class OffHeapDatabaseFactory implements DatabaseFactory {@Override public Database create(String name) { return new OffHeapDatabase(createCache()); }private OHCache createCache() { return builder() .eviction(Eviction.NONE) .throwOOME(true) .keySerializer(new FSTSerializer<>()) .valueSerializer(new FSTSerializer<>()) .build(); }private OHCacheBuilder builder() { return OHCacheBuilder.newBuilder(); }@Override public void clear() { // nothing to do }private static class FSTSerializer implements CacheSerializer {private static final FSTConfiguration FST = FSTConfiguration.createDefaultConfiguration(); static { FST.registerClass(DatabaseValue.class); FST.registerClass(DatabaseKey.class); FST.registerClass(SafeString.class); FST.registerClass(SortedSet.class); }@Override public void serialize(E value, ByteBuffer buf) { byte[] array = FST.asByteArray(value); buf.putInt(array.length); buf.put(array); }@SuppressWarnings("unchecked") @Override public E deserialize(ByteBuffer buf) { int length = buf.getInt(); byte[] array = new byte[length]; buf.get(array); return (E) FST.asObject(array); }@Override public int serializedSize(E value) { return FST.asByteArray(value).length + Integer.BYTES; } } }

  • OffHeapDatabaseFactory实现了DatabaseFactory接口,其create方法创建的是OffHeapDatabase;其createCache方法使用OHCacheBuilder来构造OHCache,其eviction为NONE,其throwOOME为true;其keySerializer及valueSerializer均为FSTSerializer
小结 【聊聊claudb的Database】claudb提供了OnHeapDatabase、OffHeapDatabase两种实现,前者使用HashMap,后者使用OHCache
doc
  • Database

    推荐阅读