package com.github.ltsopensource.core.failstore.leveldb;
import com.github.ltsopensource.core.commons.file.FileUtils;
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.json.JSON;
import org.fusesource.leveldbjni.JniDBFactory;
import org.iq80.leveldb.*;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Only a single process (possibly multi-threaded) can access a particular database at a time
* Robert HG (254963746@qq.com) on 5/21/15.
*/
public class LeveldbFailStore extends AbstractFailStore {
private DB db;
private Options options;
public static final String name = "leveldb";
public LeveldbFailStore(File dbPath, boolean needLock) {
super(dbPath, needLock);
}
@Override
protected void init() throws FailStoreException {
try {
options = new Options();
options.createIfMissing(true);
options.cacheSize(100 * 1024 * 1024); // 100M
options.maxOpenFiles(400);
} catch (Exception e) {
throw new FailStoreException(e);
}
}
protected String getName() {
return name;
}
@Override
public void open() throws FailStoreException {
try {
JniDBFactory.factory.repair(dbPath, options);
db = JniDBFactory.factory.open(dbPath, options);
} catch (IOException e) {
throw new FailStoreException(e);
}
}
@Override
public void put(String key, Object value) throws FailStoreException {
try {
String valueString = JSON.toJSONString(value);
assert valueString != null;
db.put(key.getBytes("UTF-8"), valueString.getBytes("UTF-8"));
} catch (Exception e) {
throw new FailStoreException(e);
}
}
@Override
public void delete(String key) throws FailStoreException {
try {
if (key == null) {
return;
}
db.delete(key.getBytes("UTF-8"));
} catch (Exception e) {
throw new FailStoreException(e);
}
}
@Override
public void delete(List<String> keys) throws FailStoreException {
if (keys == null || keys.size() == 0) {
return;
}
WriteBatch batch = db.createWriteBatch();
try {
for (String key : keys) {
batch.delete(key.getBytes("UTF-8"));
}
db.write(batch);
} catch (UnsupportedEncodingException e) {
throw new FailStoreException(e);
} finally {
try {
batch.close();
} catch (IOException ignored) {
}
}
}
@Override
public <T> List<Pair<String, T>> fetchTop(int size, Type type) throws FailStoreException {
Snapshot snapshot = db.getSnapshot();
DBIterator iterator = null;
try {
List<Pair<String, T>> list = new ArrayList<Pair<String, T>>(size);
ReadOptions options = new ReadOptions();
options.snapshot(snapshot);
iterator = db.iterator(options);
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
Map.Entry<byte[], byte[]> entry = iterator.peekNext();
String key = new String(entry.getKey(), "UTF-8");
T value = JSON.parse(new String(entry.getValue(), "UTF-8"), 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 (iterator != null) {
try {
iterator.close();
} catch (IOException ignored) {
}
}
try {
snapshot.close();
} catch (IOException ignored) {
}
}
}
@Override
public void close() throws FailStoreException {
try {
if (db != null) {
db.close();
}
} catch (IOException e) {
throw new FailStoreException(e);
}
}
public void destroy() throws FailStoreException {
try {
close();
JniDBFactory.factory.destroy(dbPath, options);
} catch (IOException e) {
throw new FailStoreException(e);
} finally {
if (fileLock != null) {
fileLock.release();
}
FileUtils.delete(dbPath);
}
}
}