Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add possibility to remove composite index entries
With this change it will be possible to remove stale composite index entries from the graph Related to #1099 Signed-off-by: Oleksandr Porunov <alexandr.porunov@gmail.com>
- Loading branch information
Showing
14 changed files
with
1,221 additions
and
448 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
# Permanent stale index inconsistency | ||
|
||
In some situations due to crashes of storage database, index database, or JanusGraph instances | ||
permanent stale index may appear. | ||
One of such cases could be a vertex removal from the graph but due to the crash during index persistence | ||
there is a chance that index won't be updated ever. In such situation `IllegalStateException` will be | ||
thrown with the message `Vertex with id %vertexId% was removed.` during attempts of removing such vertex in normal way. | ||
This problem is known and should be temporal limitation until this issue is fixed in JanusGraph. | ||
As for now there are several workarounds described below to fix permanent stale indices. | ||
|
||
## StaleIndexRecordUtil | ||
|
||
`StaleIndexRecordUtil.class` is available in `janusgraph-core` module and is meant to be used as a helper class | ||
to fix permanent stale index entries. | ||
|
||
`StaleIndexRecordUtil.forceRemoveElementFromGraphIndex` can be used to force remove an entry of any element from | ||
a graph index. Right now the limitations of this method is that it can be used with Composite indices only. | ||
An example of using this method is below: | ||
```java | ||
StandardJanusGraph graph = (StandardJanusGraph) JanusGraphFactory.open(configuration); | ||
StandardJanusGraphTx tx = (StandardJanusGraphTx) graph.newTransaction(); | ||
JanusGraphManagement mgmt = graph.openManagement(); | ||
|
||
// Let's say we want to remove non-existent vertex from a stale index. | ||
// We will assume the next constraints: | ||
// vertex id is 12345; | ||
// Composite index name is: nameIndex | ||
// There is a single indexed property: name | ||
// Value of the vertex property is: HelloWorld | ||
|
||
long vertexId = 12345L; | ||
String compositeIndexName = "nameIndex"; | ||
String propertyKeyName = "name"; | ||
String value = "HelloWorld"; | ||
|
||
PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName); | ||
long propertyKeyId = propertyKey.longId(); | ||
IndexRecordEntry namePropertyIndexRecord = new IndexRecordEntry(propertyKeyId, value, propertyKey); | ||
IndexRecordEntry[] fullIndexRecord = new IndexRecordEntry[]{namePropertyIndexRecord}; | ||
|
||
JanusGraphElement elementToBeRemoved = new CacheVertex(tx, vertexId, ElementLifeCycle.New); | ||
|
||
// After the below method is executed index entry of the vertex 12345 should be removed from the index which | ||
// effectively fixes permanent stale index inconsistency | ||
StaleIndexRecordUtil.forceRemoveElementFromGraphIndex( | ||
elementToBeRemoved, | ||
fullIndexRecord, | ||
graph, | ||
compositeIndexName | ||
); | ||
tx.commit(); | ||
mgmt.rollback(); | ||
``` | ||
|
||
## Manually mutate index record | ||
|
||
In case a stale index have missing added elements to the graph then it's possible to manually add or remove any | ||
index records of the index. To do so you will need to use `BackendTransaction` directly. | ||
|
||
**Vertex index record update** | ||
|
||
```java | ||
StandardJanusGraph graph = (StandardJanusGraph) JanusGraphFactory.open(configuration); | ||
StandardJanusGraphTx tx = (StandardJanusGraphTx) graph.newTransaction(); | ||
ManagementSystem mgmt = (ManagementSystem) graph.openManagement(); | ||
|
||
// Let's say we want to remove non-existent vertex from a stale index. | ||
// We will assume the next constraints: | ||
// vertex id is 12345; | ||
// Composite index name is: nameIndex | ||
// There is a single indexed property: name | ||
// Value of the vertex property is: HelloWorld | ||
|
||
long vertexId = 12345L; | ||
String compositeIndexName = "nameIndex"; | ||
String propertyKeyName = "name"; | ||
String value = "HelloWorld"; | ||
|
||
PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName); | ||
long propertyKeyId = propertyKey.longId(); | ||
IndexRecordEntry namePropertyIndexRecord = new IndexRecordEntry(propertyKeyId, value, propertyKey); | ||
IndexRecordEntry[] fullIndexRecord = new IndexRecordEntry[]{namePropertyIndexRecord}; | ||
|
||
JanusGraphElement elementToBeRemoved = new CacheVertex(tx, vertexId, ElementLifeCycle.New); | ||
|
||
JanusGraphIndex indexToBeUpdated = managementSystem.getGraphIndex(compositeIndexName); | ||
JanusGraphSchemaVertex indexSchemaVertex = managementSystem.getSchemaVertex(indexToBeUpdated); | ||
CompositeIndexType compositeIndexTypeToBeUpdated = (CompositeIndexType) indexSchemaVertex.asIndexType(); | ||
|
||
Serializer serializer = graph.getDataSerializer(); | ||
boolean hashKeys = graph.getIndexSerializer().isHashKeys(); | ||
HashingUtil.HashLength hashLength = graph.getIndexSerializer().getHashLength(); | ||
|
||
IndexUpdate<StaticBuffer, Entry> update = IndexRecordUtil.getCompositeIndexUpdate( | ||
compositeIndexTypeToBeUpdated, | ||
IndexMutationType.DELETE, | ||
fullIndexRecord, | ||
elementToBeRemoved, | ||
serializer, | ||
hashKeys, | ||
hashLength | ||
); | ||
|
||
BackendTransaction backendTransaction = tx.getTxHandle(); | ||
backendTransaction.mutateIndex(update.getKey(), Collections.emptyList(), Collections.singletonList(update.getEntry())); | ||
transaction.commit(); | ||
tx.commit(); | ||
mgmt.rollback(); | ||
``` | ||
|
||
In case above you wanted to add index entry instead of removing it you would need to use `IndexMutationType.ADD` instead | ||
of `IndexMutationType.DELETE` as provide entries collection as a second parameter into `mutateIndex` method instead of third parameter. | ||
I.e. `backendTransaction.mutateIndex(update.getKey(), Collections.emptyList(), Collections.singletonList(update.getEntry()));` | ||
|
||
**Edge index record update** | ||
|
||
Edge index record update is currently more limited to Vertex index record update above as you will need to find `relationId` | ||
as well as both ids of the connected vertices. It may be more challenging in case you don't have those elements in the graph. | ||
Thus, below example shows how to remove index record of *existing* edge which leads to stale index. You shouldn't repeat | ||
below steps unless you want to force remove existing edge index record. | ||
```java | ||
StandardJanusGraph graph = (StandardJanusGraph) JanusGraphFactory.open(configuration); | ||
StandardJanusGraphTx tx = (StandardJanusGraphTx) graph.newTransaction(); | ||
ManagementSystem mgmt = (ManagementSystem) graph.openManagement(); | ||
|
||
// Let's say we want to remove existent edge from an index. | ||
// We will assume the next constraints: | ||
// Composite index name is: nameIndex | ||
// There is a single indexed property: name | ||
// Value of the vertex property is: HelloWorld | ||
|
||
String compositeIndexName = "nameIndex"; | ||
String propertyKeyName = "name"; | ||
String value = "HelloWorld"; | ||
|
||
PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName); | ||
|
||
Edge edge = tx.traversal().E().has(propertyKeyName, value).next(); | ||
RelationIdentifier relationIdentifier = (RelationIdentifier) edge.id(); | ||
long relationId = relationIdentifier.getRelationId(); | ||
EdgeLabel edgeLabel = managementSystem.getEdgeLabel(edgeName); | ||
|
||
IndexRecordEntry[] fullIndexRecord = new IndexRecordEntry[]{new IndexRecordEntry(relationId, value, propertyKey)}; | ||
|
||
InternalVertex internalVertex1 = (InternalVertex) edge.outVertex(); | ||
InternalVertex internalVertex2 = (InternalVertex) edge.inVertex(); | ||
JanusGraphElement elementToBeRemoved = new StandardEdge(relationId, edgeLabel, internalVertex1, internalVertex2, ElementLifeCycle.New); | ||
|
||
JanusGraphIndex indexToBeUpdated = managementSystem.getGraphIndex(compositeIndexName); | ||
JanusGraphSchemaVertex indexSchemaVertex = managementSystem.getSchemaVertex(indexToBeUpdated); | ||
CompositeIndexType compositeIndexTypeToBeUpdated = (CompositeIndexType) indexSchemaVertex.asIndexType(); | ||
|
||
Serializer serializer = graph.getDataSerializer(); | ||
boolean hashKeys = graph.getIndexSerializer().isHashKeys(); | ||
HashingUtil.HashLength hashLength = graph.getIndexSerializer().getHashLength(); | ||
|
||
IndexUpdate<StaticBuffer, Entry> update = IndexRecordUtil.getCompositeIndexUpdate( | ||
compositeIndexTypeToBeUpdated, | ||
IndexMutationType.DELETE, | ||
fullIndexRecord, | ||
elementToBeRemoved, | ||
serializer, | ||
hashKeys, | ||
hashLength | ||
); | ||
|
||
BackendTransaction backendTransaction = tx.getTxHandle(); | ||
backendTransaction.mutateIndex(update.getKey(), Collections.emptyList(), Collections.singletonList(update.getEntry())); | ||
transaction.commit(); | ||
tx.commit(); | ||
mgmt.rollback(); | ||
``` |
Oops, something went wrong.