示例#1
0
 /**
  * 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());
 }
示例#2
0
  @Override
  public Collection<DynamicRecord> put(long[] labelIds, NodeStore nodeStore) {
    long existingLabelsField = node.getLabelField();
    long existingLabelsBits = parseLabelsBody(existingLabelsField);

    Collection<DynamicRecord> changedDynamicRecords = node.getDynamicLabelRecords();

    if (labelField != 0) {
      // There are existing dynamic label records, get them
      nodeStore.ensureHeavy(node, existingLabelsBits);
      changedDynamicRecords = node.getDynamicLabelRecords();
      setNotInUse(changedDynamicRecords);
    }

    if (!new InlineNodeLabels(labelField, node)
        .tryInlineInNodeRecord(labelIds, changedDynamicRecords)) {
      Set<DynamicRecord> allRecords = new HashSet<>(changedDynamicRecords);
      Collection<DynamicRecord> allocatedRecords =
          nodeStore.allocateRecordsForDynamicLabels(
              node.getId(), labelIds, changedDynamicRecords.iterator());
      allRecords.addAll(allocatedRecords);
      node.setLabelField(dynamicPointer(allocatedRecords), allocatedRecords);
      changedDynamicRecords = allRecords;
    }

    return changedDynamicRecords;
  }
示例#3
0
 @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;
 }
示例#4
0
 @Override
 public Collection<DynamicRecord> remove(long labelId, NodeStore nodeStore) {
   nodeStore.ensureHeavy(node, parseLabelsBody(labelField));
   Collection<DynamicRecord> existingRecords = node.getDynamicLabelRecords();
   long[] existingLabelIds = nodeStore.getDynamicLabelsArray(existingRecords);
   long[] newLabelIds = filter(existingLabelIds, labelId);
   if (new InlineNodeLabels(labelField, node)
       .tryInlineInNodeRecord(newLabelIds, existingRecords)) {
     setNotInUse(existingRecords);
   } else {
     Collection<DynamicRecord> newRecords =
         nodeStore.allocateRecordsForDynamicLabels(
             node.getId(), newLabelIds, existingRecords.iterator());
     node.setLabelField(dynamicPointer(newRecords), existingRecords);
     if (!newRecords.equals(
         existingRecords)) { // One less dynamic record, mark that one as not in use
       for (DynamicRecord record : existingRecords) {
         if (!newRecords.contains(record)) {
           record.setInUse(false);
           record.setLength(0); // so that it will not be made heavy again...
         }
       }
     }
   }
   return existingRecords;
 }
示例#5
0
 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;
 }
示例#6
0
 @Override
 public Map<String, Object> getNodeProperties(long nodeId) {
   NodeRecord record = getNodeRecord(nodeId);
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     return getPropertyChain(record.getNextProp());
   }
   return Collections.emptyMap();
 }
示例#7
0
 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);
   }
 }
示例#8
0
 private long internalCreateNode(long nodeId, Map<String, Object> properties) {
   NodeRecord nodeRecord =
       new NodeRecord(
           nodeId, Record.NO_NEXT_RELATIONSHIP.intValue(), Record.NO_NEXT_PROPERTY.intValue());
   nodeRecord.setInUse(true);
   nodeRecord.setCreated();
   nodeRecord.setNextProp(createPropertyChain(properties));
   getNodeStore().updateRecord(nodeRecord);
   return nodeId;
 }
示例#9
0
 @Override
 public void setNodeProperties(long node, Map<String, Object> properties) {
   NodeRecord record = getNodeRecord(node).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();
 }
示例#10
0
 @Override
 public Collection<DynamicRecord> add(long labelId, NodeStore nodeStore) {
   nodeStore.ensureHeavy(node, parseLabelsBody(labelField));
   Collection<DynamicRecord> existingRecords = node.getDynamicLabelRecords();
   long[] existingLabelIds = nodeStore.getDynamicLabelsArray(existingRecords);
   long[] newLabelIds = LabelIdArray.concatAndSort(existingLabelIds, labelId);
   Collection<DynamicRecord> changedDynamicRecords =
       nodeStore.allocateRecordsForDynamicLabels(
           node.getId(), newLabelIds, existingRecords.iterator());
   node.setLabelField(dynamicPointer(changedDynamicRecords), changedDynamicRecords);
   return changedDynamicRecords;
 }
  @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);
  }
示例#12
0
 @Override
 public long[] getIfLoaded() {
   if (node.isLight()) {
     return null;
   }
   for (DynamicRecord dynamic : node.getDynamicLabelRecords()) {
     if (dynamic.isLight()) {
       return null;
     }
   }
   return stripNodeId(
       (long[])
           getRightArray(readFullByteArrayFromHeavyRecords(node.getDynamicLabelRecords(), ARRAY)));
 }
示例#13
0
  private long internalCreateNode(long nodeId, Map<String, Object> properties, Label... labels) {
    NodeRecord nodeRecord = recordAccess.getNodeRecords().create(nodeId, null).forChangingData();
    nodeRecord.setInUse(true);
    nodeRecord.setCreated();
    nodeRecord.setNextProp(
        propertyCreator.createPropertyChain(
            nodeRecord, propertiesIterator(properties), recordAccess.getPropertyRecords()));

    if (labels.length > 0) {
      setNodeLabels(nodeRecord, labels);
    }

    recordAccess.commit();
    return nodeId;
  }
示例#14
0
  @Test
  public void shouldReadNodeRecords() throws IOException {
    URL nodeStoreFile = getClass().getResource("exampledb/neostore.nodestore.db");

    LegacyNodeStoreReader nodeStoreReader =
        new LegacyNodeStoreReader(new File(nodeStoreFile.getFile()));
    assertEquals(1001, nodeStoreReader.getMaxId());
    Iterable<NodeRecord> records = nodeStoreReader.readNodeStore();
    int nodeCount = 0;
    for (NodeRecord record : records) {
      if (record.inUse()) nodeCount++;
    }
    assertEquals(501, nodeCount);
    nodeStoreReader.close();
  }
示例#15
0
 private void convertNodeToDenseIfNecessary(
     NodeRecord node,
     RecordAccess<Long, RelationshipRecord, Void> relRecords,
     RecordAccess<Long, RelationshipGroupRecord, Integer> relGroupRecords) {
   if (node.isDense()) {
     return;
   }
   long relId = node.getNextRel();
   if (relId != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     RecordProxy<Long, RelationshipRecord, Void> relChange = relRecords.getOrLoad(relId, null);
     RelationshipRecord rel = relChange.forReadingLinkage();
     if (RelationshipCounter.relCount(node.getId(), rel) >= neoStore.getDenseNodeThreshold()) {
       convertNodeToDenseNode(node, relChange.forChangingLinkage(), relRecords, relGroupRecords);
     }
   }
 }
示例#16
0
 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);
   }
 }
示例#17
0
 @Override
 public void setNodeProperties(long node, Map<String, Object> properties) {
   NodeRecord record = getNodeRecord(node);
   if (record.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
     deletePropertyChain(record.getNextProp());
     /*
      * Batch inserter does not make any attempt to maintain the store's
      * integrity. It makes sense however to keep some things intact where
      * the cost is relatively low. So here, when we delete the property
      * chain we first make sure that the node record (or the relationship
      * record below) does not point anymore to the deleted properties. This
      * way, if during creation, something goes wrong, it will not have the properties
      * expected instead of throwing invalid record exceptions.
      */
     record.setNextProp(Record.NO_NEXT_PROPERTY.intValue());
     getNodeStore().updateRecord(record);
   }
   record.setNextProp(createPropertyChain(properties));
   getNodeStore().updateRecord(record);
 }
示例#18
0
 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);
 }
示例#19
0
 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());
 }
示例#20
0
 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());
 }
 public RecordProxy<Long, RelationshipGroupRecord, Integer> getRelationshipGroup(
     NodeRecord node, int type) {
   long groupId = node.getNextRel();
   long previousGroupId = Record.NO_NEXT_RELATIONSHIP.intValue();
   Set<Integer> allTypes = new HashSet<>();
   while (groupId != Record.NO_NEXT_RELATIONSHIP.intValue()) {
     RecordProxy<Long, RelationshipGroupRecord, Integer> change =
         recordChangeSet.getRelGroupRecords().getOrLoad(groupId, type);
     RelationshipGroupRecord record = change.forReadingData();
     record.setPrev(previousGroupId); // not persistent so not a "change"
     allTypes.add(record.getType());
     if (record.getType() == type) {
       return change;
     }
     previousGroupId = groupId;
     groupId = record.getNext();
   }
   return null;
 }
 private void migrateNodes(NodeStore nodeStore, PropertyWriter propertyWriter)
     throws IOException {
   Iterable<NodeRecord> records = legacyStore.getNodeStoreReader().readNodeStore();
   // estimate total number of nodes using file size then calc number of dots or percentage
   // complete
   for (NodeRecord nodeRecord : records) {
     reportProgress(nodeRecord.getId());
     nodeStore.setHighId(nodeRecord.getId() + 1);
     if (nodeRecord.inUse()) {
       long startOfPropertyChain = nodeRecord.getNextProp();
       if (startOfPropertyChain != Record.NO_NEXT_RELATIONSHIP.intValue()) {
         long propertyRecordId = migrateProperties(startOfPropertyChain, propertyWriter);
         nodeRecord.setNextProp(propertyRecordId);
       }
       nodeStore.updateRecord(nodeRecord);
     } else {
       nodeStore.freeId(nodeRecord.getId());
     }
   }
   legacyStore.getNodeStoreReader().close();
 }
  @Test
  public void shouldNotReportMissingPropertyForDeletedNodeWithProperty() {
    // given
    PropertyRecord oldProperty = add(inUse(new PropertyRecord(10)));
    NodeRecord oldNode = add(inUse(new NodeRecord(20, false, 0, 0)));
    oldProperty.setNodeId(oldNode.getId());
    oldNode.setNextProp(oldProperty.getId());

    PropertyRecord newProperty = add(notInUse(new PropertyRecord(10)));
    NodeRecord newNode = add(notInUse(new NodeRecord(20, false, 0, 0)));
    newProperty.setNodeId(newNode.getId());
    newNode.setNextProp(newProperty.getId());

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

    // then
    verifyNoMoreInteractions(report);
  }
示例#24
0
 @Override
 public String toString() {
   return after.toString();
 }
示例#25
0
 @Override
 public long[] get(NodeStore nodeStore) {
   nodeStore.ensureHeavy(node, getFirstDynamicRecordId());
   return nodeStore.getDynamicLabelsArray(node.getDynamicLabelRecords());
 }
 public void updateFirstRelationships() {
   for (RecordProxy<Long, NodeRecord, Void> change : recordChangeSet.getNodeRecords().changes()) {
     NodeRecord record = change.forReadingLinkage();
     txState.setFirstIds(record.getId(), record.getNextRel(), record.getNextProp());
   }
 }
示例#27
0
  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());
    }
  }
示例#28
0
 private void connect(
     NodeRecord node,
     RelationshipRecord rel,
     RecordAccess<Long, RelationshipRecord, Void> relRecords) {
   connect(node.getId(), node.getNextRel(), rel, relRecords);
 }
示例#29
0
 public NodeCommand init(NodeRecord before, NodeRecord after) {
   setup(after.getId(), Mode.fromRecordState(after));
   this.before = before;
   this.after = after;
   return this;
 }