package com.github.ltsopensource.kv;
import com.github.ltsopensource.core.commons.file.FileUtils;
import com.github.ltsopensource.kv.cache.DataCache;
import com.github.ltsopensource.kv.cache.LRUDataCache;
import com.github.ltsopensource.kv.data.DataAppendResult;
import com.github.ltsopensource.kv.data.DataBlockEngine;
import com.github.ltsopensource.kv.index.*;
import com.github.ltsopensource.kv.iterator.DBIterator;
import com.github.ltsopensource.kv.replay.TxLogReplay;
import com.github.ltsopensource.kv.serializer.StoreSerializer;
import com.github.ltsopensource.kv.txlog.StoreTxLogEngine;
import com.github.ltsopensource.kv.txlog.StoreTxLogPosition;
import java.io.Closeable;
/**
* ------- PUT(REMOVE) --------
* 1. 一次 事务日志 (TxLog) 的顺序写入
* 2. 一次 数据文件 (Data) 的顺序写入
* 3. 一次 内存索引 (Index) 的写入 (后面实现B+树)
* 4. 数据缓存
* <p/>
* ------- GET --------
* 1. 缓存数据中 GET 命中即返回
* 2. 从数据文件 (DATA) 中GET
*
* @author Robert HG (254963746@qq.com) on 12/13/15.
*/
public class DBImpl<K, V> implements DB<K, V>, Closeable {
private StoreTxLogEngine<K, V> storeTxLogEngine;
private DataBlockEngine<K, V> dataBlockEngine;
private StoreConfig storeConfig;
private Index<K, V> index;
private DataCache<K, V> dataCache;
private IndexSnapshot<K, V> indexSnapshot;
private TxLogReplay<K, V> txLogReplay;
public DBImpl(StoreSerializer serializer, StoreConfig storeConfig) {
this.storeConfig = storeConfig;
this.dataCache = new LRUDataCache<K, V>(storeConfig.getMaxDataCacheSize());
this.storeTxLogEngine = new StoreTxLogEngine<K, V>(serializer, storeConfig);
this.dataBlockEngine = new DataBlockEngine<K, V>(serializer, storeConfig);
if (IndexType.MEM == storeConfig.getIndexType()) {
this.index = new MemIndex<K, V>(storeConfig, dataBlockEngine, dataCache);
this.txLogReplay = new TxLogReplay<K, V>(storeTxLogEngine, dataBlockEngine, index, dataCache);
this.indexSnapshot = new MemIndexSnapshot<K, V>(txLogReplay, index, storeConfig, serializer);
((MemIndex<K, V>) this.index).setIndexSnapshot(this.indexSnapshot);
} else {
throw new IllegalArgumentException("Illegal IndexEngine " + storeConfig.getIndexType());
}
}
public void init() throws DBException {
try {
FileUtils.createDirIfNotExist(storeConfig.getDbPath());
storeTxLogEngine.init();
dataBlockEngine.init();
indexSnapshot.init();
} catch (Exception e) {
throw new DBException("DB init error:" + e.getMessage(), e);
}
}
public int size() {
return index.size();
}
public boolean containsKey(K key) {
return index.containsKey(key);
}
public V get(K key) {
// 1. 从缓存中获取
V value = dataCache.get(key);
if (value != null) {
return value;
}
IndexItem<K> indexItem = index.getIndexItem(key);
if (indexItem == null) {
return null;
}
// 2. 从Data文件读取
return dataBlockEngine.getValue(indexItem);
}
public void put(K key, V value) {
// 1. 先写Log
StoreTxLogPosition storeTxLogPosition = storeTxLogEngine.append(Operation.PUT, key, value);
// 2. 写Data
DataAppendResult dataAppendResult = dataBlockEngine.append(storeTxLogPosition, key, value);
// 3. 写Index
index.putIndexItem(storeTxLogPosition, key, convertToIndex(key, dataAppendResult));
// 4. 写缓存
dataCache.put(key, value);
}
public void remove(K key) {
// 先移除缓存
dataCache.remove(key);
// 1. 先写Log
StoreTxLogPosition storeTxLogPosition = storeTxLogEngine.append(Operation.REMOVE, key);
// 2. 移除Index
IndexItem<K> indexItem = index.removeIndexItem(storeTxLogPosition, key);
if (indexItem != null) {
// 3. 移除Data
dataBlockEngine.remove(storeTxLogPosition, indexItem);
}
}
public DBIterator<Entry<K, V>> iterator() {
return index.iterator();
}
@Override
public void close() {
dataCache.clear();
}
public static <K> IndexItem<K> convertToIndex(K key, DataAppendResult result) {
IndexItem<K> index = new IndexItem<K>();
index.setKey(key);
index.setFileId(result.getFileId());
index.setFromIndex(result.getFromIndex());
index.setLength(result.getLength());
return index;
}
}