本文主要研究一下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<DatabaseKey> keySet();

  Sequence<DatabaseValue> values();

  ImmutableSet<Tuple2<DatabaseKey, DatabaseValue>> entrySet();

  default SafeString getString(SafeString key) {
    return getOrDefault(safeKey(key), DatabaseValue.EMPTY_STRING).getString();
  }

  default ImmutableList<SafeString> getList(SafeString key) {
    return getOrDefault(safeKey(key), DatabaseValue.EMPTY_LIST).getList();
  }

  default ImmutableSet<SafeString> getSet(SafeString key) {
    return getOrDefault(safeKey(key), DatabaseValue.EMPTY_SET).getSet();
  }

  default NavigableSet<Entry<Double, SafeString>> getSortedSet(SafeString key) {
    return getOrDefault(safeKey(key), DatabaseValue.EMPTY_ZSET).getSortedSet();
  }

  default ImmutableMap<SafeString, SafeString> getHash(SafeString key) {
    return getOrDefault(safeKey(key), DatabaseValue.EMPTY_HASH).getHash();
  }

  default void putAll(ImmutableMap<? extends DatabaseKey, ? extends DatabaseValue> map) {
    map.forEach(this::put);
  }

  default DatabaseValue putIfAbsent(DatabaseKey key, DatabaseValue value) {
    DatabaseValue oldValue = get(key);
    if (oldValue == null) {
        oldValue = put(key, value);
    }
    return oldValue;
  }

  default DatabaseValue merge(DatabaseKey key, DatabaseValue value,
      BiFunction<DatabaseValue, DatabaseValue, DatabaseValue> remappingFunction) {
    DatabaseValue oldValue = 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<DatabaseKey, DatabaseValue> value) {
    clear();
    putAll(value);
  }

  default ImmutableSet<DatabaseKey> 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<DatabaseKey, DatabaseValue> cache;

  public OnHeapDatabase(Map<DatabaseKey, DatabaseValue> 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 = 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<DatabaseKey> keySet() {
    return ImmutableSet.from(cache.keySet());
  }

  @Override
  public Sequence<DatabaseValue> values() {
    return ImmutableSet.from(cache.values());
  }

  @Override
  public ImmutableSet<Tuple2<DatabaseKey, DatabaseValue>> 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<DatabaseKey, DatabaseValue> cache;

  public OffHeapDatabase(OHCache<DatabaseKey, DatabaseValue> 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 = 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<DatabaseKey> keySet() {
    Set<DatabaseKey> keys = new HashSet<>();
    try (CloseableIterator<DatabaseKey> iterator = cache.keyIterator()) {
      while (iterator.hasNext()) {
        keys.add(iterator.next());
      }
    } catch(IOException e) {
      throw new UncheckedIOException(e);
    }
    return ImmutableSet.from(keys);
  }

  @Override
  public Sequence<DatabaseValue> values() {
    List<DatabaseValue> values = new LinkedList<>();
    for (DatabaseKey key : keySet()) {
      values.add(cache.get(key));
    }
    return ImmutableList.from(values);
  }

  @Override
  public ImmutableSet<Tuple2<DatabaseKey, DatabaseValue>> 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<DatabaseKey, DatabaseValue> createCache() {
    return builder()
        .eviction(Eviction.NONE)
        .throwOOME(true)
        .keySerializer(new FSTSerializer<>())
        .valueSerializer(new FSTSerializer<>())
        .build();
  }

  private OHCacheBuilder<DatabaseKey, DatabaseValue> builder() {
    return OHCacheBuilder.newBuilder();
  }

  @Override
  public void clear() {
    // nothing to do
  }

  private static class FSTSerializer<E> implements CacheSerializer<E> {

    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提供了OnHeapDatabase、OffHeapDatabase两种实现,前者使用HashMap,后者使用OHCache

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...