package com.ctriposs.tsdb.table; import java.io.File; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.ctriposs.tsdb.ILogWriter; import com.ctriposs.tsdb.InternalKey; import com.ctriposs.tsdb.iterator.MemSeekIterator; import com.ctriposs.tsdb.manage.FileManager; import com.ctriposs.tsdb.storage.CodeItem; import com.ctriposs.tsdb.storage.Head; import com.ctriposs.tsdb.storage.TimeItem; public class MemTable { public final static long MAX_MEM_SIZE = 256 * 1024 * 1024L; public final static long MINUTE = 1000 * 60; private final ConcurrentHashMap<Long, ConcurrentSkipListMap<InternalKey, byte[]>> table; private final long maxMemTableSize; private final AtomicLong used = new AtomicLong(Head.HEAD_SIZE); private Lock lock = new ReentrantLock(); private InternalKeyComparator internalKeyComparator; private ILogWriter logWriter; private long fileNumber; public MemTable(String dir, long fileNumber, long capacity, long maxMemTableSize, InternalKeyComparator internalKeyComparator) throws IOException { this.table = new ConcurrentHashMap<Long, ConcurrentSkipListMap<InternalKey, byte[]>>(); this.maxMemTableSize = maxMemTableSize; this.internalKeyComparator = internalKeyComparator; this.logWriter = new MapFileLogWriter(dir, fileNumber, capacity); this.fileNumber = fileNumber; } public MemTable(File file, long fileNumber, InternalKeyComparator internalKeyComparator) throws IOException { this.table = new ConcurrentHashMap<Long, ConcurrentSkipListMap<InternalKey, byte[]>>(); this.maxMemTableSize = MAX_MEM_SIZE; this.internalKeyComparator = internalKeyComparator; this.logWriter = new MapFileLogWriter(file); this.fileNumber = fileNumber; } public boolean isEmpty() { return table.isEmpty(); } public long getUsed() { return used.get(); } public static long format(long time) { return time/MINUTE*MINUTE; } public boolean add(InternalKey key, byte value[]) throws IOException { boolean result = true; int length = value.length + CodeItem.CODE_ITEM_SIZE + TimeItem.TIME_ITEM_SIZE; if (used.addAndGet(length) > maxMemTableSize) { result = false; } else { long ts = format(key.getTime()); ConcurrentSkipListMap<InternalKey, byte[]> slot = table.get(ts); if(slot == null) { try { lock.lock(); slot = table.get(ts); if(slot == null) { slot = new ConcurrentSkipListMap<InternalKey, byte[]>(internalKeyComparator); table.put(ts, slot); } } finally { lock.unlock(); } } logWriter.add(key.getCode(), key.getTime(), value); slot.put(key, value); } return result; } public byte[] getValue(InternalKey key){ long ts = format(key.getTime()); ConcurrentSkipListMap<InternalKey, byte[]> slot = table.get(ts); if(slot != null) { return slot.get(key); } else { return null; } } public ConcurrentHashMap<Long, ConcurrentSkipListMap<InternalKey, byte[]>> getTable(){ return this.table; } public ConcurrentSkipListMap<InternalKey, byte[]> getAllConcurrentSkipList(){ ConcurrentSkipListMap<InternalKey, byte[]> result = new ConcurrentSkipListMap<InternalKey, byte[]>(internalKeyComparator); for(ConcurrentSkipListMap<InternalKey, byte[]> value:table.values()){ result.putAll(value); } return result; } public void close() throws IOException{ logWriter.close(); } public String getLogFile(){ return logWriter.getName(); } public long getFileNumber(){ return fileNumber; } public MemSeekIterator iterator(FileManager fileManager){ return new MemSeekIterator(fileManager, this,-fileNumber); } }