use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class RecordStorageEngineTestUtils method applyLogicalChanges.
public static void applyLogicalChanges(RecordStorageEngine storageEngine, ThrowingBiConsumer<ReadableTransactionState, TxStateVisitor, Exception> changes) throws Exception {
ReadableTransactionState txState = mock(ReadableTransactionState.class);
doAnswer(invocationOnMock -> {
TxStateVisitor visitor = invocationOnMock.getArgument(0);
changes.accept(txState, visitor);
return null;
}).when(txState).accept(any());
List<StorageCommand> commands = new ArrayList<>();
NeoStores neoStores = storageEngine.testAccessNeoStores();
MetaDataStore metaDataStore = neoStores.getMetaDataStore();
CursorContext cursorContext = CursorContext.NULL;
try (RecordStorageCommandCreationContext commandCreationContext = storageEngine.newCommandCreationContext(EmptyMemoryTracker.INSTANCE)) {
commandCreationContext.initialize(cursorContext);
storageEngine.createCommands(commands, txState, storageEngine.newReader(), commandCreationContext, ResourceLocker.IGNORE, LockTracer.NONE, metaDataStore.getLastCommittedTransactionId(), t -> t, cursorContext, EmptyMemoryTracker.INSTANCE);
storageEngine.apply(new GroupOfCommands(metaDataStore.nextCommittingTransactionId(), commands.toArray(new StorageCommand[0])), TransactionApplicationMode.EXTERNAL);
}
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class ManyPropertyKeysIT method databaseWithManyPropertyKeys.
private GraphDatabaseAPI databaseWithManyPropertyKeys(int propertyKeyCount) throws IOException {
var cacheTracer = PageCacheTracer.NULL;
var cursorContext = new CursorContext(cacheTracer.createPageCursorTracer("databaseWithManyPropertyKeys"));
StoreFactory storeFactory = new StoreFactory(databaseLayout, Config.defaults(), new DefaultIdGeneratorFactory(fileSystem, immediate(), databaseLayout.getDatabaseName()), pageCache, fileSystem, NullLogProvider.getInstance(), cacheTracer, writable());
NeoStores neoStores = storeFactory.openAllNeoStores(true);
PropertyKeyTokenStore store = neoStores.getPropertyKeyTokenStore();
for (int i = 0; i < propertyKeyCount; i++) {
PropertyKeyTokenRecord record = new PropertyKeyTokenRecord((int) store.nextId(cursorContext));
record.setInUse(true);
Collection<DynamicRecord> nameRecords = store.allocateNameRecords(PropertyStore.encodeString(key(i)), cursorContext, INSTANCE);
record.addNameRecords(nameRecords);
record.setNameId((int) Iterables.first(nameRecords).getId());
store.updateRecord(record, NULL);
}
neoStores.flush(cursorContext);
neoStores.close();
return database();
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class NodeChecker method check.
private void check(long fromNodeId, long toNodeId, boolean last) throws Exception {
long usedNodes = 0;
try (var cursorContext = new CursorContext(context.pageCacheTracer.createPageCursorTracer(NODE_RANGE_CHECKER_TAG));
RecordReader<NodeRecord> nodeReader = new RecordReader<>(context.neoStores.getNodeStore(), true, cursorContext);
RecordReader<DynamicRecord> labelReader = new RecordReader<>(context.neoStores.getNodeStore().getDynamicLabelStore(), false, cursorContext);
BoundedIterable<EntityTokenRange> labelIndexReader = getLabelIndexReader(fromNodeId, toNodeId, last, cursorContext);
SafePropertyChainReader property = new SafePropertyChainReader(context, cursorContext);
SchemaComplianceChecker schemaComplianceChecker = new SchemaComplianceChecker(context, mandatoryProperties, smallIndexes, cursorContext, context.memoryTracker)) {
ProgressListener localProgress = nodeProgress.threadLocalReporter();
MutableIntObjectMap<Value> propertyValues = new IntObjectHashMap<>();
CacheAccess.Client client = context.cacheAccess.client();
long[] nextRelCacheFields = new long[] { -1, -1, 1, /*inUse*/
0, 0, 1, /*note that this needs to be checked*/
0, 0 };
Iterator<EntityTokenRange> nodeLabelRangeIterator = labelIndexReader.iterator();
EntityTokenIndexCheckState labelIndexState = new EntityTokenIndexCheckState(null, fromNodeId - 1);
for (long nodeId = fromNodeId; nodeId < toNodeId && !context.isCancelled(); nodeId++) {
localProgress.add(1);
NodeRecord nodeRecord = nodeReader.read(nodeId);
if (!nodeRecord.inUse()) {
continue;
}
// Cache nextRel
long nextRel = nodeRecord.getNextRel();
if (nextRel < NULL_REFERENCE.longValue()) {
reporter.forNode(nodeRecord).relationshipNotInUse(new RelationshipRecord(nextRel));
nextRel = NULL_REFERENCE.longValue();
}
nextRelCacheFields[CacheSlots.NodeLink.SLOT_RELATIONSHIP_ID] = nextRel;
nextRelCacheFields[CacheSlots.NodeLink.SLOT_IS_DENSE] = longOf(nodeRecord.isDense());
usedNodes++;
// Labels
long[] unverifiedLabels = RecordLoading.safeGetNodeLabels(context, nodeRecord.getId(), nodeRecord.getLabelField(), labelReader, cursorContext);
long[] labels = checkNodeLabels(nodeRecord, unverifiedLabels, cursorContext);
// Cache the label field, so that if it contains inlined labels then it's free.
// Otherwise cache the dynamic labels in another data structure and point into it.
long labelField = nodeRecord.getLabelField();
boolean hasInlinedLabels = !NodeLabelsField.fieldPointsToDynamicRecordOfLabels(nodeRecord.getLabelField());
if (labels == null) {
// There was some inconsistency in the label field or dynamic label chain. Let's continue but w/o labels for this node
hasInlinedLabels = true;
labelField = NO_LABELS_FIELD.longValue();
}
boolean hasSingleLabel = labels != null && labels.length == 1;
nextRelCacheFields[CacheSlots.NodeLink.SLOT_HAS_INLINED_LABELS] = longOf(hasInlinedLabels);
nextRelCacheFields[CacheSlots.NodeLink.SLOT_LABELS] = hasSingleLabel ? // this makes RelationshipChecker "parse" the cached node labels more efficiently for single-label nodes
labels[0] : // Otherwise put the encoded label field if inlined, otherwise a ref to the cached dynamic labels
hasInlinedLabels ? labelField : observedCounts.cacheDynamicNodeLabels(labels);
nextRelCacheFields[CacheSlots.NodeLink.SLOT_HAS_SINGLE_LABEL] = longOf(hasSingleLabel);
// Properties
lightClear(propertyValues);
boolean propertyChainIsOk = property.read(propertyValues, nodeRecord, reporter::forNode, cursorContext);
// Label index
if (labelIndexReader.maxCount() != 0) {
checkNodeVsLabelIndex(nodeRecord, nodeLabelRangeIterator, labelIndexState, nodeId, labels, fromNodeId, cursorContext);
}
client.putToCache(nodeId, nextRelCacheFields);
// Mandatory properties and (some) indexing
if (labels != null && propertyChainIsOk) {
schemaComplianceChecker.checkContainsMandatoryProperties(nodeRecord, labels, propertyValues, reporter::forNode);
// gets checked this way, larger indexes will be checked in IndexChecker
if (context.consistencyFlags.isCheckIndexes()) {
schemaComplianceChecker.checkCorrectlyIndexed(nodeRecord, labels, propertyValues, reporter::forNode);
}
}
// Large indexes are checked elsewhere, more efficiently than per-entity
}
if (!context.isCancelled() && labelIndexReader.maxCount() != 0) {
reportRemainingLabelIndexEntries(nodeLabelRangeIterator, labelIndexState, last ? Long.MAX_VALUE : toNodeId, cursorContext);
}
localProgress.done();
}
observedCounts.incrementNodeLabel(ANY_LABEL, usedNodes);
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class NodeChecker method checkIndexVsNodes.
private void checkIndexVsNodes(LongRange range, IndexDescriptor descriptor, boolean lastRange) throws Exception {
CacheAccess.Client client = context.cacheAccess.client();
IndexAccessor accessor = context.indexAccessors.accessorFor(descriptor);
RelationshipCounter.NodeLabelsLookup nodeLabelsLookup = observedCounts.nodeLabelsLookup();
SchemaDescriptor schema = descriptor.schema();
PropertySchemaType propertySchemaType = schema.propertySchemaType();
long[] indexEntityTokenIds = toLongArray(schema.getEntityTokenIds());
indexEntityTokenIds = sortAndDeduplicate(indexEntityTokenIds);
try (var cursorContext = new CursorContext(context.pageCacheTracer.createPageCursorTracer(NODE_INDEXES_CHECKER_TAG));
var allEntriesReader = accessor.newAllEntriesValueReader(range.from(), lastRange ? Long.MAX_VALUE : range.to(), cursorContext)) {
for (long entityId : allEntriesReader) {
try {
boolean entityExists = client.getBooleanFromCache(entityId, CacheSlots.NodeLink.SLOT_IN_USE);
if (!entityExists) {
reporter.forIndexEntry(new IndexEntry(descriptor, context.tokenNameLookup, entityId)).nodeNotInUse(recordLoader.node(entityId, cursorContext));
} else {
long[] entityTokenIds = nodeLabelsLookup.nodeLabels(entityId);
compareTwoSortedLongArrays(propertySchemaType, entityTokenIds, indexEntityTokenIds, indexLabel -> reporter.forIndexEntry(new IndexEntry(descriptor, context.tokenNameLookup, entityId)).nodeDoesNotHaveExpectedLabel(recordLoader.node(entityId, cursorContext), indexLabel), storeLabel -> {
/*here we're only interested in what the the index has that the store doesn't have*/
});
}
} catch (ArrayIndexOutOfBoundsException e) {
// OK so apparently the index has a node way outside node highId
reporter.forIndexEntry(new IndexEntry(descriptor, context.tokenNameLookup, entityId)).nodeNotInUse(recordLoader.node(entityId, cursorContext));
}
}
}
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class RelationshipChainChecker method relationshipVsRelationshipChecker.
private ThrowingRunnable relationshipVsRelationshipChecker(LongRange nodeIdRange, ScanDirection direction, RelationshipStore store, ArrayBlockingQueue<BatchedRelationshipRecords> queue, AtomicBoolean end, int threadId) {
final RelationshipRecord relationship = store.newRecord();
final RelationshipRecord otherRelationship = store.newRecord();
final CacheAccess.Client client = cacheAccess.client();
final RelationshipLink sourceCachePointer = direction.sourceLink;
final RelationshipLink targetCachePointer = direction.targetLink;
final long prevOrNext = direction.cacheSlot;
return () -> {
try (var cursorContext = new CursorContext(context.pageCacheTracer.createPageCursorTracer(RELATIONSHIP_CONSISTENCY_CHECKER_TAG));
var otherRelationshipCursor = store.openPageCursorForReading(0, cursorContext)) {
while ((!end.get() || !queue.isEmpty()) && !context.isCancelled()) {
BatchedRelationshipRecords batch = queue.poll(100, TimeUnit.MILLISECONDS);
if (batch != null) {
while (batch.fillNext(relationship) && !context.isCancelled()) {
long firstNode = relationship.getFirstNode();
long secondNode = relationship.getSecondNode();
// Intentionally not checking nodes outside highId of node store because RelationshipChecker will spot this inconsistency
boolean processStartNode = Math.abs(firstNode % numberOfChainCheckers) == threadId && nodeIdRange.isWithinRangeExclusiveTo(firstNode);
boolean processEndNode = Math.abs(secondNode % numberOfChainCheckers) == threadId && nodeIdRange.isWithinRangeExclusiveTo(secondNode);
if (processStartNode) {
checkRelationshipLink(direction, SOURCE_PREV, relationship, client, otherRelationship, otherRelationshipCursor, store, cursorContext);
checkRelationshipLink(direction, SOURCE_NEXT, relationship, client, otherRelationship, otherRelationshipCursor, store, cursorContext);
}
if (processEndNode) {
checkRelationshipLink(direction, TARGET_PREV, relationship, client, otherRelationship, otherRelationshipCursor, store, cursorContext);
checkRelationshipLink(direction, TARGET_NEXT, relationship, client, otherRelationship, otherRelationshipCursor, store, cursorContext);
}
if (processStartNode) {
boolean wasInUse = client.getBooleanFromCache(firstNode, SLOT_IN_USE);
long link = sourceCachePointer.link(relationship);
if (link < NULL_REFERENCE.longValue()) {
sourceCachePointer.reportDoesNotReferenceBack(reporter, relationship, otherRelationship);
} else {
client.putToCache(firstNode, relationship.getId(), link, SOURCE, prevOrNext, 1, longOf(wasInUse), longOf(relationship.isFirstInFirstChain()));
}
}
if (processEndNode) {
boolean wasInUse = client.getBooleanFromCache(secondNode, SLOT_IN_USE);
long link = targetCachePointer.link(relationship);
if (link < NULL_REFERENCE.longValue()) {
targetCachePointer.reportDoesNotReferenceBack(reporter, relationship, otherRelationship);
} else {
client.putToCache(secondNode, relationship.getId(), link, TARGET, prevOrNext, 1, longOf(wasInUse), longOf(relationship.isFirstInSecondChain()));
}
}
}
}
}
}
};
}
Aggregations