private void Disconnect(RelationshipRecord rel, RelationshipConnection pointer, RecordAccess <RelationshipRecord, Void> relChanges, ResourceLocker locks) { long otherRelId = pointer.otherSide().get(rel); if (otherRelId == Record.NO_NEXT_RELATIONSHIP.intValue()) { return; } locks.AcquireExclusive(LockTracer.NONE, ResourceTypes.RELATIONSHIP, otherRelId); RelationshipRecord otherRel = relChanges.GetOrLoad(otherRelId, null).forChangingLinkage(); bool changed = false; long newId = pointer.get(rel); bool newIsFirst = pointer.isFirstInChain(rel); if (otherRel.FirstNode == pointer.compareNode(rel)) { pointer.start().set(otherRel, newId, newIsFirst); changed = true; } if (otherRel.SecondNode == pointer.compareNode(rel)) { pointer.end().set(otherRel, newId, newIsFirst); changed = true; } if (!changed) { throw new InvalidRecordException(otherRel + " don't match " + rel); } }
public virtual RelationshipGroupPosition GetRelationshipGroup(NodeRecord node, int type, RecordAccess <RelationshipGroupRecord, int> relGroupRecords) { long groupId = node.NextRel; long previousGroupId = Record.NO_NEXT_RELATIONSHIP.intValue(); RecordAccess_RecordProxy <RelationshipGroupRecord, int> previous = null; RecordAccess_RecordProxy <RelationshipGroupRecord, int> current; while (groupId != Record.NO_NEXT_RELATIONSHIP.intValue()) { current = relGroupRecords.GetOrLoad(groupId, null); RelationshipGroupRecord record = current.ForReadingData(); record.Prev = previousGroupId; // not persistent so not a "change" if (record.Type == type) { return(new RelationshipGroupPosition(previous, current)); } else if (record.Type > type) { // The groups are sorted in the chain, so if we come too far we can return // empty handed right away return(new RelationshipGroupPosition(previous, null)); } previousGroupId = groupId; groupId = record.Next; previous = current; } return(new RelationshipGroupPosition(previous, null)); }
private void DecrementTotalRelationshipCount(long nodeId, RelationshipRecord rel, long firstRelId, RecordAccess <RelationshipRecord, Void> relRecords, ResourceLocker locks) { if (firstRelId == Record.NO_PREV_RELATIONSHIP.intValue()) { return; } bool firstInChain = RelIsFirstInChain(nodeId, rel); if (!firstInChain) { locks.AcquireExclusive(LockTracer.NONE, ResourceTypes.RELATIONSHIP, firstRelId); } RelationshipRecord firstRel = relRecords.GetOrLoad(firstRelId, null).forChangingLinkage(); if (nodeId == firstRel.FirstNode) { firstRel.FirstPrevRel = firstInChain ? relCount(nodeId, rel) - 1 : relCount(nodeId, firstRel) - 1; firstRel.FirstInFirstChain = true; } if (nodeId == firstRel.SecondNode) { firstRel.SecondPrevRel = firstInChain ? relCount(nodeId, rel) - 1 : relCount(nodeId, firstRel) - 1; firstRel.FirstInSecondChain = true; } }
private void UnlinkPropertyRecord <P>(PropertyRecord propRecord, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords, RecordAccess_RecordProxy <P, Void> primitiveRecordChange) where P : Org.Neo4j.Kernel.impl.store.record.PrimitiveRecord { P primitive = primitiveRecordChange.ForReadingLinkage(); Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); Debug.Assert(propRecord.Size() == 0); long prevProp = propRecord.PrevProp; long nextProp = propRecord.NextProp; if (primitive.NextProp == propRecord.Id) { Debug.Assert(propRecord.PrevProp == Record.NO_PREVIOUS_PROPERTY.intValue(), propRecord + " for "); +primitive; primitiveRecordChange.ForChangingLinkage().NextProp = nextProp; } if (prevProp != Record.NO_PREVIOUS_PROPERTY.intValue()) { PropertyRecord prevPropRecord = propertyRecords.GetOrLoad(prevProp, primitive).forChangingLinkage(); Debug.Assert(prevPropRecord.InUse(), prevPropRecord + "->" + propRecord + " for " + primitive); prevPropRecord.NextProp = nextProp; prevPropRecord.Changed = primitive; } if (nextProp != Record.NO_NEXT_PROPERTY.intValue()) { PropertyRecord nextPropRecord = propertyRecords.GetOrLoad(nextProp, primitive).forChangingLinkage(); Debug.Assert(nextPropRecord.InUse(), propRecord + "->" + nextPropRecord + " for " + primitive); nextPropRecord.PrevProp = prevProp; nextPropRecord.Changed = primitive; } propRecord.InUse = false; /* * The following two are not needed - the above line does all the work (PropertyStore * does not write out the prev/next for !inUse records). It is nice to set this * however to check for consistency when assertPropertyChain(). */ propRecord.PrevProp = Record.NO_PREVIOUS_PROPERTY.intValue(); propRecord.NextProp = Record.NO_NEXT_PROPERTY.intValue(); propRecord.Changed = primitive; Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); }
public virtual void GetPropertyChain(long nextProp, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords, Listener <PropertyBlock> collector) { while (nextProp != Record.NO_NEXT_PROPERTY.intValue()) { PropertyRecord propRecord = propertyRecords.GetOrLoad(nextProp, null).forReadingData(); foreach (PropertyBlock propBlock in propRecord) { collector.Receive(propBlock); } nextProp = propRecord.NextProp; } }
private void DeleteGroup(RecordAccess_RecordProxy <NodeRecord, Void> nodeChange, RelationshipGroupRecord group, RecordAccess <RelationshipGroupRecord, int> relGroupRecords) { long previous = group.Prev; long next = group.Next; if (previous == Record.NO_NEXT_RELATIONSHIP.intValue()) { // This is the first one, just point the node to the next group nodeChange.ForChangingLinkage().NextRel = next; } else { // There are others before it, point the previous to the next group RelationshipGroupRecord previousRecord = relGroupRecords.GetOrLoad(previous, null).forChangingLinkage(); previousRecord.Next = next; } if (next != Record.NO_NEXT_RELATIONSHIP.intValue()) { // There are groups after this one, point that next group to the previous of the group to be deleted RelationshipGroupRecord nextRecord = relGroupRecords.GetOrLoad(next, null).forChangingLinkage(); nextRecord.Prev = previous; } group.InUse = false; }
private void ConvertNodeToDenseIfNecessary(NodeRecord node, RecordAccess <RelationshipRecord, Void> relRecords, RecordAccess <RelationshipGroupRecord, int> relGroupRecords, ResourceLocker locks) { if (node.Dense) { return; } long relId = node.NextRel; if (relId != Record.NO_NEXT_RELATIONSHIP.intValue()) { RecordAccess_RecordProxy <RelationshipRecord, Void> relChange = relRecords.GetOrLoad(relId, null); RelationshipRecord rel = relChange.ForReadingLinkage(); if (RelCount(node.Id, rel) >= _denseNodeThreshold) { locks.AcquireExclusive(LockTracer.NONE, ResourceTypes.RELATIONSHIP, relId); // Re-read the record after we've locked it since another transaction might have // changed in the meantime. relChange = relRecords.GetOrLoad(relId, null); ConvertNodeToDenseNode(node, relChange.ForChangingLinkage(), relRecords, relGroupRecords, locks); } } }
private void ConvertNodeToDenseNode(NodeRecord node, RelationshipRecord firstRel, RecordAccess <RelationshipRecord, Void> relRecords, RecordAccess <RelationshipGroupRecord, int> relGroupRecords, ResourceLocker locks) { node.Dense = true; node.NextRel = Record.NO_NEXT_RELATIONSHIP.intValue(); long relId = firstRel.Id; RelationshipRecord relRecord = firstRel; while (relId != Record.NO_NEXT_RELATIONSHIP.intValue()) { // Get the next relationship id before connecting it (where linkage is overwritten) relId = RelChain(relRecord, node.Id).get(relRecord); ConnectRelationshipToDenseNode(node, relRecord, relRecords, relGroupRecords, locks); if (relId != Record.NO_NEXT_RELATIONSHIP.intValue()) { // Lock and load the next relationship in the chain locks.AcquireExclusive(LockTracer.NONE, ResourceTypes.RELATIONSHIP, relId); relRecord = relRecords.GetOrLoad(relId, null).forChangingLinkage(); } } }
private void Connect(long nodeId, long firstRelId, RelationshipRecord rel, RecordAccess <RelationshipRecord, Void> relRecords, ResourceLocker locks) { long newCount = 1; if (firstRelId != Record.NO_NEXT_RELATIONSHIP.intValue()) { locks.AcquireExclusive(LockTracer.NONE, ResourceTypes.RELATIONSHIP, firstRelId); RelationshipRecord firstRel = relRecords.GetOrLoad(firstRelId, null).forChangingLinkage(); bool changed = false; if (firstRel.FirstNode == nodeId) { newCount = firstRel.FirstPrevRel + 1; firstRel.FirstPrevRel = rel.Id; firstRel.FirstInFirstChain = false; changed = true; } if (firstRel.SecondNode == nodeId) { newCount = firstRel.SecondPrevRel + 1; firstRel.SecondPrevRel = rel.Id; firstRel.FirstInSecondChain = false; changed = true; } if (!changed) { throw new InvalidRecordException(nodeId + " doesn't match " + firstRel); } } // Set the relationship count if (rel.FirstNode == nodeId) { rel.FirstPrevRel = newCount; rel.FirstInFirstChain = true; } if (rel.SecondNode == nodeId) { rel.SecondPrevRel = newCount; rel.FirstInSecondChain = true; } }
/// <summary> /// Traverses a property record chain and finds the record containing the property with key {@code propertyKey}. /// If none is found and {@code strict} is {@code true} then <seealso cref="System.InvalidOperationException"/> is thrown, /// otherwise id value of <seealso cref="Record.NO_NEXT_PROPERTY"/> is returned. /// </summary> /// <param name="primitive"> <seealso cref="PrimitiveRecord"/> which is the owner of the chain. </param> /// <param name="propertyKey"> property key token id to look for. </param> /// <param name="propertyRecords"> access to records. </param> /// <param name="strict"> dictates behavior on property key not found. If {@code true} then <seealso cref="System.InvalidOperationException"/> /// is thrown, otherwise value of <seealso cref="Record.NO_NEXT_PROPERTY"/> is returned. </param> /// <returns> property record id containing property with the given {@code propertyKey}, otherwise if /// {@code strict} is false value of <seealso cref="Record.NO_NEXT_PROPERTY"/>. </returns> public virtual long FindPropertyRecordContaining(PrimitiveRecord primitive, int propertyKey, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords, bool strict) { long propertyRecordId = primitive.NextProp; while (!Record.NO_NEXT_PROPERTY.@is(propertyRecordId)) { PropertyRecord propertyRecord = propertyRecords.GetOrLoad(propertyRecordId, primitive).forReadingLinkage(); if (propertyRecord.GetPropertyBlock(propertyKey) != null) { return(propertyRecordId); } propertyRecordId = propertyRecord.NextProp; } if (strict) { throw new System.InvalidOperationException("No property record in property chain for " + primitive + " contained property with key " + propertyKey); } return(Record.NO_NEXT_PROPERTY.intValue()); }
public virtual bool AssertPropertyChain(PrimitiveRecord primitive, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords) { IList <PropertyRecord> toCheck = new LinkedList <PropertyRecord>(); long nextIdToFetch = primitive.NextProp; while (nextIdToFetch != Record.NO_NEXT_PROPERTY.intValue()) { PropertyRecord propRecord = propertyRecords.GetOrLoad(nextIdToFetch, primitive).forReadingLinkage(); toCheck.Add(propRecord); Debug.Assert(propRecord.InUse(), primitive + "->"); +Arrays.ToString(toCheck.ToArray()); Debug.Assert(propRecord.Size() <= PropertyType.PayloadSize, propRecord + " size " + propRecord.Size()); nextIdToFetch = propRecord.NextProp; } if (toCheck.Count == 0) { Debug.Assert(primitive.NextProp == Record.NO_NEXT_PROPERTY.intValue(), primitive); return(true); } PropertyRecord first = toCheck[0]; PropertyRecord last = toCheck[toCheck.Count - 1]; Debug.Assert(first.PrevProp == Record.NO_PREVIOUS_PROPERTY.intValue(), primitive + "->"); +Arrays.ToString(toCheck.ToArray()); Debug.Assert(last.NextProp == Record.NO_NEXT_PROPERTY.intValue(), primitive + "->"); +Arrays.ToString(toCheck.ToArray()); PropertyRecord current; PropertyRecord previous = first; for (int i = 1; i < toCheck.Count; i++) { current = toCheck[i]; Debug.Assert(current.PrevProp == previous.Id, primitive + "->"); +Arrays.ToString(toCheck.ToArray()); Debug.Assert(previous.NextProp == current.Id, primitive + "->"); +Arrays.ToString(toCheck.ToArray()); previous = current; } return(true); }
public virtual RecordAccess_RecordProxy <RelationshipGroupRecord, int> GetOrCreateRelationshipGroup(NodeRecord node, int type, RecordAccess <RelationshipGroupRecord, int> relGroupRecords) { RelationshipGroupPosition existingGroup = GetRelationshipGroup(node, type, relGroupRecords); RecordAccess_RecordProxy <RelationshipGroupRecord, int> change = existingGroup.Group(); if (change == null) { Debug.Assert(node.Dense, "Node " + node + " should have been dense at this point"); long id = _idGenerator.nextId(); change = relGroupRecords.Create(id, type); RelationshipGroupRecord record = change.ForChangingData(); record.InUse = true; record.SetCreated(); record.OwningNode = node.Id; // Attach it... RecordAccess_RecordProxy <RelationshipGroupRecord, int> closestPreviousChange = existingGroup.ClosestPrevious(); if (closestPreviousChange != null) { // ...after the closest previous one RelationshipGroupRecord closestPrevious = closestPreviousChange.ForChangingLinkage(); record.Next = closestPrevious.Next; record.Prev = closestPrevious.Id; closestPrevious.Next = id; } else { // ...first in the chain long firstGroupId = node.NextRel; if (firstGroupId != Record.NO_NEXT_RELATIONSHIP.intValue()) { // There are others, make way for this new group RelationshipGroupRecord previousFirstRecord = relGroupRecords.GetOrLoad(firstGroupId, type).forReadingData(); record.Next = previousFirstRecord.Id; previousFirstRecord.Prev = id; } node.NextRel = id; } } return(change); }
public virtual void PrimitiveSetProperty <P>(RecordAccess_RecordProxy <P, Void> primitiveRecordChange, int propertyKey, Value value, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords) where P : Org.Neo4j.Kernel.impl.store.record.PrimitiveRecord { PropertyBlock block = EncodePropertyValue(propertyKey, value); P primitive = primitiveRecordChange.ForReadingLinkage(); Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); int newBlockSizeInBytes = block.Size; // Traverse the existing property chain. Tracking two things along the way: // - (a) Free space for this block (candidateHost) // - (b) Existence of a block with the property key // Chain traversal can be aborted only if: // - (1) (b) occurs and new property block fits where the current is // - (2) (a) occurs and (b) has occurred, but new property block didn't fit // - (3) (b) occurs and (a) has occurred // - (4) Chain ends RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> freeHostProxy = null; RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> existingHostProxy = null; long prop = primitive.NextProp; while (prop != Record.NO_NEXT_PROPERTY.intValue()) // <-- (4) { RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> proxy = propertyRecords.GetOrLoad(prop, primitive); PropertyRecord propRecord = proxy.ForReadingLinkage(); Debug.Assert(propRecord.InUse(), propRecord); // (a) search for free space if (PropertyFitsInside(newBlockSizeInBytes, propRecord)) { freeHostProxy = proxy; if (existingHostProxy != null) { // (2) PropertyRecord freeHost = proxy.ForChangingData(); freeHost.AddPropertyBlock(block); freeHost.Changed = primitive; Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); return; } } // (b) search for existence of property key PropertyBlock existingBlock = propRecord.GetPropertyBlock(propertyKey); if (existingBlock != null) { // We found an existing property and whatever happens we have to remove the existing // block so that we can add the new one, where ever we decide to place it existingHostProxy = proxy; PropertyRecord existingHost = existingHostProxy.ForChangingData(); RemoveProperty(primitive, existingHost, existingBlock); // Now see if we at this point can add the new block if (newBlockSizeInBytes <= existingBlock.Size || PropertyFitsInside(newBlockSizeInBytes, existingHost)) // fallback check { // (1) yes we could add it right into the host of the existing block existingHost.AddPropertyBlock(block); Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); return; } else if (freeHostProxy != null) { // (3) yes we could add it to a previously found host with sufficiently free space in it PropertyRecord freeHost = freeHostProxy.ForChangingData(); freeHost.AddPropertyBlock(block); freeHost.Changed = primitive; Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); return; } // else we can't add it at this point } // Continue down the chain prop = propRecord.NextProp; } // At this point we haven't added the property block, although we may have found room for it // along the way. If we didn't then just create a new record, it's fine PropertyRecord freeHost; if (freeHostProxy == null) { // We couldn't find free space along the way, so create a new host record freeHost = propertyRecords.Create(_propertyRecordIdGenerator.nextId(), primitive).forChangingData(); freeHost.InUse = true; if (primitive.NextProp != Record.NO_NEXT_PROPERTY.intValue()) { // This isn't the first property record for the entity, re-shuffle the first one so that // the new one becomes the first PropertyRecord prevProp = propertyRecords.GetOrLoad(primitive.NextProp, primitive).forChangingLinkage(); Debug.Assert(prevProp.PrevProp == Record.NO_PREVIOUS_PROPERTY.intValue()); prevProp.PrevProp = freeHost.Id; freeHost.NextProp = prevProp.Id; prevProp.Changed = primitive; } // By the way, this is the only condition where the primitive record also needs to change primitiveRecordChange.ForChangingLinkage().NextProp = freeHost.Id; } else { freeHost = freeHostProxy.ForChangingData(); } // At this point we know that we have a host record with sufficient space in it for the block // to add, so simply add it freeHost.AddPropertyBlock(block); Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); }
public virtual void DeletePropertyChain(PrimitiveRecord primitive, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords) { long nextProp = primitive.NextProp; while (nextProp != Record.NO_NEXT_PROPERTY.intValue()) { RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> propertyChange = propertyRecords.GetOrLoad(nextProp, primitive); // TODO forChanging/forReading piggy-backing PropertyRecord propRecord = propertyChange.ForChangingData(); DeletePropertyRecordIncludingValueRecords(propRecord); nextProp = propRecord.NextProp; propRecord.Changed = primitive; } primitive.NextProp = Record.NO_NEXT_PROPERTY.intValue(); }
private void RemoveProperty <P>(RecordAccess_RecordProxy <P, Void> primitiveProxy, int propertyKey, RecordAccess <PropertyRecord, PrimitiveRecord> propertyRecords, PrimitiveRecord primitive, long propertyId) where P : Org.Neo4j.Kernel.impl.store.record.PrimitiveRecord { RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> recordChange = propertyRecords.GetOrLoad(propertyId, primitive); PropertyRecord propRecord = recordChange.ForChangingData(); if (!propRecord.InUse()) { throw new System.InvalidOperationException("Unable to delete property[" + propertyId + "] since it is already deleted."); } PropertyBlock block = propRecord.RemovePropertyBlock(propertyKey); if (block == null) { throw new System.InvalidOperationException("Property with index[" + propertyKey + "] is not present in property[" + propertyId + "]"); } foreach (DynamicRecord valueRecord in block.ValueRecords) { Debug.Assert(valueRecord.InUse()); valueRecord.SetInUse(false, block.Type.intValue()); propRecord.AddDeletedRecord(valueRecord); } if (propRecord.Size() > 0) { /* * There are remaining blocks in the record. We do not unlink yet. */ propRecord.Changed = primitive; Debug.Assert(_traverser.assertPropertyChain(primitive, propertyRecords)); } else { UnlinkPropertyRecord(propRecord, propertyRecords, primitiveProxy); } }