Changeset View
Changeset View
Standalone View
Standalone View
java/src/main/java/org/softwareheritage/graph/Graph.java
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | public class Graph extends ImmutableGraph { | ||||
/** Path and basename of the compressed graph */ | /** Path and basename of the compressed graph */ | ||||
String path; | String path; | ||||
/** Mapping long id ↔ SWHIDs */ | /** Mapping long id ↔ SWHIDs */ | ||||
NodeIdMap nodeIdMap; | NodeIdMap nodeIdMap; | ||||
/** Mapping long id → node types */ | /** Mapping long id → node types */ | ||||
NodeTypesMap nodeTypesMap; | NodeTypesMap nodeTypesMap; | ||||
/** | /** | ||||
* Defines which directions of the graph can be loaded in memory. | |||||
*/ | |||||
public enum LoadDirection { | |||||
FORWARD, | |||||
BACKWARD, | |||||
BOTH | |||||
} | |||||
/** The direction of the graph loaded into memory */ | |||||
private LoadDirection loadedDirection; | |||||
/** | |||||
* Constructor. | * Constructor. | ||||
* | * | ||||
* @param path path and basename of the compressed graph to load | * @param path path and basename of the compressed graph to load | ||||
* @param direction the direction of the graph to load into memory | |||||
*/ | */ | ||||
private Graph(String path) throws IOException { | private Graph(String path, LoadDirection direction) throws IOException { | ||||
loadInternal(path, null, LoadMethod.MAPPED); | loadInternal(path, null, LoadMethod.MAPPED, direction); | ||||
} | } | ||||
/** | /** | ||||
* Loading mechanisms | * Loading mechanisms | ||||
*/ | */ | ||||
enum LoadMethod { | enum LoadMethod { | ||||
MEMORY, MAPPED, OFFLINE, | MEMORY, MAPPED, OFFLINE, | ||||
} | } | ||||
protected Graph loadInternal(String path, ProgressLogger pl, LoadMethod method) throws IOException { | protected Graph loadInternal(String path, ProgressLogger pl, LoadMethod method, LoadDirection direction) throws IOException { | ||||
this.path = path; | this.path = path; | ||||
this.loadedDirection = direction; | |||||
if (method == LoadMethod.MEMORY) { | if (method == LoadMethod.MEMORY) { | ||||
this.graph = ImmutableGraph.load(path, pl); | loadInternal(ImmutableGraph::load, path, pl, direction); | ||||
this.graphTransposed = ImmutableGraph.load(path + "-transposed", pl); | |||||
} else if (method == LoadMethod.MAPPED) { | } else if (method == LoadMethod.MAPPED) { | ||||
this.graph = ImmutableGraph.loadMapped(path, pl); | loadInternal(ImmutableGraph::loadMapped, path, pl, direction); | ||||
this.graphTransposed = ImmutableGraph.loadMapped(path + "-transposed", pl); | |||||
} else if (method == LoadMethod.OFFLINE) { | } else if (method == LoadMethod.OFFLINE) { | ||||
this.graph = ImmutableGraph.loadOffline(path, pl); | loadInternal(ImmutableGraph::loadOffline, path, pl, direction); | ||||
this.graphTransposed = ImmutableGraph.loadOffline(path + "-transposed", pl); | |||||
} | } | ||||
this.nodeTypesMap = new NodeTypesMap(path); | this.nodeTypesMap = new NodeTypesMap(path); | ||||
this.nodeIdMap = new NodeIdMap(path, numNodes()); | this.nodeIdMap = new NodeIdMap(path, numNodes()); | ||||
return this; | return this; | ||||
} | } | ||||
private interface GraphLoader { | |||||
ImmutableGraph load(String path, ProgressLogger pl) throws IOException; | |||||
} | |||||
private void loadInternal(GraphLoader loader, String path, ProgressLogger pl, LoadDirection direction) throws IOException { | |||||
if (direction == LoadDirection.FORWARD) { | |||||
this.graph = loader.load(path, pl); | |||||
} else if (direction == LoadDirection.BACKWARD) { | |||||
this.graph = loader.load(path + "-transposed", pl); | |||||
} else if (direction == LoadDirection.BOTH) { | |||||
this.graph = loader.load(path, pl); | |||||
this.graphTransposed = loader.load(path + "-transposed", pl); | |||||
} | |||||
} | |||||
protected Graph() { | protected Graph() { | ||||
} | } | ||||
public static Graph load(String path, ProgressLogger pl) throws IOException { | public static Graph load(String path, ProgressLogger pl, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, pl, LoadMethod.MEMORY); | return new Graph().loadInternal(path, pl, LoadMethod.MEMORY, direction); | ||||
} | } | ||||
public static Graph loadMapped(String path, ProgressLogger pl) throws IOException { | public static Graph loadMapped(String path, ProgressLogger pl, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, pl, LoadMethod.MAPPED); | return new Graph().loadInternal(path, pl, LoadMethod.MAPPED, direction); | ||||
} | } | ||||
public static Graph loadOffline(String path, ProgressLogger pl) throws IOException { | public static Graph loadOffline(String path, ProgressLogger pl, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, null, LoadMethod.OFFLINE); | return new Graph().loadInternal(path, pl, LoadMethod.OFFLINE, direction); | ||||
} | } | ||||
public static Graph load(String path) throws IOException { | public static Graph load(String path, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, null, LoadMethod.MEMORY); | return load(path, null, direction); | ||||
} | } | ||||
public static Graph loadMapped(String path) throws IOException { | public static Graph loadMapped(String path, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, null, LoadMethod.MAPPED); | return loadMapped(path, null, direction); | ||||
} | } | ||||
public static Graph loadOffline(String path) throws IOException { | public static Graph loadOffline(String path, LoadDirection direction) throws IOException { | ||||
return new Graph().loadInternal(path, null, LoadMethod.OFFLINE); | return loadOffline(path, null, direction); | ||||
} | } | ||||
/** | /** | ||||
* Constructor used for copy() | * Constructor used for copy() | ||||
*/ | */ | ||||
protected Graph(ImmutableGraph graph, ImmutableGraph graphTransposed, String path, NodeIdMap nodeIdMap, | protected Graph(ImmutableGraph graph, ImmutableGraph graphTransposed, String path, NodeIdMap nodeIdMap, | ||||
NodeTypesMap nodeTypesMap) { | NodeTypesMap nodeTypesMap, LoadDirection direction) { | ||||
this.graph = graph; | this.graph = graph; | ||||
this.graphTransposed = graphTransposed; | this.graphTransposed = graphTransposed; | ||||
this.path = path; | this.path = path; | ||||
this.nodeIdMap = nodeIdMap; | this.nodeIdMap = nodeIdMap; | ||||
this.nodeTypesMap = nodeTypesMap; | this.nodeTypesMap = nodeTypesMap; | ||||
this.loadedDirection = direction; | |||||
} | } | ||||
/** | /** | ||||
* Return a flyweight copy of the graph. | * Return a flyweight copy of the graph. | ||||
*/ | */ | ||||
@Override | @Override | ||||
public Graph copy() { | public Graph copy() { | ||||
return new Graph(this.graph.copy(), this.graphTransposed.copy(), this.path, this.nodeIdMap, this.nodeTypesMap); | ImmutableGraph initial = this.graph.copy(); | ||||
ImmutableGraph transposed = null; | |||||
if (this.loadedDirection == LoadDirection.BOTH) { | |||||
transposed = this.graphTransposed.copy(); | |||||
} | |||||
return new Graph(initial, transposed, this.path, this.nodeIdMap, this.nodeTypesMap, this.loadedDirection); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean randomAccess() { | public boolean randomAccess() { | ||||
return graph.randomAccess() && graphTransposed.randomAccess(); | return graph.randomAccess() && (this.loadedDirection != LoadDirection.BOTH || graphTransposed.randomAccess()); | ||||
} | } | ||||
/** | /** | ||||
* Return a transposed version of the graph. | * Return a transposed version of the graph. | ||||
*/ | */ | ||||
public Graph transpose() { | public Graph transpose() { | ||||
return new Graph(this.graphTransposed, this.graph, this.path, this.nodeIdMap, this.nodeTypesMap); | if (this.loadedDirection != LoadDirection.BOTH) { | ||||
throw new UnsupportedOperationException("Unable to transpose graph: both directions must be loaded into memory."); | |||||
} | |||||
return new Graph(this.graphTransposed, this.graph, this.path, this.nodeIdMap, this.nodeTypesMap, this.loadedDirection); | |||||
} | } | ||||
/** | /** | ||||
* Return a symmetric version of the graph. | * Return a symmetric version of the graph. | ||||
*/ | */ | ||||
public Graph symmetrize() { | public Graph symmetrize() { | ||||
if (this.loadedDirection != LoadDirection.BOTH) { | |||||
throw new UnsupportedOperationException("Unable to symmetrize graph: both directions must be loaded into memory."); | |||||
} | |||||
ImmutableGraph symmetric = Transform.union(graph, graphTransposed); | ImmutableGraph symmetric = Transform.union(graph, graphTransposed); | ||||
return new Graph(symmetric, symmetric, this.path, this.nodeIdMap, this.nodeTypesMap); | return new Graph(symmetric, symmetric, this.path, this.nodeIdMap, this.nodeTypesMap, this.loadedDirection); | ||||
} | } | ||||
/** | /** | ||||
* Cleans up graph resources after use. | * Cleans up graph resources after use. | ||||
*/ | */ | ||||
public void cleanUp() throws IOException { | public void cleanUp() throws IOException { | ||||
nodeIdMap.close(); | nodeIdMap.close(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | public class Graph extends ImmutableGraph { | ||||
* | * | ||||
* @param nodeId node specified as a long id | * @param nodeId node specified as a long id | ||||
* @return corresponding node type | * @return corresponding node type | ||||
* @see org.softwareheritage.graph.Node.Type | * @see org.softwareheritage.graph.Node.Type | ||||
*/ | */ | ||||
public Node.Type getNodeType(long nodeId) { | public Node.Type getNodeType(long nodeId) { | ||||
return nodeTypesMap.getType(nodeId); | return nodeTypesMap.getType(nodeId); | ||||
} | } | ||||
/** | |||||
* Returns the direction of the graph loaded into memory. | |||||
*/ | |||||
public LoadDirection getLoadedDirection() { | |||||
return loadedDirection; | |||||
} | |||||
} | } |