use of org.neo4j.kernel.impl.store.RelationshipGroupStore in project neo4j by neo4j.
the class DegreesRebuildFromStoreTest method skipNotUsedRecordsOnDegreeStoreRebuild.
@Test
void skipNotUsedRecordsOnDegreeStoreRebuild() throws Exception {
// given a dataset containing mixed sparse and dense nodes with relationships in random directions,
// where some chains have been marked as having external degrees
int denseThreshold = dense_node_threshold.defaultValue();
DatabaseLayout layout = DatabaseLayout.ofFlat(directory.homePath());
int[] relationshipTypes;
MutableLongLongMap expectedDegrees = LongLongMaps.mutable.empty();
try (Lifespan life = new Lifespan()) {
RecordStorageEngine storageEngine = openStorageEngine(layout, denseThreshold);
relationshipTypes = createRelationshipTypes(storageEngine);
life.add(storageEngine);
generateData(storageEngine, denseThreshold, relationshipTypes);
storageEngine.relationshipGroupDegreesStore().accept((groupId, direction, degree) -> expectedDegrees.put(combinedKeyOnGroupAndDirection(groupId, direction), degree), NULL);
assertThat(expectedDegrees.isEmpty()).isFalse();
RelationshipGroupStore groupStore = storageEngine.testAccessNeoStores().getRelationshipGroupStore();
long highId = groupStore.getHighId();
assertThat(highId).isGreaterThan(1);
for (int i = 10; i < highId; i++) {
RelationshipGroupRecord record = groupStore.getRecord(i, new RelationshipGroupRecord(i), RecordLoad.ALWAYS, NULL);
record.setInUse(false);
groupStore.updateRecord(record, NULL);
}
storageEngine.flushAndForce(NULL);
}
// when
directory.getFileSystem().deleteFile(layout.relationshipGroupDegreesStore());
try (Lifespan life = new Lifespan()) {
RecordStorageEngine storageEngine = assertDoesNotThrow(() -> life.add(openStorageEngine(layout, denseThreshold)));
// then
storageEngine.relationshipGroupDegreesStore().accept((groupId, direction, degree) -> {
long key = combinedKeyOnGroupAndDirection(groupId, direction);
assertThat(expectedDegrees.containsKey(key)).isTrue();
long expectedDegree = expectedDegrees.get(key);
expectedDegrees.remove(key);
assertThat(degree).isEqualTo(expectedDegree);
}, NULL);
assertThat(expectedDegrees.size()).isGreaterThan(0);
}
}
use of org.neo4j.kernel.impl.store.RelationshipGroupStore in project neo4j by neo4j.
the class RelationshipGroupChecker method checkToOwner.
/**
* Check relationship group to owner node
*/
private void checkToOwner(LongRange nodeIdRange, PageCacheTracer pageCacheTracer) {
ProgressListener localProgress = progress.threadLocalReporter();
RelationshipGroupStore groupStore = neoStores.getRelationshipGroupStore();
CacheAccess.Client client = context.cacheAccess.client();
final long highId = groupStore.getHighId();
try (var cursorContext = new CursorContext(pageCacheTracer.createPageCursorTracer(RELATIONSHIP_GROUPS_CHECKER_TAG));
RecordReader<RelationshipGroupRecord> groupReader = new RecordReader<>(neoStores.getRelationshipGroupStore(), true, cursorContext)) {
for (long id = 0; id < highId && !context.isCancelled(); id++) {
localProgress.add(1);
RelationshipGroupRecord record = groupReader.read(id);
if (!record.inUse()) {
continue;
}
long owningNode = record.getOwningNode();
if (nodeIdRange.isWithinRangeExclusiveTo(owningNode)) {
long cachedOwnerNextRel = client.getFromCache(owningNode, CacheSlots.NodeLink.SLOT_RELATIONSHIP_ID);
boolean nodeIsInUse = client.getBooleanFromCache(owningNode, CacheSlots.NodeLink.SLOT_IN_USE);
if (!nodeIsInUse) {
reporter.forRelationshipGroup(record).ownerNotInUse();
} else if (cachedOwnerNextRel == id) {
// The old checker only verified that the relationship group that node.nextGroup pointed to had this node as its owner
client.putToCacheSingle(owningNode, CacheSlots.NodeLink.SLOT_CHECK_MARK, 0);
}
if (NULL_REFERENCE.is(record.getNext())) {
// This is the last group in the chain for this node. Verify that there's only one such last group.
boolean hasAlreadySeenLastGroup = client.getBooleanFromCache(owningNode, CacheSlots.NodeLink.SLOT_HAS_LAST_GROUP);
if (hasAlreadySeenLastGroup) {
reporter.forRelationshipGroup(record).multipleLastGroups(context.recordLoader.node(owningNode, cursorContext));
}
client.putToCacheSingle(owningNode, CacheSlots.NodeLink.SLOT_HAS_LAST_GROUP, 1);
}
}
}
}
localProgress.done();
}
use of org.neo4j.kernel.impl.store.RelationshipGroupStore in project neo4j by neo4j.
the class WriteTransactionCommandOrderingTest method injectAllPossibleCommands.
private static TransactionRecordState injectAllPossibleCommands() {
RecordChangeSet recordChangeSet = mock(RecordChangeSet.class);
RecordChanges<LabelTokenRecord, Void> labelTokenChanges = mock(RecordChanges.class);
RecordChanges<RelationshipTypeTokenRecord, Void> relationshipTypeTokenChanges = mock(RecordChanges.class);
RecordChanges<PropertyKeyTokenRecord, Void> propertyKeyTokenChanges = mock(RecordChanges.class);
RecordChanges<NodeRecord, Void> nodeRecordChanges = mock(RecordChanges.class);
RecordChanges<RelationshipRecord, Void> relationshipRecordChanges = mock(RecordChanges.class);
RecordChanges<PropertyRecord, PrimitiveRecord> propertyRecordChanges = mock(RecordChanges.class);
RecordChanges<RelationshipGroupRecord, Integer> relationshipGroupChanges = mock(RecordChanges.class);
RecordChanges<SchemaRecord, SchemaRule> schemaRuleChanges = mock(RecordChanges.class);
when(recordChangeSet.getLabelTokenChanges()).thenReturn(labelTokenChanges);
when(recordChangeSet.getRelationshipTypeTokenChanges()).thenReturn(relationshipTypeTokenChanges);
when(recordChangeSet.getPropertyKeyTokenChanges()).thenReturn(propertyKeyTokenChanges);
when(recordChangeSet.getNodeRecords()).thenReturn(nodeRecordChanges);
when(recordChangeSet.getRelRecords()).thenReturn(relationshipRecordChanges);
when(recordChangeSet.getPropertyRecords()).thenReturn(propertyRecordChanges);
when(recordChangeSet.getRelGroupRecords()).thenReturn(relationshipGroupChanges);
when(recordChangeSet.getSchemaRuleChanges()).thenReturn(schemaRuleChanges);
List<RecordProxy<NodeRecord, Void>> nodeChanges = new LinkedList<>();
RecordChange<NodeRecord, Void> deletedNode = mock(RecordChange.class);
when(deletedNode.getBefore()).thenReturn(inUseNode());
when(deletedNode.forReadingLinkage()).thenReturn(missingNode());
nodeChanges.add(deletedNode);
RecordChange<NodeRecord, Void> createdNode = mock(RecordChange.class);
when(createdNode.getBefore()).thenReturn(missingNode());
when(createdNode.forReadingLinkage()).thenReturn(createdNode());
nodeChanges.add(createdNode);
RecordChange<NodeRecord, Void> updatedNode = mock(RecordChange.class);
when(updatedNode.getBefore()).thenReturn(inUseNode());
when(updatedNode.forReadingLinkage()).thenReturn(inUseNode());
nodeChanges.add(updatedNode);
when(nodeRecordChanges.changes()).thenReturn(nodeChanges);
when(nodeRecordChanges.changeSize()).thenReturn(3);
when(recordChangeSet.changeSize()).thenReturn(3);
when(labelTokenChanges.changes()).thenReturn(Collections.emptyList());
when(relationshipTypeTokenChanges.changes()).thenReturn(Collections.emptyList());
when(propertyKeyTokenChanges.changes()).thenReturn(Collections.emptyList());
when(relationshipRecordChanges.changes()).thenReturn(Collections.emptyList());
when(propertyRecordChanges.changes()).thenReturn(Collections.emptyList());
when(relationshipGroupChanges.changes()).thenReturn(Collections.emptyList());
when(schemaRuleChanges.changes()).thenReturn(Collections.emptyList());
NeoStores neoStores = mock(NeoStores.class);
NodeStore store = mock(NodeStore.class);
when(neoStores.getNodeStore()).thenReturn(store);
RelationshipGroupStore relationshipGroupStore = mock(RelationshipGroupStore.class);
when(neoStores.getRelationshipGroupStore()).thenReturn(relationshipGroupStore);
RelationshipStore relationshipStore = mock(RelationshipStore.class);
when(neoStores.getRelationshipStore()).thenReturn(relationshipStore);
return new TransactionRecordState(neoStores, mock(IntegrityValidator.class), recordChangeSet, 0, null, LockTracer.NONE, null, null, null, NULL, INSTANCE, LATEST_LOG_SERIALIZATION);
}
use of org.neo4j.kernel.impl.store.RelationshipGroupStore in project neo4j by neo4j.
the class DegreesRebuildFromStore method rebuild.
@Override
public void rebuild(RelationshipGroupDegreesStore.Updater updater, CursorContext cursorContext, MemoryTracker memoryTracker) {
// === sketch of a more performant version
// - Read all groups and for every group make a mark in a memory-structure like so:
// (node) -> (type,active directions,out,in,loop)
// - Read all relationships and for every matching node go into the memory-structure
// if it's there then look up the type
// if it's there then see if the direction matches any active direction
// if it does then increment the counter in the correct slot
// - Go though the memory-structure and write to the updater
//
// If not all data can fit in memory then do multiple passes (node id range)
RelationshipGroupStore groupStore = neoStores.getRelationshipGroupStore();
try (RecordStorageReader storageReader = new RecordStorageReader(neoStores);
StorageRelationshipTraversalCursor traversalCursor = storageReader.allocateRelationshipTraversalCursor(cursorContext);
PageCursor groupCursor = groupStore.openPageCursorForReadingWithPrefetching(0, cursorContext)) {
RelationshipGroupRecord groupRecord = groupStore.newRecord();
long highGroupId = groupStore.getHighId();
for (long id = groupStore.getNumberOfReservedLowIds(); id < highGroupId; id++) {
groupStore.getRecordByCursor(id, groupRecord, RecordLoad.LENIENT_CHECK, groupCursor);
if (groupRecord.inUse() && (groupRecord.hasExternalDegreesOut() || groupRecord.hasExternalDegreesIn() || groupRecord.hasExternalDegreesLoop())) {
updateDegree(groupRecord.hasExternalDegreesOut(), groupRecord.getFirstOut(), groupRecord, OUTGOING, traversalCursor, updater);
updateDegree(groupRecord.hasExternalDegreesIn(), groupRecord.getFirstIn(), groupRecord, INCOMING, traversalCursor, updater);
updateDegree(groupRecord.hasExternalDegreesLoop(), groupRecord.getFirstLoop(), groupRecord, LOOP, traversalCursor, updater);
}
}
}
}
use of org.neo4j.kernel.impl.store.RelationshipGroupStore in project neo4j by neo4j.
the class RecordNodeCursorTest method shouldChooseFastTotalDegreeLookupWhenPossible.
@Test
void shouldChooseFastTotalDegreeLookupWhenPossible() {
// given
NodeStore nodeStore = mock(NodeStore.class);
long relationshipId = 99;
long nextRelationshipId = relationshipId + 1;
long nodeId = 5;
int degree = 123;
when(nodeStore.getHighestPossibleIdInUse(NULL)).thenReturn(nodeId + 1);
doAnswer(invocationOnMock -> {
long id = invocationOnMock.getArgument(0);
NodeRecord record = invocationOnMock.getArgument(1);
record.setId(id);
record.initialize(true, NULL_REFERENCE.longValue(), false, relationshipId, NO_LABELS_FIELD.longValue());
return null;
}).when(nodeStore).getRecordByCursor(eq(nodeId), any(), any(), any());
RelationshipStore relationshipStore = mock(RelationshipStore.class);
doAnswer(invocationOnMock -> {
long id = invocationOnMock.getArgument(0);
RelationshipRecord record = invocationOnMock.getArgument(1);
record.setId(id);
record.initialize(true, NULL_REFERENCE.longValue(), nodeId, nodeId + 10, 1, degree, nextRelationshipId, 33, 44, true, false);
return null;
}).when(relationshipStore).getRecordByCursor(eq(relationshipId), any(), any(), any());
RelationshipGroupStore groupStore = mock(RelationshipGroupStore.class);
RelationshipGroupDegreesStore groupDegreesStore = mock(RelationshipGroupDegreesStore.class);
RecordNodeCursor nodeCursor = new RecordNodeCursor(nodeStore, relationshipStore, groupStore, groupDegreesStore, NULL);
// when
nodeCursor.single(nodeId);
assertThat(nodeCursor.next()).isTrue();
SingleDegree mutator = new SingleDegree();
nodeCursor.degrees(RelationshipSelection.ALL_RELATIONSHIPS, mutator, true);
// then
assertThat(mutator.getTotal()).isEqualTo(degree);
verifyNoInteractions(groupStore);
verify(relationshipStore).getRecordByCursor(eq(relationshipId), any(), any(), any());
verify(relationshipStore, never()).getRecordByCursor(eq(nextRelationshipId), any(), any(), any());
}
Aggregations