package org.infinispan.tree.impl;
import org.infinispan.AdvancedCache;
import org.infinispan.atomic.AtomicMap;
import org.infinispan.atomic.AtomicMapLookup;
import org.infinispan.batch.AutoBatchSupport;
import org.infinispan.batch.BatchContainer;
import org.infinispan.tree.Fqn;
import org.infinispan.tree.Node;
import org.infinispan.tree.TreeCache;
import org.infinispan.util.concurrent.locks.LockManager;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
public class TreeStructureSupport extends AutoBatchSupport {
private static final Log log = LogFactory.getLog(TreeStructureSupport.class);
private static final boolean trace = log.isTraceEnabled();
protected final AdvancedCache<NodeKey, AtomicMap<?, ?>> cache;
@SuppressWarnings("unchecked")
public TreeStructureSupport(AdvancedCache<?, ?> cache, BatchContainer batchContainer) {
this.cache = (AdvancedCache<NodeKey, AtomicMap<?, ?>>) cache;
this.batchContainer = batchContainer;
}
public boolean exists(Fqn f) {
return exists(cache, f);
}
protected boolean exists(AdvancedCache<?, ?> cache, Fqn f) {
startAtomic();
try {
return cache.containsKey(new NodeKey(f, NodeKey.Type.DATA))
&& cache.containsKey(new NodeKey(f, NodeKey.Type.STRUCTURE));
}
finally {
endAtomic();
}
}
/**
* @return true if created, false if this was not necessary.
*/
boolean createNodeInCache(Fqn fqn) {
return createNodeInCache(cache, fqn);
}
protected boolean createNodeInCache(AdvancedCache<?, ?> cache, Fqn fqn) {
startAtomic();
try {
NodeKey dataKey = new NodeKey(fqn, NodeKey.Type.DATA);
NodeKey structureKey = new NodeKey(fqn, NodeKey.Type.STRUCTURE);
if (cache.containsKey(dataKey) && cache.containsKey(structureKey)) return false;
Fqn parent = fqn.getParent();
if (!fqn.isRoot()) {
if (!exists(cache, parent)) createNodeInCache(cache, parent);
AtomicMap<Object, Fqn> parentStructure = getStructure(cache, parent);
parentStructure.put(fqn.getLastElement(), fqn);
}
getAtomicMap(cache, structureKey);
getAtomicMap(cache, dataKey);
if (trace) log.tracef("Created node %s", fqn);
return true;
}
finally {
endAtomic();
}
}
private AtomicMap<Object, Fqn> getStructure(AdvancedCache<?, ?> cache, Fqn fqn) {
return getAtomicMap(cache, new NodeKey(fqn, NodeKey.Type.STRUCTURE));
}
public static boolean isLocked(LockManager lockManager, Fqn fqn) {
return ((lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.STRUCTURE)) &&
lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.DATA))));
}
/**
* Returns a String representation of a tree cache.
*/
public static String printTree(TreeCache<?, ?> cache, boolean details) {
StringBuilder sb = new StringBuilder();
sb.append("\n\n");
// walk tree
sb.append("+ ").append(Fqn.SEPARATOR);
if (details) sb.append(" ").append(cache.getRoot().getData());
sb.append("\n");
addChildren(cache.getRoot(), 1, sb, details);
return sb.toString();
}
private static void addChildren(Node<?, ?> node, int depth, StringBuilder sb, boolean details) {
for (Node<?, ?> child : node.getChildren()) {
for (int i = 0; i < depth; i++) sb.append(" "); // indentations
sb.append("+ ");
sb.append(child.getFqn().getLastElementAsString()).append(Fqn.SEPARATOR);
if (details) sb.append(" ").append(child.getData());
sb.append("\n");
addChildren(child, depth + 1, sb, details);
}
}
protected final <K, V> AtomicMap<K, V> getAtomicMap(NodeKey key) {
return AtomicMapLookup.getAtomicMap(cache, key);
}
protected final <K, V> AtomicMap<K, V> getAtomicMap(AdvancedCache<?, ?> cache, NodeKey key) {
return AtomicMapLookup.getAtomicMap((AdvancedCache<NodeKey, AtomicMap<?, ?>>) cache, key);
}
}