package com.github.ltsopensource.kv.index;
import com.github.ltsopensource.core.factory.NamedThreadFactory;
import com.github.ltsopensource.core.logger.Logger;
import com.github.ltsopensource.core.logger.LoggerFactory;
import com.github.ltsopensource.kv.Entry;
import com.github.ltsopensource.kv.StoreConfig;
import com.github.ltsopensource.kv.cache.DataCache;
import com.github.ltsopensource.kv.data.DataBlockEngine;
import com.github.ltsopensource.kv.iterator.DBIterator;
import com.github.ltsopensource.kv.iterator.MemIteratorImpl;
import com.github.ltsopensource.kv.txlog.StoreTxLogPosition;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author Robert HG (254963746@qq.com) on 12/16/15.
*/
public class MemIndex<K, V> implements Index<K, V> {
private static final Logger LOGGER = LoggerFactory.getLogger(MemIndex.class);
private StoreTxLogPosition lastTxLog;
private ConcurrentMap<K, IndexItem<K>> indexMap;
private StoreConfig storeConfig;
private DataBlockEngine<K, V> dataBlockEngine;
private DataCache<K, V> dataCache;
private AtomicLong lastSnapshotChangeNum = new AtomicLong(0);
private AtomicLong currentChangeNum = new AtomicLong(0);
private IndexSnapshot<K, V> indexSnapshot;
public MemIndex(final StoreConfig storeConfig, DataBlockEngine<K, V> dataBlockEngine, DataCache<K, V> dataCache) {
this.indexMap = new ConcurrentSkipListMap<K, IndexItem<K>>();
this.storeConfig = storeConfig;
this.dataBlockEngine = dataBlockEngine;
this.dataCache = dataCache;
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("ltsdb-index-snapshot-check-service", true));
executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
// 检查一下当改变的量达到一定量时要snapshot
if (currentChangeNum.get() - lastSnapshotChangeNum.get() > storeConfig.getIndexSnapshotThreshold()) {
indexSnapshot.snapshot();
}
} catch (Throwable t) {
LOGGER.error("SNAPSHOT Error", t);
}
}
}, 3, 2, TimeUnit.SECONDS);
}
public IndexItem<K> getIndexItem(K key) {
return indexMap.get(key);
}
@Override
public IndexItem<K> removeIndexItem(StoreTxLogPosition txLogResult, K key) {
IndexItem<K> value = indexMap.remove(key);
this.lastTxLog = txLogResult;
currentChangeNum.incrementAndGet();
return value;
}
@Override
public void putIndexItem(StoreTxLogPosition txLogResult, K key, IndexItem<K> indexItem) {
indexMap.put(key, indexItem);
this.lastTxLog = txLogResult;
currentChangeNum.incrementAndGet();
}
@Override
public int size() {
return indexMap.size();
}
@Override
public boolean containsKey(K key) {
return indexMap.containsKey(key);
}
@Override
public DBIterator<Entry<K, V>> iterator() {
return new MemIteratorImpl<K, V>(this, dataBlockEngine, dataCache);
}
@Override
public StoreTxLogPosition lastTxLog() {
return lastTxLog;
}
void setLastTxLog(StoreTxLogPosition lastTxLog) {
this.lastTxLog = lastTxLog;
}
public ConcurrentMap<K, IndexItem<K>> getIndexMap() {
return indexMap;
}
void setIndexMap(ConcurrentMap<K, IndexItem<K>> indexMap) {
this.indexMap = indexMap;
}
public void setIndexSnapshot(IndexSnapshot<K, V> indexSnapshot) {
this.indexSnapshot = indexSnapshot;
}
}