package com.alibaba.doris.dataserver.store.innodb;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
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.innodb.config.InnoDBDatabaseConfiguration;
import com.alibaba.doris.dataserver.store.innodb.db.InnoDBBuilder;
import com.alibaba.doris.dataserver.store.innodb.db.InnoDBDataBase;
import com.alibaba.doris.dataserver.store.innodb.write.InnoWriteThread;
import com.alibaba.doris.dataserver.store.innodb.write.WriteOperation;
import com.alibaba.doris.dataserver.store.innodb.write.WriteType;
/**
* @author long.mal long.mal@alibaba-inc.com
*/
public class InnoDBStorage extends BaseStorage {
public InnoDBStorage(InnoDBDatabaseConfiguration config) {
this.config = config;
}
public void open() {
builder = new InnoDBBuilder(config);
builder.initDataBase();
CountDownLatch latch = new CountDownLatch(config.getWriteThread());
startWriteThread(latch);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void close() {
endWriteThread();
builder.getDatabase().shutdown(false);
}
private void startWriteThread(CountDownLatch latch) {
executors = Executors.newFixedThreadPool(config.getWriteThread());
operationQueues = new ConcurrentHashMap<String, BlockingQueue<WriteOperation>>(config.getWriteThread());
for (int i = 0; i < config.getWriteThread(); i++) {
BlockingQueue<WriteOperation> writeOps = new ArrayBlockingQueue<WriteOperation>(1000);
InnoWriteThread writeThread = new InnoWriteThread(writeOps, latch);
operationQueues.put(Integer.toString(i), writeOps);
executors.submit(writeThread);
}
}
private void endWriteThread() {
executors.shutdownNow();
}
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.");
}
for (Integer vnode : vnodeList) {
String dbName = getDatabaseName(vnode.intValue());
InnoDBDataBase db = getInnoDBDataBase(dbName);
if (null != db) {
// db.delete(vnodeList);
if (builder.deleteInnoDBDataBase(db)) {
databaseMap.remove(dbName);
isSuccess = true;
}
}
}
return isSuccess;
}
public Value get(Key key) {
String databaseName = getDatabaseName(key);
InnoDBDataBase db = getInnoDBDataBase(databaseName);
return db.get(key);
}
public StorageType getType() {
return InnoDBStorageType.INNODB;
}
public Iterator<Pair> iterator() {
return new MultiDataBaseIterator<InnoDBDataBase>(databaseMap.values().iterator(), null);
}
public Iterator<Pair> iterator(List<Integer> vnodeList) {
List<InnoDBDataBase> dbList = new ArrayList<InnoDBDataBase>(vnodeList.size());
for (Integer vnode : vnodeList) {
InnoDBDataBase localDb = databaseMap.get(getDatabaseName(vnode.intValue()));
if (null != localDb && !dbList.contains(localDb)) {
dbList.add(localDb);
}
}
return new MultiDataBaseIterator<InnoDBDataBase>(dbList.iterator(), vnodeList);
}
public void set(Key key, Value value) {
String databaseName = getDatabaseName(key);
InnoDBDataBase db = getInnoDBDataBase(databaseName);
int correspondingQueueID = key.getVNode() % config.getWriteThread();
BlockingQueue<WriteOperation> writeOpQueue = operationQueues.get(String.valueOf(correspondingQueueID));
Semaphore semaphore = new Semaphore(0);
WriteOperation operation = new WriteOperation(db, WriteType.INSERT, key, value, false, semaphore);
try {
writeOpQueue.put(operation);
Object result = operation.getResult();
if (result instanceof RuntimeException)
throw (RuntimeException) result;
} catch (InterruptedException e) {
System.out.println(correspondingQueueID);
e.printStackTrace();
}
}
public void set(Key key, Value value, boolean isSetWithCompareVersion) {
String databaseName = getDatabaseName(key);
InnoDBDataBase db = getInnoDBDataBase(databaseName);
int correspondingQueueID = key.getVNode() % config.getWriteThread();
BlockingQueue<WriteOperation> writeOpQueue = operationQueues.get(String.valueOf(correspondingQueueID));
Semaphore semaphore = new Semaphore(0);
WriteOperation operation = new WriteOperation(db, WriteType.INSERT, key, value, isSetWithCompareVersion, semaphore);
try {
writeOpQueue.put(operation);
Object result = operation.getResult();
if (result instanceof RuntimeException)
throw (RuntimeException) result;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean delete(Key key) {
String databaseName = getDatabaseName(key);
InnoDBDataBase db = getInnoDBDataBase(databaseName);
int correspondingQueueID = key.getVNode() % config.getWriteThread();
BlockingQueue<WriteOperation> writeOpQueue = operationQueues.get(String.valueOf(correspondingQueueID));
Semaphore semaphore = new Semaphore(0);
WriteOperation operation = new WriteOperation(db, WriteType.DELETE, key, null, false, semaphore);
try {
writeOpQueue.put(operation);
Object result = operation.getResult();
if (result instanceof RuntimeException)
throw (RuntimeException) result;
return (Boolean) result;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
public boolean delete(Key key, Value value) {
String databaseName = getDatabaseName(key);
InnoDBDataBase db = getInnoDBDataBase(databaseName);
int correspondingQueueID = key.getVNode() % config.getWriteThread();
BlockingQueue<WriteOperation> writeOpQueue = operationQueues.get(String.valueOf(correspondingQueueID));
Semaphore semaphore = new Semaphore(0);
WriteOperation operation = new WriteOperation(db, WriteType.DELETE, key, value, false, semaphore);
try {
writeOpQueue.put(operation);
Object result = operation.getResult();
if (result instanceof RuntimeException) {
throw (RuntimeException) result;
}
return (Boolean) result;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
protected String getDatabaseName(Key key) {
return getDatabaseName(key.getVNode());
}
protected String getDatabaseName(int vnode) {
return String.valueOf(vnode);
}
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 InnoDBDataBase getInnoDBDataBase(String databaseName) {
InnoDBDataBase db = databaseMap.get(databaseName);
if (null != db) {
return db;
}
try {
synchronized (lock) {
db = databaseMap.get(databaseName);
if (null != db) {
return db;
}
db = builder.buildInnoDBDataBase(databaseName);
databaseMap.put(databaseName, db);
}
} catch (Exception e) {
throw new InnoDBStorageException(e);
}
return db;
}
private ExecutorService executors;
private Map<String, BlockingQueue<WriteOperation>> operationQueues;
private Object lock = new Object();
private Map<String, InnoDBDataBase> databaseMap = new ConcurrentHashMap<String, InnoDBDataBase>();
private InnoDBDatabaseConfiguration config;
private InnoDBBuilder builder;
}