package com.chap.memo.memoNodes.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import com.chap.memo.memoNodes.MemoUtils;
import com.chap.memo.memoNodes.bus.MemoReadBus;
import com.chap.memo.memoNodes.storage.NodeValueIndex;
import com.chap.memo.memoNodes.storage.NodeValueShard;
import com.eaio.uuid.UUID;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
public class NodeValueBuffer {
public static final int STORESIZE = 50000;
public static final int COMPRESSION_RATIO = 8;
MemoReadBus ReadBus;
public static final ArrayListMultimap<Long, NodeValue> template = ArrayListMultimap
.create();
public transient ListMultimap<Long, NodeValue> nodes = Multimaps
.synchronizedListMultimap(ArrayListMultimap.create(template));
long oldest = 0;
long newest = 0;
long size = 0;
public void store(NodeValue nodeVal) {
synchronized (this) {
if (MemoUtils.gettime(nodeVal.getId()) < 0) return;
nodes.put(nodeVal.getId().time, nodeVal);
if (newest == 0 || nodeVal.getTimestamp_long() > newest)
newest = nodeVal.getTimestamp_long();
if (oldest == 0 || nodeVal.getTimestamp_long() < oldest)
oldest = nodeVal.getTimestamp_long();
if ((size+=(nodeVal.getValue().length+48)) >= STORESIZE*COMPRESSION_RATIO) {
// System.out.println("Size grown to:"+size+", flushing!");
flush();
}
}
}
public void flush() {
ArrayList<NodeValueShard> others = null;
synchronized (this) {
if (size == 0)
return;
if (ReadBus == null) {
ReadBus = MemoReadBus.getBus();
}
NodeValueShard shard = new NodeValueShard(this);
NodeValueIndex index = new NodeValueIndex(shard);
if (STORESIZE*COMPRESSION_RATIO - size > 0) {
others = ReadBus.getSparseNodeValueShards(size/COMPRESSION_RATIO);
if (others != null){
others.add(0,shard);
}
}
ReadBus.addNodeValueIndex(index, shard);
this.nodes.clear();
size=0;
}
if (others != null){
NodeValueShard.devideAndMerge(others.toArray(new NodeValueShard[0]));
}
}
public ImmutableList<NodeValue> findAll(UUID id) {
synchronized (this) {
if (size == 0) return null;
List<NodeValue> list = nodes.get(id.time);
if (list != null && !list.isEmpty()) {
Collections.sort(list);
for (NodeValue nv: list){
if (!nv.getId().equals(id)) list.remove(nv);
}
return ImmutableList.copyOf(list);
} else {
return new ImmutableList.Builder<NodeValue>().build();
}
}
}
public NodeValue find(UUID id) {
return findBefore(id, System.currentTimeMillis());
}
public NodeValue findBefore(UUID id, Date timestamp) {
return findBefore(id, timestamp.getTime());
}
public NodeValue findBefore(UUID id, long timestamp_long) {
synchronized (this) {
if (size == 0) return null;
if (timestamp_long < oldest)
return null; // shortcut, will probably not be used...
List<NodeValue> res = nodes.get(id.time);
if (res != null && !res.isEmpty()) {
Collections.sort(res);
NodeValue result = null;
Iterator<NodeValue> iter = res.iterator();
while (iter.hasNext()) {
NodeValue next = iter.next();
if (!next.getId().equals(id)) continue;
if (next.getTimestamp_long() <= timestamp_long) {
if (result == null
|| next.getTimestamp_long() >= result
.getTimestamp_long()) {
result = next;
}
}
}
return result;
}
return null;
}
}
public long getOldest() {
return oldest;
}
public long getNewest() {
return newest;
}
}