com.lambdazen.bitsy.store.AdjacencyMapForBeans Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bitsy Show documentation
Show all versions of bitsy Show documentation
Bitsy v3 is a small, fast, embeddable, durable in-memory graph database that is compatible with Tinkerpop3
package com.lambdazen.bitsy.store;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.tinkerpop.gremlin.structure.Direction;
import com.lambdazen.bitsy.ads.set.ClassifierGetter;
import com.lambdazen.bitsy.ads.set.CompactMultiSetMax;
import com.lambdazen.bitsy.ads.set.CompactSet;
import com.lambdazen.bitsy.ads.set.Set24;
import com.lambdazen.bitsy.ads.set.SetMax;
/** This map is used to keep track of edges between vertices in the memory graph store. */
public class AdjacencyMapForBeans {
IEdgeRemover edgeRemover;
ClassifierGetter edgeBeanClassifier;
public AdjacencyMapForBeans(boolean isConcurrent, IEdgeRemover edgeRemover) {
this.edgeRemover = edgeRemover;
this.edgeBeanClassifier = new ClassifierGetter() {
@Override
public String getClassifier(EdgeBean eBean) {
return eBean.getLabel();
}
};
}
public void addEdge(EdgeBean eBean) {
// Update in and out vertices
VertexBean outV = eBean.outVertex;
VertexBean inV = eBean.inVertex;
outV.outEdges = addEdgeToAdjList(outV.outEdges, eBean);
inV.inEdges = addEdgeToAdjList(inV.inEdges, eBean);
}
private Object addEdgeToAdjList(Object adjList, EdgeBean eBean) {
if (adjList instanceof CompactMultiSetMax) {
CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList;
return adjListMultiSet.add(eBean, edgeBeanClassifier);
} else {
Object ans = CompactSet.add(adjList, eBean);
if (ans instanceof SetMax) {
return convertToMultiSet((SetMax)ans);
} else {
return ans;
}
}
}
/** This method removes the edges without calling edgeRemover.removeEdge() */
protected void removeEdgeWithoutCallback(EdgeBean eBean) {
if (eBean == null) {
return;
}
// Update in and out vertices
VertexBean outV = eBean.outVertex;
VertexBean inV = eBean.inVertex;
outV.outEdges = removeEdgeFromAdjList(outV.outEdges, eBean); // CompactSet.remove(outV.outEdges, eBean);
inV.inEdges = removeEdgeFromAdjList(inV.inEdges, eBean);; // CompactSet.remove(inV.inEdges, eBean);
}
private Object removeEdgeFromAdjList(Object adjList, EdgeBean eBean) {
if (adjList instanceof CompactMultiSetMax) {
CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList;
CompactMultiSetMax ans = adjListMultiSet.remove(eBean, edgeBeanClassifier);
// The first check is fast and increases the chances of hitting the second one
if ((ans.getOccupiedCells() <= 13) && !ans.sizeBiggerThan24()) {
return convertToSet(ans);
} else {
return ans;
}
} else {
return CompactSet.remove(adjList, eBean);
}
}
private Object[] getEdgesFromAdjList(Object adjList) {
if (adjList instanceof CompactMultiSetMax) {
CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList;
return adjListMultiSet.getAllElements();
} else {
return CompactSet.getElements(adjList);
}
}
private Object convertToSet(CompactMultiSetMax set) {
// The size is guaranteed to be between 13 and 24
// The Set24 will automatically adjust on a remove if it is too big
return new Set24(set.getAllElements());
}
private Object convertToMultiSet(SetMax set) {
// Use safe = false, which means that the multi-set can use the default SetMax implementation
CompactMultiSetMax ans = new CompactMultiSetMax(36, false);
for (Object obj : set.getElements()) {
if (obj != null) {
ans.add((EdgeBean)obj, edgeBeanClassifier);
}
}
return ans;
}
public void removeVertex(VertexBean vBean) {
if (vBean == null) {
return;
}
// Remove outgoing edges
for (Object obj : getEdgesFromAdjList(vBean.outEdges)) {
EdgeBean eBean = (EdgeBean)obj;
eBean.inVertex.inEdges = removeEdgeFromAdjList(eBean.inVertex.inEdges, eBean); // CompactSet.remove(eBean.inVertex.inEdges, eBean);
// Callback
edgeRemover.removeEdge(eBean.getId());
}
vBean.outEdges = null;
// Remove incoming edges
for (Object obj : getEdgesFromAdjList(vBean.inEdges)) {
EdgeBean eBean = (EdgeBean)obj;
eBean.outVertex.outEdges = removeEdgeFromAdjList(eBean.outVertex.outEdges, eBean); // CompactSet.remove(eBean.outVertex.outEdges, eBean);
// Callback
edgeRemover.removeEdge(eBean.getId());
}
vBean.inEdges = null;
}
public List getEdges(VertexBean vBean, Direction dir, String[] edgeLabels) {
if (vBean == null) {
return Collections.emptyList();
}
boolean outDirection = (dir == Direction.OUT);
Object edges = outDirection ? vBean.outEdges : vBean.inEdges;
if (edges == null) {
return Collections.emptyList();
}
// Need a new list
List ans = new ArrayList();
boolean origMatch = (edgeLabels == null) || edgeLabels.length == 0;
boolean multiSet = (edges instanceof CompactMultiSetMax, ?>);
String[] edgeLabelsToQuery = (multiSet && (!origMatch)) ? edgeLabels : new String[] {null};
for (String edgeLabelToQuery : edgeLabelsToQuery) {
Object[] edgeBeans;
if (multiSet) {
edgeBeans = ((CompactMultiSetMax)edges).getSuperSetWithClassifier(edgeLabelToQuery);
} else {
edgeBeans = CompactSet.getElements(edges);
}
for (Object obj : edgeBeans) {
// Always check for nulls on getElements() because reads don't acquire locks
if (obj == null) {
continue;
}
boolean match = origMatch;
EdgeBean eBean = (EdgeBean)obj;
if (!match) {
String eLabel = eBean.getLabel();
if (edgeLabelToQuery != null) {
match = eLabel.equals(edgeLabelToQuery);
} else {
for (String label : edgeLabels) {
if (eLabel.equals(label)) {
match = true;
break;
}
}
}
}
if (match) {
// Always copy objects that are directly picked up from the memory store
// These objects can be updated later while the query is in progress
ans.add(new EdgeBean(eBean));
}
}
}
return ans;
}
}