package com.alibaba.doris.dataserver.store.bdb;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.doris.common.data.Key;
import com.alibaba.doris.common.data.Pair;
import com.alibaba.doris.common.data.Value;
import com.alibaba.doris.dataserver.store.BaseStorage;
import com.alibaba.doris.dataserver.store.StorageType;
import com.alibaba.doris.dataserver.store.exception.StorageException;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.LockTimeoutException;
/**
* @author ajun Email:jack.yuj@alibaba-inc.com
*/
public class BDBStorage extends BaseStorage {
public BDBStorage(BDBDataBaseFactory databaseFactory) {
this.databaseFactory = databaseFactory;
}
public void close() {
// 刷新cache,释放资源
Set<Entry<String, BDBDataBase>> entrySet = databaseMap.entrySet();
Iterator<Entry<String, BDBDataBase>> itr = entrySet.iterator();
while (itr.hasNext()) {
itr.next().getValue().close();
}
List<Environment> envList = databaseFactory.getEnvironmentList();
for (Environment env : envList) {
env.close();
}
}
public void open() {
// 打开文件,如果是第一次启动,需要初始化文件信息。
List<Environment> envList = databaseFactory.getEnvironmentList();
// load 所有已经存在的database。
for (Environment localEnv : envList) {
for (String name : localEnv.getDatabaseNames()) {
getDataBase(name);
}
}
}
public Value get(Key key) {
if (null == key || StringUtils.isBlank(key.getKey())) {
throw new IllegalArgumentException("Key can't be null!");
}
BDBDataBase db = getDataBase(getDatabaseName(key));
Value value = db.get(key);
if (logger.isDebugEnabled()) {
if (value != null) {
logger.debug("get: key=" + key + " timestamp=" + value.getTimestamp());
} else {
logger.debug("get: key=" + key + " value is null.");
}
}
return value;
}
public Map<Key, Value> getAll(Iterable<Key> keyIterator) {
int size = ((Collection<?>) keyIterator).size();
Map<Key, Value> result = new HashMap<Key, Value>(size);
for (Key key : keyIterator) {
Value value = get(key);
if (value != null) {
result.put(key, value);
}
}
return result;
}
public void set(Key key, Value value) {
BDBDataBase db = getDataBase(getDatabaseName(key));
db.set(key, value);
}
public void set(Key key, Value value, boolean isSetWithCompareVersion) {
if (null == key || StringUtils.isBlank(key.getKey())) {
throw new IllegalArgumentException("Key can't be null!");
}
if (null == value) {
throw new IllegalArgumentException("Value can't be null!");
}
if (logger.isDebugEnabled()) {
logger.debug("set: key=" + key + " timestamp=" + value.getTimestamp());
}
BDBDataBase db = getDataBase(getDatabaseName(key));
try {
db.set(key, value, isSetWithCompareVersion);
} catch (LockTimeoutException writeFailedException) {
// get lock failed, retry.
db.set(key, value, isSetWithCompareVersion);
}
}
public StorageType getType() {
return BDBStorageDriver.type;
}
public boolean delete(Key key) {
if (null == key || StringUtils.isBlank(key.getKey())) {
throw new IllegalArgumentException("Key can't be null!");
}
BDBDataBase db = getDataBase(getDatabaseName(key));
try {
return db.delete(key);
} catch (LockTimeoutException writeFailedException) {
// get lock failed, retry.
return db.delete(key);
}
}
public boolean delete(Key key, Value value) {
if (null == key || StringUtils.isBlank(key.getKey())) {
throw new IllegalArgumentException("Key can't be null!");
}
if (null == value) {
throw new IllegalArgumentException("Value can't be null!");
}
BDBDataBase db = getDataBase(getDatabaseName(key));
try {
return db.delete(key, value);
} catch (LockTimeoutException writeFailedException) {
// get lock failed, retry.
return db.delete(key, value);
}
}
public boolean delete(List<Integer> vnodeList) {
boolean isSuccess = false;
if (null == vnodeList || vnodeList.size() <= 0) {
throw new IllegalArgumentException("Invalid argument. The vnodeList can't be empty list.");
}
String dbName = getDatabaseName(vnodeList.get(0));
if (SINGLE_DATA_BASE_NAME.equals(dbName)) {
BDBDataBase db = getDataBase(dbName);
if (null != db) {
isSuccess = db.delete(vnodeList);
} else {
throw new StorageException("Couldn't find the database for name [" + dbName + "]");
}
} else {
isSuccess = true;
for (Integer vnode : vnodeList) {
dbName = getDatabaseName(vnode.intValue());
BDBDataBase db = getDataBase(dbName);
if (null != db) {
if (!db.delete(vnodeList)) {
isSuccess = false;
break;
} else {
if (databaseFactory.removeDataBase(db)) {
databaseMap.remove(dbName);
}
}
}
}
}
return isSuccess;
}
public Iterator<Pair> iterator() {
return new MultiDataBaseIterator<BDBDataBase>(databaseMap.values().iterator(), null);
}
public Iterator<Pair> iterator(List<Integer> vnodeList) {
List<BDBDataBase> dbList = new ArrayList<BDBDataBase>(vnodeList.size());
for (Integer vnode : vnodeList) {
BDBDataBase localDb = databaseMap.get(getDatabaseName(vnode.intValue()));
if (null != localDb && !dbList.contains(localDb)) {
dbList.add(localDb);
}
}
return new MultiDataBaseIterator<BDBDataBase>(dbList.iterator(), vnodeList);
}
protected String getDatabaseName(Key key) {
// int node = virtualRouter.findVirtualNode((String) key.getKey());
// return getDatabaseName(node);
return SINGLE_DATA_BASE_NAME;
}
protected String getDatabaseName(int vnode) {
// return String.valueOf(vnode);
return SINGLE_DATA_BASE_NAME;
}
protected List<String> getDatabaseName(List<Integer> vnodeList) {
List<String> dsList = new ArrayList<String>(vnodeList.size());
for (Integer node : vnodeList) {
dsList.add(node.toString());
}
return dsList;
}
protected BDBDataBase getDataBase(String databaseName) {
BDBDataBase bdb = databaseMap.get(databaseName);
if (null != bdb) {
return bdb;
}
try {
synchronized (lock) {
bdb = databaseMap.get(databaseName);
if (null != bdb) {
return bdb;
}
bdb = databaseFactory.createDataBase(databaseName);
databaseMap.put(databaseName, bdb);
}
} catch (DatabaseException e) {
throw new BDBStorageException(e);
}
return bdb;
}
private Map<String, BDBDataBase> databaseMap = new ConcurrentHashMap<String, BDBDataBase>();
private Object lock = new Object();
private BDBDataBaseFactory databaseFactory;
private static final Logger logger = LoggerFactory.getLogger(BDBStorage.class);
private static final String SINGLE_DATA_BASE_NAME = "0";
}