package com.chap.memo.memoNodes.storage; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; 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.model.NodeValue; import com.chap.memo.memoNodes.model.NodeValueBuffer; import com.eaio.uuid.UUID; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; public final class NodeValueShard extends MemoStorable { private static final long serialVersionUID = 7295820980658238258L; final long oldest; final long newest; final NodeValue[] nodeArray; final int size; transient private final static UuidCmp nodeCmp = new UuidCmp(); public static void dropHistory(NodeValueShard shard) { MemoReadBus ReadBus = MemoReadBus.getBus(); HashMap<UUID, NodeValue> newNodes = new HashMap<UUID, NodeValue>( shard.nodeArray.length); for (NodeValue node : shard.getNodes()) { newNodes.put(node.getId(), node); } NodeValueShard newshard = new NodeValueShard(new ArrayList<NodeValue>(newNodes.values())); NodeValueIndex index = new NodeValueIndex(newshard); ReadBus.addNodeValueIndex(index, newshard); NodeValueIndex idx = ReadBus.removeNodeValueIndexByShard(shard .getMyKey()); if (idx != null) idx.delete(); ReadBus.delShard(shard); shard.delete(); } public static void devideAndMerge(NodeValueShard[] shards) { if (shards.length <= 1) return; System.out.println("Merging NodeValue shards:" + shards.length); MemoReadBus ReadBus = MemoReadBus.getBus(); int maxSize = NodeValueBuffer.COMPRESSION_RATIO * NodeValueBuffer.STORESIZE; ArrayList<NodeValue> nodes = new ArrayList<NodeValue>(maxSize / 52); for (NodeValueShard shard : shards) { nodes.ensureCapacity(nodes.size() + shard.nodeArray.length); nodes.addAll(Arrays.asList(shard.nodeArray)); } Collections.sort(nodes); // Sort on Timestamp ArrayList<NodeValue> newNodes = new ArrayList<NodeValue>(Math.min( maxSize / 52, nodes.size())); Iterator<NodeValue> iter = nodes.iterator(); while (iter.hasNext()) { int count = maxSize - (newNodes.size() > 0 ? newNodes.get(0).getValue().length + 48 : 0); NodeValue node = iter.hasNext() ? iter.next() : null; while (count > 0 && node != null) { newNodes.add(node); iter.remove(); count -= node.getValue().length + 48; node = iter.hasNext() ? iter.next() : null; } if (count <= 0) { NodeValueShard shard = new NodeValueShard(newNodes); NodeValueIndex index = new NodeValueIndex(shard); ReadBus.addNodeValueIndex(index, shard); newNodes.clear(); } if (node != null) newNodes.add(node); } if (newNodes.size() > 0) { NodeValueShard shard = new NodeValueShard(newNodes); NodeValueIndex index = new NodeValueIndex(shard); ReadBus.addNodeValueIndex(index, shard); newNodes.clear(); } for (NodeValueShard other : shards) { NodeValueIndex idx = ReadBus.removeNodeValueIndexByShard(other .getMyKey()); if (idx != null) idx.delete(); ReadBus.delShard(other); other.delete(); } } public NodeValueShard(NodeValueBuffer buffer) { List<NodeValue> list = new ArrayList<NodeValue>(buffer.nodes.values()); newest = buffer.getNewest(); oldest = buffer.getOldest(); Collections.sort(list); Collections.sort(list, nodeCmp); nodeArray = list.toArray(new NodeValue[0]); int count = 0; for (NodeValue val : nodeArray) { count += val.getValue().length + 48; } size = count; if (nodeArray.length > 0) { this.spread = MemoUtils.gettime(nodeArray[nodeArray.length - 1] .getId()) - MemoUtils.gettime(nodeArray[0].getId()); } } public NodeValueShard(List<NodeValue> nodeList) { Collections.sort(nodeList); oldest = nodeList.get(0).getTimestamp_long(); newest = nodeList.get(nodeList.size() - 1).getTimestamp_long(); Collections.sort(nodeList, nodeCmp); nodeArray = nodeList.toArray(new NodeValue[0]); int count = 0; for (NodeValue val : nodeArray) { count += val.getValue().length + 48; } size = count; if (nodeArray.length > 0) { this.spread = MemoUtils.gettime(nodeArray[nodeArray.length - 1] .getId()) - MemoUtils.gettime(nodeArray[0].getId()); } } public ImmutableList<NodeValue> findAll(UUID id) { int pivot = Arrays.binarySearch(nodeArray, new NodeValue(id, null, 0), nodeCmp); if (pivot < 0) return ImmutableList.of(); while (pivot > 0 && nodeArray[pivot - 1].getId().time == id.time) pivot--; Builder<NodeValue> resBuilder = ImmutableList.builder(); while (pivot < nodeArray.length && nodeArray[pivot].getId().time == id.time) { NodeValue val = nodeArray[pivot]; if (val.getId().equals(id)) { resBuilder.add(val); } pivot++; } return resBuilder.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) { if (timestamp_long < oldest) { System.out.println("Took shortcut! ??"); return null; // shortcut, will probably not be used... } int pivot = Arrays.binarySearch(nodeArray, new NodeValue(id, null, 0), nodeCmp); if (pivot < 0) { return null; } while (pivot < nodeArray.length - 1 && nodeArray[pivot + 1].getId().time == id.time) pivot++; while (pivot >= 0 && nodeArray[pivot].getId().time == id.time) { NodeValue val = nodeArray[pivot]; if (val.getId().equals(id) && val.getTimestamp_long() <= timestamp_long) { return val; } pivot--; } return null; } public NodeValue[] getNodes() { return this.nodeArray; } public long getOldest() { return oldest; } public long getNewest() { return newest; } @Override public int getSize() { return this.size; } } class UuidCmp implements Comparator<NodeValue> { public int compare(NodeValue a, NodeValue b) { return a.getId().time == b.getId().time ? 0 : (MemoUtils.gettime(a .getId()) > MemoUtils.gettime(b.getId()) ? 1 : -1); } }