コード例 #1
0
ファイル: NodeManager.java プロジェクト: sytanta/neo4j
 private void receiveRelationships(
     Iterable<RelationshipRecord> rels,
     ArrayMap<Integer, RelIdArray> newRelationshipMap,
     List<RelationshipImpl> relsList,
     DirectionWrapper dir,
     boolean hasLoops) {
   for (RelationshipRecord rel : rels) {
     long relId = rel.getId();
     RelationshipImpl relImpl = relCache.get(relId);
     RelationshipType type = null;
     int typeId;
     if (relImpl == null) {
       typeId = rel.getType();
       type = getRelationshipTypeById(typeId);
       assert type != null;
       relImpl =
           newRelationshipImpl(
               relId, rel.getFirstNode(), rel.getSecondNode(), type, typeId, false);
       relsList.add(relImpl);
     } else {
       typeId = relImpl.getTypeId();
       type = getRelationshipTypeById(typeId);
     }
     RelIdArray relationshipSet = newRelationshipMap.get(typeId);
     if (relationshipSet == null) {
       relationshipSet = hasLoops ? new RelIdArrayWithLoops(typeId) : new RelIdArray(typeId);
       newRelationshipMap.put(typeId, relationshipSet);
     }
     relationshipSet.add(relId, dir);
   }
 }
コード例 #2
0
 @Override
 public BatchRelationship apply(RelationshipRecord relRecord) {
   RelationshipType type =
       new RelationshipTypeImpl(relationshipTypeTokens.nameOf(relRecord.getType()));
   return new BatchRelationship(
       relRecord.getId(), relRecord.getFirstNode(), relRecord.getSecondNode(), type);
 }
コード例 #3
0
ファイル: NodeManager.java プロジェクト: sytanta/neo4j
 protected Relationship getRelationshipByIdOrNull(long relId) {
   RelationshipImpl relationship = relCache.get(relId);
   if (relationship != null) {
     return new RelationshipProxy(relId, relationshipLookups);
   }
   ReentrantLock loadLock = lockId(relId);
   try {
     relationship = relCache.get(relId);
     if (relationship != null) {
       return new RelationshipProxy(relId, relationshipLookups);
     }
     RelationshipRecord data = persistenceManager.loadLightRelationship(relId);
     if (data == null) {
       return null;
     }
     int typeId = data.getType();
     RelationshipType type = getRelationshipTypeById(typeId);
     if (type == null) {
       throw new NotFoundException(
           "Relationship["
               + data.getId()
               + "] exist but relationship type["
               + typeId
               + "] not found.");
     }
     final long startNodeId = data.getFirstNode();
     final long endNodeId = data.getSecondNode();
     relationship = newRelationshipImpl(relId, startNodeId, endNodeId, type, typeId, false);
     relCache.put(relationship);
     return new RelationshipProxy(relId, relationshipLookups);
   } finally {
     loadLock.unlock();
   }
 }
コード例 #4
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 @Override
 public BatchRelationship getRelationshipById(long relId) {
   RelationshipRecord record = getRelationshipRecord(relId);
   RelationshipType type = new RelationshipTypeImpl(typeHolder.getName(record.getType()));
   return new BatchRelationship(
       record.getId(), record.getFirstNode(), record.getSecondNode(), type);
 }
コード例 #5
0
ファイル: Command.java プロジェクト: naimdjon/neo4j
 @Override
 public void invalidateCache(CacheAccessBackDoor cacheAccess) {
   cacheAccess.removeRelationshipFromCache(getKey());
   /*
    * If isRecovered() then beforeUpdate is the correct one UNLESS this is the second time this command
    * is executed, where it might have been actually written out to disk so the fields are already -1. So
    * we still need to check.
    * If !isRecovered() then beforeUpdate is the same as record, so we are still ok.
    * We don't check for !inUse() though because that is implicit in the call of this method.
    * The above is a hand waiving proof that the conditions that lead to the patchDeletedRelationshipNodes()
    * in the if below are the same as in RelationshipCommand.execute() so it should be safe.
    */
   if (beforeUpdate.getFirstNode() != -1 || beforeUpdate.getSecondNode() != -1) {
     cacheAccess.patchDeletedRelationshipNodes(
         getKey(),
         beforeUpdate.getFirstNode(),
         beforeUpdate.getFirstNextRel(),
         beforeUpdate.getSecondNode(),
         beforeUpdate.getSecondNextRel());
   }
   if (record.getFirstNode() != -1 || record.getSecondNode() != -1) {
     cacheAccess.removeNodeFromCache(record.getFirstNode());
     cacheAccess.removeNodeFromCache(record.getSecondNode());
   }
 }
コード例 #6
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
 /**
  * Creates a relationship with the given id, from the nodes identified by id and of type typeId
  *
  * @param id The id of the relationship to create.
  * @param type The id of the relationship type this relationship will have.
  * @param firstNodeId The id of the start node.
  * @param secondNodeId The id of the end node.
  */
 public void relationshipCreate(
     long id, int type, long firstNodeId, long secondNodeId, RecordAccessSet recordChangeSet) {
   // TODO could be unnecessary to mark as changed here already, dense nodes may not need to change
   NodeRecord firstNode =
       recordChangeSet.getNodeRecords().getOrLoad(firstNodeId, null).forChangingLinkage();
   if (!firstNode.inUse()) {
     throw new IllegalStateException(
         "First node[" + firstNodeId + "] is deleted and cannot be used to create a relationship");
   }
   NodeRecord secondNode =
       recordChangeSet.getNodeRecords().getOrLoad(secondNodeId, null).forChangingLinkage();
   if (!secondNode.inUse()) {
     throw new IllegalStateException(
         "Second node["
             + secondNodeId
             + "] is deleted and cannot be used to create a relationship");
   }
   convertNodeToDenseIfNecessary(
       firstNode, recordChangeSet.getRelRecords(), recordChangeSet.getRelGroupRecords());
   convertNodeToDenseIfNecessary(
       secondNode, recordChangeSet.getRelRecords(), recordChangeSet.getRelGroupRecords());
   RelationshipRecord record =
       recordChangeSet.getRelRecords().create(id, null).forChangingLinkage();
   record.setLinks(firstNodeId, secondNodeId, type);
   record.setInUse(true);
   record.setCreated();
   connectRelationship(
       firstNode,
       secondNode,
       record,
       recordChangeSet.getRelRecords(),
       recordChangeSet.getRelGroupRecords());
 }
コード例 #7
0
 @Override
 public BatchRelationship getRelationshipById(long relId) {
   RelationshipRecord record = getRelationshipRecord(relId).forReadingData();
   RelationshipType type =
       new RelationshipTypeImpl(relationshipTypeTokens.nameOf(record.getType()));
   return new BatchRelationship(
       record.getId(), record.getFirstNode(), record.getSecondNode(), type);
 }
コード例 #8
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
 private void setCorrectNextRel(NodeRecord node, RelationshipRecord rel, long nextRel) {
   if (node.getId() == rel.getFirstNode()) {
     rel.setFirstNextRel(nextRel);
   }
   if (node.getId() == rel.getSecondNode()) {
     rel.setSecondNextRel(nextRel);
   }
 }
コード例 #9
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 @Override
 public Map<String, Object> getRelationshipProperties(long relId) {
   RelationshipRecord record = getRelationshipRecord(relId);
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     return getPropertyChain(record.getNextProp());
   }
   return Collections.emptyMap();
 }
コード例 #10
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
 private static RelationshipConnection relChain(RelationshipRecord rel, long nodeId) {
   if (rel.getFirstNode() == nodeId) {
     return RelationshipConnection.START_NEXT;
   }
   if (rel.getSecondNode() == nodeId) {
     return RelationshipConnection.END_NEXT;
   }
   throw new RuntimeException(nodeId + " neither start not end node in " + rel);
 }
コード例 #11
0
 @Override
 public Map<String, Object> getRelationshipProperties(long relId) {
   RelationshipRecord record =
       recordAccess.getRelRecords().getOrLoad(relId, null).forChangingData();
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     return getPropertyChain(record.getNextProp());
   }
   return Collections.emptyMap();
 }
コード例 #12
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 public Iterable<SimpleRelationship> getSimpleRelationships(long nodeId) {
   NodeRecord nodeRecord = getNodeRecord(nodeId);
   long nextRel = nodeRecord.getNextRel();
   List<SimpleRelationship> rels = new ArrayList<SimpleRelationship>();
   while (nextRel != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     RelationshipRecord relRecord = getRelationshipRecord(nextRel);
     RelationshipType type = new RelationshipTypeImpl(typeHolder.getName(relRecord.getType()));
     rels.add(
         new SimpleRelationship(
             relRecord.getId(), relRecord.getFirstNode(), relRecord.getSecondNode(), type));
     long firstNode = relRecord.getFirstNode();
     long secondNode = relRecord.getSecondNode();
     if (firstNode == nodeId) {
       nextRel = relRecord.getFirstNextRel();
     } else if (secondNode == nodeId) {
       nextRel = relRecord.getSecondNextRel();
     } else {
       throw new InvalidRecordException(
           "Node["
               + nodeId
               + "] not part of firstNode["
               + firstNode
               + "] or secondNode["
               + secondNode
               + "]");
     }
   }
   return rels;
 }
コード例 #13
0
 @Override
 public void setRelationshipProperties(long rel, Map<String, Object> properties) {
   RelationshipRecord record = recordAccess.getRelRecords().getOrLoad(rel, null).forChangingData();
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     propertyDeletor.getAndDeletePropertyChain(record, recordAccess.getPropertyRecords());
   }
   record.setNextProp(
       propertyCreator.createPropertyChain(
           record, propertiesIterator(properties), recordAccess.getPropertyRecords()));
   recordAccess.commit();
 }
コード例 #14
0
  @Test
  public void shouldNotReportMissingPropertyForDeletedRelationshipWithProperty() {
    // given
    NodeRecord oldNode1 = add(inUse(new NodeRecord(1, false, NONE, NONE)));
    NodeRecord oldNode2 = add(inUse(new NodeRecord(2, false, NONE, NONE)));

    RelationshipRecord oldRel = add(inUse(new RelationshipRecord(42, 1, 2, 7)));
    oldNode1.setNextRel(oldRel.getId());
    oldNode2.setNextRel(oldRel.getId());

    PropertyRecord oldProperty = add(inUse(new PropertyRecord(101)));
    oldProperty.setRelId(oldRel.getId());
    oldRel.setNextProp(oldProperty.getId());

    NodeRecord newNode1 = add(notInUse(new NodeRecord(1, false, NONE, NONE)));
    NodeRecord newNode2 = add(notInUse(new NodeRecord(2, false, NONE, NONE)));

    RelationshipRecord newRel = add(notInUse(new RelationshipRecord(42, 1, 2, 7)));
    newNode1.setNextRel(newRel.getId());
    newNode2.setNextRel(newRel.getId());

    PropertyRecord newProperty = add(notInUse(new PropertyRecord(101)));
    newProperty.setRelId(newRel.getId());
    newRel.setNextProp(newProperty.getId());

    // when
    ConsistencyReport.PropertyConsistencyReport report = checkChange(oldProperty, newProperty);

    // then
    verifyNoMoreInteractions(report);
  }
コード例 #15
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 @Override
 public void setRelationshipProperties(long rel, Map<String, Object> properties) {
   RelationshipRecord record = getRelationshipRecord(rel);
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     deletePropertyChain(record.getNextProp());
     /*
      * See setNodeProperties above for an explanation of what goes on
      * here
      */
     record.setNextProp(Record.NO_NEXT_PROPERTY.intValue());
     getRelationshipStore().updateRecord(record);
   }
   record.setNextProp(createPropertyChain(properties));
   getRelationshipStore().updateRecord(record);
 }
コード例 #16
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
 private void connectRelationshipToDenseNode(
     NodeRecord node,
     RelationshipRecord rel,
     RecordAccess<Long, RelationshipRecord, Void> relRecords,
     RecordAccess<Long, RelationshipGroupRecord, Integer> relGroupRecords) {
   RelationshipGroupRecord group =
       relGroupGetter
           .getOrCreateRelationshipGroup(node, rel.getType(), relGroupRecords)
           .forChangingData();
   RelIdArray.DirectionWrapper dir = DirectionIdentifier.wrapDirection(rel, node);
   long nextRel = dir.getNextRel(group);
   setCorrectNextRel(node, rel, nextRel);
   connect(node.getId(), nextRel, rel, relRecords);
   dir.setNextRel(group, rel.getId());
 }
コード例 #17
0
  @Test
  public void shouldReadRelationshipRecords() throws IOException {
    URL nodeStoreFile = getClass().getResource("exampledb/neostore.relationshipstore.db");

    LegacyRelationshipStoreReader relationshipStoreReader =
        new LegacyRelationshipStoreReader(new File(nodeStoreFile.getFile()));
    assertEquals(1500, relationshipStoreReader.getMaxId());
    Iterable<RelationshipRecord> records = relationshipStoreReader.readRelationshipStore();
    int relationshipCount = 0;
    for (RelationshipRecord record : records) {
      if (record.inUse()) relationshipCount++;
    }
    assertEquals(500, relationshipCount);
    relationshipStoreReader.close();
  }
コード例 #18
0
 @Override
 public long createRelationship(
     long node1, long node2, RelationshipType type, Map<String, Object> properties) {
   long id = neoStore.getRelationshipStore().nextId();
   int typeId = getOrCreateRelationshipTypeToken(type);
   relationshipCreator.relationshipCreate(id, typeId, node1, node2, recordAccess);
   if (properties != null && !properties.isEmpty()) {
     RelationshipRecord record =
         recordAccess.getRelRecords().getOrLoad(id, null).forChangingData();
     record.setNextProp(
         propertyCreator.createPropertyChain(
             record, propertiesIterator(properties), recordAccess.getPropertyRecords()));
   }
   recordAccess.commit();
   return id;
 }
コード例 #19
0
ファイル: Command.java プロジェクト: naimdjon/neo4j
 public RelationshipCommand init(RelationshipRecord record) {
   setup(record.getId(), Mode.fromRecordState(record));
   this.record = record;
   // the default (common) case is that the record to be written is complete and not from
   // recovery or HA
   this.beforeUpdate = record;
   return this;
 }
コード例 #20
0
  @Test
  public void shouldReportPropertyNotReferencedFromRelationshipWithChain() throws Exception {
    // given
    PropertyRecord oldProperty = notInUse(new PropertyRecord(42));
    PropertyRecord newProperty = inUse(new PropertyRecord(42));
    RelationshipRecord rel = add(inUse(new RelationshipRecord(1, 10, 20, 0)));
    PropertyRecord a = add(inUse(new PropertyRecord(1)));
    PropertyRecord b = add(inUse(new PropertyRecord(2)));
    a.setNextProp(b.getId());
    b.setPrevProp(a.getId());
    rel.setNextProp(a.getId());
    newProperty.setRelId(rel.getId());

    // when
    ConsistencyReport.PropertyConsistencyReport report = checkChange(oldProperty, newProperty);

    // then
    verify(report).ownerDoesNotReferenceBack();
    verifyNoMoreInteractions(report);
  }
コード例 #21
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 @Override
 public long createRelationship(
     long node1, long node2, RelationshipType type, Map<String, Object> properties) {
   NodeRecord firstNode = getNodeRecord(node1);
   NodeRecord secondNode = getNodeRecord(node2);
   int typeId = typeHolder.getTypeId(type.name());
   if (typeId == -1) {
     typeId = createNewRelationshipType(type.name());
   }
   long id = getRelationshipStore().nextId();
   RelationshipRecord record = new RelationshipRecord(id, node1, node2, typeId);
   record.setInUse(true);
   record.setCreated();
   connectRelationship(firstNode, secondNode, record);
   getNodeStore().updateRecord(firstNode);
   getNodeStore().updateRecord(secondNode);
   record.setNextProp(createPropertyChain(properties));
   getRelationshipStore().updateRecord(record);
   return id;
 }
コード例 #22
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 @Override
 public Iterable<Long> getRelationshipIds(long nodeId) {
   NodeRecord nodeRecord = getNodeRecord(nodeId);
   long nextRel = nodeRecord.getNextRel();
   List<Long> ids = new ArrayList<Long>();
   while (nextRel != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     RelationshipRecord relRecord = getRelationshipRecord(nextRel);
     ids.add(relRecord.getId());
     long firstNode = relRecord.getFirstNode();
     long secondNode = relRecord.getSecondNode();
     if (firstNode == nodeId) {
       nextRel = relRecord.getFirstNextRel();
     } else if (secondNode == nodeId) {
       nextRel = relRecord.getSecondNextRel();
     } else {
       throw new InvalidRecordException(
           "Node["
               + nodeId
               + "] not part of firstNode["
               + firstNode
               + "] or secondNode["
               + secondNode
               + "]");
     }
   }
   return ids;
 }
コード例 #23
0
ファイル: NodeManager.java プロジェクト: sytanta/neo4j
 public RelationshipImpl getRelationshipForProxy(long relId, LockType lock) {
   if (lock != null) {
     lock.acquire(getTransactionState(), new RelationshipProxy(relId, relationshipLookups));
   }
   RelationshipImpl relationship = relCache.get(relId);
   if (relationship != null) {
     return relationship;
   }
   ReentrantLock loadLock = lockId(relId);
   try {
     relationship = relCache.get(relId);
     if (relationship != null) {
       return relationship;
     }
     RelationshipRecord data = persistenceManager.loadLightRelationship(relId);
     if (data == null) {
       throw new NotFoundException(format("Relationship %d not found", relId));
     }
     int typeId = data.getType();
     RelationshipType type = getRelationshipTypeById(typeId);
     if (type == null) {
       throw new NotFoundException(
           "Relationship["
               + data.getId()
               + "] exist but relationship type["
               + typeId
               + "] not found.");
     }
     relationship =
         newRelationshipImpl(
             relId, data.getFirstNode(), data.getSecondNode(), type, typeId, false);
     // relCache.put( relId, relationship );
     relCache.put(relationship);
     return relationship;
   } finally {
     loadLock.unlock();
   }
 }
コード例 #24
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
  private void connectRelationship(
      NodeRecord firstNode,
      NodeRecord secondNode,
      RelationshipRecord rel,
      RecordAccess<Long, RelationshipRecord, Void> relRecords,
      RecordAccess<Long, RelationshipGroupRecord, Integer> relGroupRecords) {
    // Assertion interpreted: if node is a normal node and we're trying to create a
    // relationship that we already have as first rel for that node --> error
    assert firstNode.getNextRel() != rel.getId() || firstNode.isDense();
    assert secondNode.getNextRel() != rel.getId() || secondNode.isDense();

    if (!firstNode.isDense()) {
      rel.setFirstNextRel(firstNode.getNextRel());
    }
    if (!secondNode.isDense()) {
      rel.setSecondNextRel(secondNode.getNextRel());
    }

    if (!firstNode.isDense()) {
      connect(firstNode, rel, relRecords);
    } else {
      connectRelationshipToDenseNode(firstNode, rel, relRecords, relGroupRecords);
    }

    if (!secondNode.isDense()) {
      if (firstNode.getId() != secondNode.getId()) {
        connect(secondNode, rel, relRecords);
      } else {
        rel.setFirstInFirstChain(true);
        rel.setSecondPrevRel(rel.getFirstPrevRel());
      }
    } else if (firstNode.getId() != secondNode.getId()) {
      connectRelationshipToDenseNode(secondNode, rel, relRecords, relGroupRecords);
    }

    if (!firstNode.isDense()) {
      firstNode.setNextRel(rel.getId());
    }
    if (!secondNode.isDense()) {
      secondNode.setNextRel(rel.getId());
    }
  }
コード例 #25
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
 private void convertNodeToDenseNode(
     NodeRecord node,
     RelationshipRecord firstRel,
     RecordAccess<Long, RelationshipRecord, Void> relRecords,
     RecordAccess<Long, RelationshipGroupRecord, Integer> relGroupRecords) {
   firstRel = relRecords.getOrLoad(firstRel.getId(), null).forChangingLinkage();
   node.setDense(true);
   node.setNextRel(Record.NO_NEXT_RELATIONSHIP.intValue());
   long relId = firstRel.getId();
   RelationshipRecord relRecord = firstRel;
   while (relId != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     locker.getWriteLock(relId);
     relId = relChain(relRecord, node.getId()).get(relRecord);
     connectRelationshipToDenseNode(node, relRecord, relRecords, relGroupRecords);
     if (relId == Record.NO_NEXT_RELATIONSHIP.intValue()) {
       break;
     }
     relRecord = relRecords.getOrLoad(relId, null).forChangingLinkage();
   }
   if (upgradedDenseNodes == null) {
     upgradedDenseNodes = new ArrayList<>();
   }
   upgradedDenseNodes.add(node);
 }
コード例 #26
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 private void connectRelationship(
     NodeRecord firstNode, NodeRecord secondNode, RelationshipRecord rel) {
   assert firstNode.getNextRel() != rel.getId();
   assert secondNode.getNextRel() != rel.getId();
   rel.setFirstNextRel(firstNode.getNextRel());
   rel.setSecondNextRel(secondNode.getNextRel());
   connect(firstNode, rel);
   connect(secondNode, rel);
   firstNode.setNextRel(rel.getId());
   secondNode.setNextRel(rel.getId());
 }
コード例 #27
0
ファイル: BatchInserterImpl.java プロジェクト: kov4l/neo4j
 private void connect(NodeRecord node, RelationshipRecord rel) {
   if (node.getNextRel() != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     RelationshipRecord nextRel = getRelationshipStore().getRecord(node.getNextRel());
     boolean changed = false;
     if (nextRel.getFirstNode() == node.getId()) {
       nextRel.setFirstPrevRel(rel.getId());
       changed = true;
     }
     if (nextRel.getSecondNode() == node.getId()) {
       nextRel.setSecondPrevRel(rel.getId());
       changed = true;
     }
     if (!changed) {
       throw new InvalidRecordException(node + " dont match " + nextRel);
     }
     getRelationshipStore().updateRecord(nextRel);
   }
 }
コード例 #28
0
    private void migrateRelationships(
        RelationshipStore relationshipStore, PropertyWriter propertyWriter) throws IOException {
      long nodeMaxId = legacyStore.getNodeStoreReader().getMaxId();

      Iterable<RelationshipRecord> records =
          legacyStore.getRelationshipStoreReader().readRelationshipStore();
      for (RelationshipRecord relationshipRecord : records) {
        reportProgress(nodeMaxId + relationshipRecord.getId());
        relationshipStore.setHighId(relationshipRecord.getId() + 1);
        if (relationshipRecord.inUse()) {
          long startOfPropertyChain = relationshipRecord.getNextProp();
          if (startOfPropertyChain != Record.NO_NEXT_RELATIONSHIP.intValue()) {
            long propertyRecordId = migrateProperties(startOfPropertyChain, propertyWriter);
            relationshipRecord.setNextProp(propertyRecordId);
          }
          relationshipStore.updateRecord(relationshipRecord);
        } else {
          relationshipStore.freeId(relationshipRecord.getId());
        }
      }
      legacyStore.getRelationshipStoreReader().close();
    }
コード例 #29
0
 @Override
 public Long apply(RelationshipRecord relRecord) {
   return relRecord.getId();
 }
コード例 #30
0
ファイル: RelationshipCreator.java プロジェクト: Chan93/neo4j
  private void connect(
      long nodeId,
      long firstRelId,
      RelationshipRecord rel,
      RecordAccess<Long, RelationshipRecord, Void> relRecords) {
    long newCount = 1;
    if (firstRelId != Record.NO_NEXT_RELATIONSHIP.intValue()) {
      locker.getWriteLock(firstRelId);
      RelationshipRecord firstRel = relRecords.getOrLoad(firstRelId, null).forChangingLinkage();
      boolean changed = false;
      if (firstRel.getFirstNode() == nodeId) {
        newCount = firstRel.getFirstPrevRel() + 1;
        firstRel.setFirstPrevRel(rel.getId());
        firstRel.setFirstInFirstChain(false);
        changed = true;
      }
      if (firstRel.getSecondNode() == nodeId) {
        newCount = firstRel.getSecondPrevRel() + 1;
        firstRel.setSecondPrevRel(rel.getId());
        firstRel.setFirstInSecondChain(false);
        changed = true;
      }
      if (!changed) {
        throw new InvalidRecordException(nodeId + " doesn't match " + firstRel);
      }
    }

    // Set the relationship count
    if (rel.getFirstNode() == nodeId) {
      rel.setFirstPrevRel(newCount);
      rel.setFirstInFirstChain(true);
    }
    if (rel.getSecondNode() == nodeId) {
      rel.setSecondPrevRel(newCount);
      rel.setFirstInSecondChain(true);
    }
  }