Search in sources :

Example 96 with RelationshipRecord

use of org.neo4j.kernel.impl.store.record.RelationshipRecord in project neo4j by neo4j.

the class RelationshipDeleter method relationshipDelete.

/**
 * Deletes relationships found in {@code ids}.
 * Here we assume that all required locks are taken do do the changes needed
 *
 * @param deletions The ids of all relationships to delete in this transaction.
 * @param recordChanges {@link RecordAccessSet} to coordinate and keep changes to records.
 * @param groupDegreesUpdater for recording updates to degrees for the degrees store.
 * @param nodeDataLookup additional lookup for groups.
 * @param locks {@link ResourceLocker} for optimistic locking for deleting groups.
 */
void relationshipDelete(RelationshipBatch deletions, RecordAccessSet recordChanges, RelationshipGroupDegreesStore.Updater groupDegreesUpdater, MappedNodeDataLookup nodeDataLookup, ResourceLocker locks) {
    deletions.forEach((id, type, startNode, endNode) -> {
        RelationshipRecord record = recordChanges.getRelRecords().getOrLoad(id, null, cursorContext).forChangingLinkage();
        propertyChainDeleter.deletePropertyChain(record, recordChanges.getPropertyRecords());
        disconnectRelationship(record, recordChanges.getRelRecords());
        updateNodesForDeletedRelationship(record, recordChanges, groupDegreesUpdater, nodeDataLookup, locks);
        record.setInUse(false);
        record.setType(-1);
    });
}
Also used : RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord)

Example 97 with RelationshipRecord

use of org.neo4j.kernel.impl.store.record.RelationshipRecord in project neo4j by neo4j.

the class RelationshipLockHelper method findAndLockInsertionPoint.

/**
 * Traverses a relationship chain and tries to exclusively lock two consecutive relationships, and if successful that location
 * can be used as an insertion point for new relationships.
 *
 * @param firstInChain first relationship to start traversing from.
 * @param nodeId node id, i.e. which side of the relationship to follow when traversing.
 * @param relRecords for coordinate changes in.
 * @param locks used to try and lock the relationships.
 * @param lockTracer to go with the locks.
 * @param cursorContext for tracing page cache access.
 * @return the insertion point, if found. Otherwise {@code null}.
 */
static RecordAccess.RecordProxy<RelationshipRecord, Void> findAndLockInsertionPoint(long firstInChain, long nodeId, RecordAccess<RelationshipRecord, Void> relRecords, ResourceLocker locks, LockTracer lockTracer, CursorContext cursorContext) {
    long nextRel = firstInChain;
    RecordAccess.RecordProxy<RelationshipRecord, Void> rBefore = null;
    // Start walking the relationship chain and see where we can insert it
    if (!isNull(nextRel)) {
        while (!isNull(nextRel)) {
            boolean r1Locked = locks.tryExclusiveLock(RELATIONSHIP, nextRel);
            RecordAccess.RecordProxy<RelationshipRecord, Void> r1 = relRecords.getOrLoad(nextRel, null, ALWAYS, cursorContext);
            RelationshipRecord r1Record = r1.forReadingLinkage();
            if (!r1Locked || !r1Record.inUse()) {
                nextRel = r1Record.getNextRel(nodeId);
                if (r1Locked) {
                    locks.releaseExclusive(RELATIONSHIP, r1.getKey());
                }
                continue;
            }
            long r2Id = r1Record.getNextRel(nodeId);
            if (!isNull(r2Id)) {
                boolean r2Locked = locks.tryExclusiveLock(RELATIONSHIP, r2Id);
                RecordAccess.RecordProxy<RelationshipRecord, Void> r2 = relRecords.getOrLoad(r2Id, null, ALWAYS, cursorContext);
                RelationshipRecord r2Record = r2.forReadingLinkage();
                if (!r2Locked || !r2Record.inUse()) {
                    nextRel = r2Record.getNextRel(nodeId);
                    locks.releaseExclusive(RELATIONSHIP, r1.getKey());
                    if (r2Locked) {
                        locks.releaseExclusive(RELATIONSHIP, r2.getKey());
                    }
                    continue;
                }
            // We can insert in between r1 and r2 here
            }
            // We can insert at the end here
            rBefore = r1;
            break;
        }
        if (rBefore == null) {
            // Group is minimum read locked, so no need to re-read
            locks.acquireExclusive(lockTracer, RELATIONSHIP, firstInChain);
            RecordAccess.RecordProxy<RelationshipRecord, Void> firstProxy = relRecords.getOrLoad(firstInChain, null, ALWAYS, cursorContext);
            long secondRel = firstProxy.forReadingLinkage().getNextRel(nodeId);
            if (!isNull(secondRel)) {
                locks.acquireExclusive(lockTracer, RELATIONSHIP, secondRel);
            }
            rBefore = firstProxy;
        }
    }
    return rBefore;
}
Also used : RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord)

Example 98 with RelationshipRecord

use of org.neo4j.kernel.impl.store.record.RelationshipRecord in project neo4j by neo4j.

the class RelationshipLockHelper method lockMultipleRelationships.

private static void lockMultipleRelationships(RelationshipModifications.RelationshipBatch ids, long optionalFirstInChain, RecordAccess<RelationshipRecord, Void> relRecords, ResourceLocker locks, CursorContext cursorContext, MemoryTracker memoryTracker) {
    /*
         * The idea here is to take all locks in sorted order to avoid deadlocks
         * We start locking by optimistic reading of relationship neighbours
         * Once all neighbours plus the relationship itself is locked, we verify if there are changes.
         *      If not -> then just continue
         *      Changes means we need to rewind and unlock, to get the new changes in correct order
         */
    int upperLimitOfLocks = ids.size() * 5 + /* self and 4 neighbours */
    1;
    try (MemoryTracker scopedMemoryTracker = memoryTracker.getScopedMemoryTracker()) {
        HeapTrackingLongObjectHashMap<RelationshipRecord> optimistic = HeapTrackingCollections.newLongObjectMap(scopedMemoryTracker);
        scopedMemoryTracker.allocateHeap(sizeOfLongArray(upperLimitOfLocks));
        // First will build the list of locks we need
        SortedLockList lockList = new SortedLockList(upperLimitOfLocks);
        // The locklist does not accept NULL(-1) values, so we don't need to care about that
        lockList.add(optionalFirstInChain);
        ids.forEach((id, type, startNode, endNode) -> {
            RelationshipRecord relationship = relRecords.getOrLoad(id, null, cursorContext).forReadingLinkage();
            optimistic.put(id, relationship);
            lockList.add(relationship.getId());
            lockList.add(START_NEXT.get(relationship));
            lockList.add(START_PREV.get(relationship));
            lockList.add(END_NEXT.get(relationship));
            lockList.add(END_PREV.get(relationship));
        });
        // Then we start traversing and locking
        while (lockList.nextUnique()) {
            long id = lockList.currentHighestLockedId();
            // This could be either a relationship we're deleting, a neighbour or the first-in-chain. They all needs to be locked
            locks.acquireExclusive(NONE, RELATIONSHIP, id);
            RelationshipRecord old = optimistic.get(id);
            if (old != null) {
                // This is a relationship we we're deleting
                // No when it is locked we can check if the optimistic read is stable
                RelationshipRecord actual = relRecords.getOrLoad(id, null, cursorContext).forReadingLinkage();
                if (recordHasLinkageChanges(old, actual)) {
                    // Something changed, so we need to retry, by unlocking and trying again
                    rewindAndUnlockChanged(locks, lockList, old, actual);
                    optimistic.put(id, actual);
                }
            }
        }
    }
}
Also used : RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord) MemoryTracker(org.neo4j.memory.MemoryTracker)

Example 99 with RelationshipRecord

use of org.neo4j.kernel.impl.store.record.RelationshipRecord in project neo4j by neo4j.

the class RelationshipModifier method checkAndLockRelationshipsIfNodeIsGoingToBeDense.

private boolean checkAndLockRelationshipsIfNodeIsGoingToBeDense(NodeRecord node, RelationshipModifications.NodeRelationshipIds byNode, RecordAccess<RelationshipRecord, Void> relRecords, ResourceLocker locks, LockTracer lockTracer) {
    // We have an exclusively locked sparse not that may turn dense
    long nextRel = node.getNextRel();
    if (!isNull(nextRel)) {
        RelationshipRecord rel = relRecords.getOrLoad(nextRel, null, cursorContext).forReadingData();
        long nodeId = node.getId();
        if (!rel.isFirstInChain(nodeId)) {
            throw new IllegalStateException("Expected node " + rel + " to be first in chain for node " + nodeId);
        }
        int currentDegree = relCount(nodeId, rel);
        if (currentDegree + byNode.creations().size() >= denseNodeThreshold) {
            // The current length plus our additions in this transaction is above threshold, it will be converted so we need to lock all the relationships
            // Since it is sparse and locked we can trust this chain read to be stable
            // find all id's and lock them as we will create new chains based on type and direction
            MutableLongList ids = LongLists.mutable.withInitialCapacity(currentDegree);
            do {
                ids.add(nextRel);
                nextRel = relRecords.getOrLoad(nextRel, null, cursorContext).forReadingData().getNextRel(nodeId);
            } while (!isNull(nextRel));
            locks.acquireExclusive(lockTracer, RELATIONSHIP, ids.toSortedArray());
            return true;
        }
    }
    return false;
}
Also used : MutableLongList(org.eclipse.collections.api.list.primitive.MutableLongList) RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord) RelationshipLockHelper.findAndLockInsertionPoint(org.neo4j.internal.recordstorage.RelationshipLockHelper.findAndLockInsertionPoint)

Example 100 with RelationshipRecord

use of org.neo4j.kernel.impl.store.record.RelationshipRecord in project neo4j by neo4j.

the class RelationshipCreator method convertNodeToDenseIfNecessary.

private void convertNodeToDenseIfNecessary(RecordProxy<NodeRecord, Void> nodeChange, RecordAccess<RelationshipRecord, Void> relRecords, RelationshipGroupDegreesStore.Updater groupDegreesUpdater, NodeDataLookup nodeDataLookup) {
    NodeRecord node = nodeChange.forReadingLinkage();
    if (node.isDense()) {
        return;
    }
    long relId = node.getNextRel();
    if (!isNull(relId)) {
        RecordProxy<RelationshipRecord, Void> relProxy = relRecords.getOrLoad(relId, null, cursorContext);
        if (relCount(node.getId(), relProxy.forReadingData()) >= denseNodeThreshold) {
            convertNodeToDenseNode(nodeChange, relProxy.forChangingLinkage(), relRecords, groupDegreesUpdater, nodeDataLookup);
        }
    }
}
Also used : NodeRecord(org.neo4j.kernel.impl.store.record.NodeRecord) RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord)

Aggregations

RelationshipRecord (org.neo4j.kernel.impl.store.record.RelationshipRecord)207 Test (org.junit.Test)73 NodeRecord (org.neo4j.kernel.impl.store.record.NodeRecord)69 ConsistencyReport (org.neo4j.consistency.report.ConsistencyReport)43 Test (org.junit.jupiter.api.Test)34 RelationshipTypeTokenRecord (org.neo4j.kernel.impl.store.record.RelationshipTypeTokenRecord)30 PropertyRecord (org.neo4j.kernel.impl.store.record.PropertyRecord)19 RelationshipGroupRecord (org.neo4j.kernel.impl.store.record.RelationshipGroupRecord)19 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)15 RelationshipStore (org.neo4j.kernel.impl.store.RelationshipStore)14 GraphStoreFixture (org.neo4j.consistency.checking.GraphStoreFixture)12 IdGenerator (org.neo4j.consistency.checking.GraphStoreFixture.IdGenerator)12 ConsistencySummaryStatistics (org.neo4j.consistency.report.ConsistencySummaryStatistics)12 TransactionDataBuilder (org.neo4j.consistency.checking.GraphStoreFixture.TransactionDataBuilder)11 InMemoryClosableChannel (org.neo4j.kernel.impl.transaction.log.InMemoryClosableChannel)11 RecordAccessStub (org.neo4j.consistency.store.RecordAccessStub)9 InputRelationship (org.neo4j.unsafe.impl.batchimport.input.InputRelationship)8 RepeatedTest (org.junit.jupiter.api.RepeatedTest)7 IOException (java.io.IOException)6 CursorContext (org.neo4j.io.pagecache.context.CursorContext)6