package com.ctriposs.tsdb.level;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.ctriposs.tsdb.InternalKey;
import com.ctriposs.tsdb.common.IStorage;
import com.ctriposs.tsdb.common.Level;
import com.ctriposs.tsdb.common.MapFileStorage;
import com.ctriposs.tsdb.common.PureFileStorage;
import com.ctriposs.tsdb.iterator.MemSeekIterator;
import com.ctriposs.tsdb.manage.FileManager;
import com.ctriposs.tsdb.storage.DBWriter;
import com.ctriposs.tsdb.storage.FileMeta;
import com.ctriposs.tsdb.storage.FileName;
import com.ctriposs.tsdb.table.MemTable;
public class StoreLevel extends Level {
private ArrayBlockingQueue<MemTable> memQueue;
protected AtomicInteger fileCount = new AtomicInteger(0);
private AtomicLong storeCounter = new AtomicLong(0);
private AtomicLong storeErrorCounter = new AtomicLong(0);
public StoreLevel(FileManager fileManager, int threads, int memCount, long interval) {
super(fileManager, 0, interval, threads);
this.memQueue = new ArrayBlockingQueue<MemTable>(memCount);
for(int i = 0; i < threads; i++){
tasks[i] = new MemTask(i);
}
}
public void addMemTable(MemTable memTable) throws Exception {
if(memTable != null) {
this.memQueue.put(memTable);
}
}
@Override
public byte[] getValue(InternalKey key) throws IOException{
byte[] value = null;
ConcurrentSkipListSet<MemTable> tableSet = new ConcurrentSkipListSet<MemTable>(fileManager.getMemTableComparator());
for(MemTable table : memQueue) {
tableSet.add(table);
}
for(Task task: tasks) {
MemTable table = task.getMemTable();
if(table != null){
tableSet.add(table);
}
}
for(MemTable table : tableSet) {
value = table.getValue(key);
if(value != null){
return value;
}
}
return getValueFromFile(key);
}
public List<MemSeekIterator> getAllMemSeekIterator(){
List<MemSeekIterator> list = new ArrayList<MemSeekIterator>();
for(MemTable table : memQueue) {
list.add(table.iterator(fileManager));
}
for(Task task: tasks) {
MemTable table = task.getMemTable();
if(table != null){
list.add(table.iterator(fileManager));
}
}
return list;
}
class MemTask extends Task {
private MemTable table = null;
private Lock lock;
public MemTask(int num) {
super(num);
this.lock = new ReentrantLock();
}
@Override
public byte[] getValue(InternalKey key) {
try{
lock.lock();
if(table != null){
return table.getValue(key);
}else{
return null;
}
}finally{
lock.unlock();
}
}
@Override
public MemTable getMemTable() {
try{
lock.lock();
return table;
}finally{
lock.unlock();
}
}
@Override
public void process() throws Exception {
try{
lock.lock();
table = memQueue.poll();
if(table == null) {
return;
}
}finally{
lock.unlock();
}
for (Entry<Long, ConcurrentSkipListMap<InternalKey, byte[]>> entry : table.getTable().entrySet()) {
try{
fileCount.incrementAndGet();
FileMeta fileMeta = storeFile(entry.getKey(), entry.getValue(), table.getFileNumber());
if(fileMeta != null){
add(entry.getKey(), fileMeta);
}
fileCount.decrementAndGet();
}catch(IOException e){
//TODO
e.printStackTrace();
storeErrorCounter.incrementAndGet();
}
}
fileManager.delete(new File(table.getLogFile()));
}
private FileMeta storeFile(Long time, ConcurrentSkipListMap<InternalKey, byte[]> dataMap, long fileNumber) throws IOException {
IStorage storage;
if(fileCount.get() < 8) {
storage = new MapFileStorage(fileManager.getStoreDir(), time, FileName.dataFileName(fileNumber,level), FILE_SIZE);
} else {
storage = new PureFileStorage(fileManager.getStoreDir(), time, FileName.dataFileName(fileNumber,level), FILE_SIZE);
}
int size = dataMap.size();
DBWriter dbWriter = new DBWriter(storage, size, fileNumber);
for(Entry<InternalKey, byte[]> entry : dataMap.entrySet()){
dbWriter.add(entry.getKey(), entry.getValue());
}
FileMeta fileMeta = null;
try{
fileMeta = dbWriter.close();
}catch(Throwable t){
t.printStackTrace();
incrementStoreError();
closeStorages.add(storage);
}
return fileMeta;
}
}
public long getStoreCounter(){
return storeCounter.get();
}
public long getStoreErrorCounter(){
return storeErrorCounter.get();
}
@Override
public void incrementStoreError() {
storeErrorCounter.incrementAndGet();
}
@Override
public void incrementStoreCount() {
storeCounter.incrementAndGet();
}
}