Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
overflowdb.BatchedUpdate Maven / Gradle / Ivy
package overflowdb;
import overflowdb.util.IteratorUtils;
import java.util.*;
public class BatchedUpdate {
public static final Object[] emptyArray = new Object[]{};
public static AppliedDiff applyDiff(Graph graph, DiffOrBuilder diff) {
return new DiffGraphApplier(graph, diff, null, null).run();
}
public static AppliedDiff applyDiff(Graph graph, DiffOrBuilder diff, KeyPool keyPool, ModificationListener listener) {
return new DiffGraphApplier(graph, diff, keyPool, listener).run();
}
public interface KeyPool {
public long next();
}
public interface DiffOrBuilder {
public int size();
Iterator iterator();
}
public interface ModificationListener {
public abstract void onAfterInitNewNode(Node node);
public abstract void onAfterAddNewEdge(Edge edge);
public abstract void onBeforePropertyChange(Node node, String key);
public abstract void onAfterPropertyChange(Node node, String key, Object value);
public abstract void onBeforeRemoveNode(Node node);
public abstract void onBeforeRemoveEdge(Edge edge);
public abstract void finish();
}
//Interface Change
public interface Change {
}
public static class DiffGraph implements DiffOrBuilder {
public final Change[] changes;
DiffGraph(Change[] changes) {
this.changes = changes;
}
@Override
public int size() {
return changes.length;
}
@Override
public Iterator iterator() {
return new IteratorUtils.ArrayIterator(changes);
}
}
public static class DiffGraphBuilder implements DiffOrBuilder {
private ArrayDeque _buffer = new ArrayDeque<>();
public DiffGraphBuilder() {
}
public DiffGraph build() {
DiffGraph res = new DiffGraph(_buffer.toArray(new Change[]{}));
this._buffer = null;
return res;
}
public int size() {
return _buffer.size();
}
public Iterator iterator() {
return _buffer.iterator();
}
public DiffGraphBuilder absorb(DiffGraphBuilder other) {
if (this._buffer.size() > other._buffer.size()) {
_buffer.addAll(other._buffer);
other._buffer = null;
} else {
ArrayDeque tmp = this._buffer;
this._buffer = other._buffer;
other._buffer = null;
for (Iterator it = tmp.descendingIterator(); it.hasNext(); ) {
Change change = it.next();
_buffer.addFirst(change);
}
}
return this;
}
public DiffGraphBuilder addNode(DetachedNodeData node) {
_buffer.addLast(node);
return this;
}
public DiffGraphBuilder addNode(String label, Object... keyvalues) {
_buffer.addLast(new DetachedNodeGeneric(label, keyvalues));
return this;
}
public DiffGraphBuilder addEdge(NodeOrDetachedNode src, NodeOrDetachedNode dst, String label) {
_buffer.addLast(new CreateEdge(label, src, dst, null));
return this;
}
public DiffGraphBuilder addEdge(NodeOrDetachedNode src, NodeOrDetachedNode dst, String label, Object... properties) {
_buffer.addLast(new CreateEdge(label, src, dst, properties.length > 0 ? properties : null));
return this;
}
public DiffGraphBuilder setNodeProperty(Node node, String label, Object property) {
_buffer.addLast(new SetNodeProperty(label, node, property));
return this;
}
public DiffGraphBuilder removeNode(Node node) {
_buffer.addLast(new RemoveNode(node));
return this;
}
public DiffGraphBuilder removeEdge(Edge edge) {
_buffer.addLast(new RemoveEdge(edge));
return this;
}
//missing API functions (not implemented because not needed at this time):
//setEdgeProperty etc.
}
public static class AppliedDiff {
public DiffOrBuilder diffGraph;
private ModificationListener listener;
private int transitiveModifications;
private Graph graph;
AppliedDiff(Graph graph, DiffOrBuilder diffGraph, ModificationListener listener, int transitiveModifications) {
this.graph = graph;
this.diffGraph = diffGraph;
this.listener = listener;
this.transitiveModifications = transitiveModifications;
}
public DiffGraph getDiffGraph() {
if (diffGraph instanceof DiffGraphBuilder) {
this.diffGraph = ((DiffGraphBuilder) diffGraph).build();
}
return (DiffGraph) diffGraph;
}
public ModificationListener getListener() {
return listener;
}
public int explicitModifications() {
return diffGraph.size();
}
public int transitiveModifications() {
return transitiveModifications;
}
}
private static class RemoveEdge implements Change {
public Edge edge;
public RemoveEdge(Edge edge) {
this.edge = edge;
}
}
public static class CreateNode implements Change {
public String label;
public Object[] ProprtiesAndKeys;
public long id; // 0 means that the label is not unknown
public CreateNode(String label) {
this.label = label;
}
}
public static class RemoveNode implements Change {
public Node node;
public RemoveNode(Node node) {
this.node = node;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof RemoveNode) && ((RemoveNode) obj).node.id() == node.id();
}
@Override
public int hashCode() {
return Objects.hash(node.id());
}
}
public static class CreateEdge implements Change {
public String label;
public NodeOrDetachedNode src;
public NodeOrDetachedNode dst;
public Object[] propertiesAndKeys;
public CreateEdge(String label, NodeOrDetachedNode src, NodeOrDetachedNode dst, Object[] propertiesAndKeys) {
this.label = label;
this.src = src;
this.dst = dst;
this.propertiesAndKeys = propertiesAndKeys;
}
}
public static class SetNodeProperty implements Change {
public String label;
public Node node;
public Object value;
public SetNodeProperty(String label, Node node, Object value) {
this.label = label;
this.node = node;
this.value = value;
}
}
private static class DiffGraphApplier {
private final DiffOrBuilder diff;
private final KeyPool keyPool;
private final ModificationListener listener;
private final ArrayDeque deferredInitializers = new ArrayDeque<>();
private final Graph graph;
private int nChanges = 0;
/** We keep track of already removed nodes to ensure we don't fail to load them from storage when they are
* removed multiple times in the same Diff. */
private Set removedNodes = new HashSet<>();
DiffGraphApplier(Graph graph, DiffOrBuilder diff, KeyPool keyPool, ModificationListener listener) {
this.diff = diff;
this.keyPool = keyPool;
this.listener = listener;
this.graph = graph;
}
AppliedDiff run() {
try {
for (Iterator it = diff.iterator(); it.hasNext(); ) {
Change change = it.next();
applyChange(change);
}
} finally {
if (listener != null)
listener.finish();
}
return new AppliedDiff(graph, diff, listener, nChanges);
}
private Node mapDetached(DetachedNodeData detachedNode) {
Object linkedNode = detachedNode.getRefOrId();
if (linkedNode == null || linkedNode instanceof Long) {
if (linkedNode == null) {
if (keyPool == null) {
linkedNode = graph.addNode(detachedNode.label());
} else {
linkedNode = graph.addNode(keyPool.next(), detachedNode.label());
}
} else if (linkedNode instanceof Long) {
linkedNode = graph.addNode(((Long) linkedNode).longValue(), detachedNode.label());
}
detachedNode.setRefOrId(linkedNode);
deferredInitializers.addLast(detachedNode);
}
return (Node) linkedNode;
}
private void drainDeferred() {
while (!deferredInitializers.isEmpty()) {
DetachedNodeData detachedNode = deferredInitializers.removeFirst();
Node actualNode = (Node) detachedNode.getRefOrId();
Node.initializeFromDetached(actualNode, detachedNode, this::mapDetached);
nChanges += 1;
if (listener != null) {
listener.onAfterInitNewNode(actualNode);
}
}
}
private void applyChange(Change change) {
if (change instanceof DetachedNodeData) {
mapDetached((DetachedNodeData) change);
drainDeferred();
} else if (change instanceof CreateEdge) {
nChanges += 1;
CreateEdge create = (CreateEdge) change;
Node src = create.src instanceof DetachedNodeData ? mapDetached((DetachedNodeData) create.src) : (Node) create.src;
Node dst = create.dst instanceof DetachedNodeData ? mapDetached((DetachedNodeData) create.dst) : (Node) create.dst;
drainDeferred();
Object[] properties = create.propertiesAndKeys == null ? emptyArray : create.propertiesAndKeys;
if (listener != null) {
Edge edge = src.addEdgeInternal(create.label, dst, properties);
listener.onAfterAddNewEdge(edge);
} else {
src.addEdgeSilentInternal(create.label, dst, properties);
}
} else if (change instanceof RemoveEdge) {
nChanges += 1;
RemoveEdge remove = (RemoveEdge) change;
if (listener != null)
listener.onBeforeRemoveEdge(remove.edge);
remove.edge.removeInternal();
} else if (change instanceof RemoveNode) {
nChanges += 1;
if (!removedNodes.contains(change)) {
RemoveNode remove = (RemoveNode) change;
if (listener != null)
listener.onBeforeRemoveNode(remove.node);
remove.node.removeInternal();
removedNodes.add(remove);
}
} else if (change instanceof SetNodeProperty) {
nChanges += 1;
SetNodeProperty setProp = (SetNodeProperty) change;
if (listener != null)
listener.onBeforePropertyChange(setProp.node, setProp.label);
setProp.node.setPropertyInternal(setProp.label, setProp.value);
if (listener != null)
listener.onAfterPropertyChange(setProp.node, setProp.label, setProp.value);
drainDeferred();
}
}
}
}