예제 #1
0
 private IndexRule[] getIndexesNeedingPopulation() {
   List<IndexRule> indexesNeedingPopulation = new ArrayList<>();
   for (SchemaRule rule : schemaCache.schemaRules()) {
     if (rule.getKind().isIndex()) {
       IndexRule indexRule = (IndexRule) rule;
       SchemaIndexProvider provider =
           schemaIndexProviders.apply(indexRule.getProviderDescriptor());
       if (provider.getInitialState(indexRule.getId()) != InternalIndexState.FAILED) {
         indexesNeedingPopulation.add(indexRule);
       }
     }
   }
   return indexesNeedingPopulation.toArray(new IndexRule[indexesNeedingPopulation.size()]);
 }
예제 #2
0
  private void createConstraintRule(UniquenessConstraint constraint) {
    // TODO: Do not create duplicate index

    SchemaStore schemaStore = getSchemaStore();

    long indexRuleId = schemaStore.nextId();
    long constraintRuleId = schemaStore.nextId();

    IndexRule indexRule =
        IndexRule.constraintIndexRule(
            indexRuleId,
            constraint.label(),
            constraint.propertyKeyId(),
            this.schemaIndexProviders.getDefaultProvider().getProviderDescriptor(),
            constraintRuleId);
    UniquenessConstraintRule constraintRule =
        UniquenessConstraintRule.uniquenessConstraintRule(
            constraintRuleId, constraint.label(), constraint.propertyKeyId(), indexRuleId);

    for (DynamicRecord record : schemaStore.allocateFrom(constraintRule)) {
      schemaStore.updateRecord(record);
    }
    schemaCache.addSchemaRule(constraintRule);
    for (DynamicRecord record : schemaStore.allocateFrom(indexRule)) {
      schemaStore.updateRecord(record);
    }
    schemaCache.addSchemaRule(indexRule);
    labelsTouched = true;
    recordAccess.commit();
  }
예제 #3
0
  @Test
  public void shouldUpdateHighIdsOnRecoveredTransaction() throws Exception {
    // GIVEN
    WriteTransaction tx = newWriteTransaction(NO_INDEXING);
    int nodeId = 5, relId = 10, relationshipType = 3, propertyKeyId = 4, ruleId = 8;

    // WHEN
    tx.nodeCreate(nodeId);
    tx.createRelationshipTypeToken(relationshipType, "type");
    tx.relationshipCreate(relId, 0, nodeId, nodeId);
    tx.relAddProperty(
        relId,
        propertyKeyId,
        new long[] {
          1l << 60, 1l << 60, 1l << 60, 1l << 60, 1l << 60, 1l << 60, 1l << 60, 1l << 60, 1l << 60,
          1l << 60
        });
    tx.createPropertyKeyToken("key", propertyKeyId);
    tx.nodeAddProperty(
        nodeId,
        propertyKeyId,
        "something long and nasty that requires dynamic records for sure I would think and hope. Ok then åäö%!=");
    for (int i = 0; i < 10; i++) {
      tx.addLabelToNode(10000 + i, nodeId);
    }
    tx.createSchemaRule(IndexRule.indexRule(ruleId, 100, propertyKeyId, PROVIDER_DESCRIPTOR));
    prepareAndCommitRecovered(tx);

    // THEN
    assertEquals("NodeStore", nodeId + 1, neoStore.getNodeStore().getHighId());
    assertEquals(
        "DynamicNodeLabelStore", 2, neoStore.getNodeStore().getDynamicLabelStore().getHighId());
    assertEquals("RelationshipStore", relId + 1, neoStore.getRelationshipStore().getHighId());
    assertEquals(
        "RelationshipTypeStore",
        relationshipType + 1,
        neoStore.getRelationshipTypeStore().getHighId());
    assertEquals(
        "RelationshipType NameStore",
        2,
        neoStore.getRelationshipTypeStore().getNameStore().getHighId());
    assertEquals("PropertyStore", 2, neoStore.getPropertyStore().getHighId());
    assertEquals(
        "PropertyStore DynamicStringStore",
        2,
        neoStore.getPropertyStore().getStringStore().getHighId());
    assertEquals(
        "PropertyStore DynamicArrayStore",
        2,
        neoStore.getPropertyStore().getArrayStore().getHighId());
    assertEquals(
        "PropertyIndexStore",
        propertyKeyId + 1,
        neoStore.getPropertyStore().getPropertyKeyTokenStore().getHighId());
    assertEquals(
        "PropertyKeyToken NameStore",
        2,
        neoStore.getPropertyStore().getPropertyKeyTokenStore().getNameStore().getHighId());
    assertEquals("SchemaStore", ruleId + 1, neoStore.getSchemaStore().getHighId());
  }
  @Test
  public void shouldStillReportInternalIndexStateAsPopulatingWhenConstraintIndexIsDonePopulating()
      throws Exception {
    // given
    when(accessor.newUpdater(any(IndexUpdateMode.class))).thenReturn(updater);

    IndexingService indexingService =
        newIndexingServiceWithMockedDependencies(populator, accessor, withData());

    life.start();

    // when
    indexingService.createIndex(
        IndexRule.constraintIndexRule(0, labelId, propertyKeyId, PROVIDER_DESCRIPTOR, null));
    IndexProxy proxy = indexingService.getProxyForRule(0);

    verify(populator, timeout(1000)).close(true);

    try (IndexUpdater updater = proxy.newUpdater(IndexUpdateMode.ONLINE)) {
      updater.process(add(10, "foo"));
    }

    // then
    assertEquals(InternalIndexState.POPULATING, proxy.getState());
    InOrder order = inOrder(populator, accessor, updater);
    order.verify(populator).create();
    order.verify(populator).close(true);
    order.verify(accessor).newUpdater(IndexUpdateMode.ONLINE);
    order.verify(updater).process(add(10, "foo"));
    order.verify(updater).close();
  }
  @Test
  public void indexCreationShouldBeIdempotent() throws Exception {
    // given
    when(accessor.newUpdater(any(IndexUpdateMode.class))).thenReturn(updater);

    IndexingService indexingService =
        newIndexingServiceWithMockedDependencies(populator, accessor, withData());

    life.start();

    // when
    indexingService.createIndex(
        IndexRule.indexRule(0, labelId, propertyKeyId, PROVIDER_DESCRIPTOR));
    indexingService.createIndex(
        IndexRule.indexRule(0, labelId, propertyKeyId, PROVIDER_DESCRIPTOR));

    // We are asserting that the second call to createIndex does not throw an exception.
  }
예제 #6
0
  @Test
  public void shouldRemoveSchemaRuleWhenRollingBackTransaction() throws Exception {
    // GIVEN
    WriteTransaction writeTransaction = newWriteTransaction(NO_INDEXING);

    // WHEN
    final long ruleId = neoStore.getSchemaStore().nextId();
    writeTransaction.createSchemaRule(IndexRule.indexRule(ruleId, 10, 7, PROVIDER_DESCRIPTOR));
    writeTransaction.prepare();
    writeTransaction.rollback();

    // THEN
    verifyNoMoreInteractions(cacheAccessBackDoor);
  }
예제 #7
0
  @Test
  public void shouldAddSchemaRuleToCacheWhenApplyingTransactionThatCreatesOne() throws Exception {
    // GIVEN
    WriteTransaction writeTransaction = newWriteTransaction(NO_INDEXING);

    // WHEN
    final long ruleId = neoStore.getSchemaStore().nextId();
    IndexRule schemaRule = IndexRule.indexRule(ruleId, 10, 8, PROVIDER_DESCRIPTOR);
    writeTransaction.createSchemaRule(schemaRule);
    writeTransaction.prepare();
    writeTransaction.commit();

    // THEN
    verify(cacheAccessBackDoor).addSchemaRule(schemaRule);
  }
예제 #8
0
  @Test
  public void createdSchemaRuleRecordMustBeWrittenHeavy() throws Exception {
    // THEN
    Visitor<XaCommand, RuntimeException> verifier = heavySchemaRuleVerifier();

    // GIVEN
    WriteTransaction tx = newWriteTransaction(NO_INDEXING, verifier);
    long ruleId = 0;
    int labelId = 5, propertyKeyId = 7;
    SchemaRule rule = IndexRule.indexRule(ruleId, labelId, propertyKeyId, PROVIDER_DESCRIPTOR);

    // WHEN
    tx.createSchemaRule(rule);
    prepareAndCommit(tx);
  }
예제 #9
0
  private void createIndexRule(Label label, String propertyKey) {
    // TODO: Do not create duplicate index

    SchemaStore schemaStore = getSchemaStore();
    IndexRule schemaRule =
        IndexRule.indexRule(
            schemaStore.nextId(),
            getOrCreateLabelId(label.name()),
            getOrCreatePropertyKeyId(propertyKey),
            this.schemaIndexProviders.getDefaultProvider().getProviderDescriptor());
    for (DynamicRecord record : schemaStore.allocateFrom(schemaRule)) {
      schemaStore.updateRecord(record);
    }
    schemaCache.addSchemaRule(schemaRule);
  }
예제 #10
0
  private void repopulateAllIndexes() throws IOException {
    final IndexRule[] rules = getIndexesNeedingPopulation();
    final IndexPopulator[] populators = new IndexPopulator[rules.length];
    // the store is uncontended at this point, so creating a local LockService is safe.
    LockService locks = new ReentrantLockService();
    IndexStoreView storeView = new NeoStoreIndexStoreView(locks, neoStore);

    final int[] labelIds = new int[rules.length];
    final int[] propertyKeyIds = new int[rules.length];

    for (int i = 0; i < labelIds.length; i++) {
      IndexRule rule = rules[i];
      labelIds[i] = rule.getLabel();
      propertyKeyIds[i] = rule.getPropertyKey();

      populators[i] =
          schemaIndexProviders
              .apply(rule.getProviderDescriptor())
              .getPopulator(rule.getId(), new IndexConfiguration(rule.isConstraintIndex()));
      populators[i].create();
    }

    Visitor<NodePropertyUpdate, IOException> propertyUpdateVisitor =
        new Visitor<NodePropertyUpdate, IOException>() {
          @Override
          public boolean visit(NodePropertyUpdate update) throws IOException {
            // Do a lookup from which property has changed to a list of indexes worried about that
            // property.
            int propertyKeyInQuestion = update.getPropertyKeyId();
            for (int i = 0; i < propertyKeyIds.length; i++) {
              if (propertyKeyIds[i] == propertyKeyInQuestion) {
                if (update.forLabel(labelIds[i])) {
                  try {
                    populators[i].add(update.getNodeId(), update.getValueAfter());
                  } catch (IndexEntryConflictException conflict) {
                    throw conflict.notAllowed(rules[i].getLabel(), rules[i].getPropertyKey());
                  }
                }
              }
            }
            return true;
          }
        };

    NodeLabelUpdateVisitor labelUpdateVisitor = new NodeLabelUpdateVisitor();
    StoreScan<IOException> storeScan =
        storeView.visitNodes(labelIds, propertyKeyIds, propertyUpdateVisitor, labelUpdateVisitor);
    storeScan.run();

    for (IndexPopulator populator : populators) {
      populator.close(true);
    }
    labelUpdateVisitor.close();
  }
예제 #11
0
  @Test
  public void shouldBringConstraintIndexOnlineWhenExplicitlyToldTo() throws Exception {
    // given
    IndexingService indexingService =
        newIndexingServiceWithMockedDependencies(populator, accessor, withData());

    life.start();

    // when
    indexingService.createIndex(
        IndexRule.constraintIndexRule(0, labelId, propertyKeyId, PROVIDER_DESCRIPTOR, null));
    IndexProxy proxy = indexingService.getProxyForRule(0);

    indexingService.activateIndex(0);

    // then
    assertEquals(ONLINE, proxy.getState());
    InOrder order = inOrder(populator, accessor);
    order.verify(populator).create();
    order.verify(populator).close(true);
  }
예제 #12
0
  @Test
  public void shouldLogIndexStateOnStart() throws Exception {
    // given
    TestLogger logger = new TestLogger();
    SchemaIndexProvider provider = mock(SchemaIndexProvider.class);
    when(provider.getProviderDescriptor()).thenReturn(PROVIDER_DESCRIPTOR);
    SchemaIndexProviderMap providerMap = new DefaultSchemaIndexProviderMap(provider);
    TokenNameLookup mockLookup = mock(TokenNameLookup.class);
    IndexingService indexingService =
        new IndexingService(
            mock(JobScheduler.class),
            providerMap,
            mock(IndexStoreView.class),
            mockLookup,
            mock(UpdateableSchemaState.class),
            mockLogging(logger));

    IndexRule onlineIndex = indexRule(1, 1, 1, PROVIDER_DESCRIPTOR);
    IndexRule populatingIndex = indexRule(2, 1, 2, PROVIDER_DESCRIPTOR);
    IndexRule failedIndex = indexRule(3, 2, 2, PROVIDER_DESCRIPTOR);

    when(provider.getInitialState(onlineIndex.getId())).thenReturn(ONLINE);
    when(provider.getInitialState(populatingIndex.getId()))
        .thenReturn(InternalIndexState.POPULATING);
    when(provider.getInitialState(failedIndex.getId())).thenReturn(InternalIndexState.FAILED);
    indexingService.initIndexes(asList(onlineIndex, populatingIndex, failedIndex).iterator());

    when(mockLookup.labelGetName(1)).thenReturn("LabelOne");
    when(mockLookup.labelGetName(2)).thenReturn("LabelTwo");
    when(mockLookup.propertyKeyGetName(1)).thenReturn("propertyOne");
    when(mockLookup.propertyKeyGetName(2)).thenReturn("propertyTwo");

    logger.clear();

    // when
    indexingService.start();

    // then
    verify(provider).getPopulationFailure(3);
    logger.assertAtLeastOnce(
        info("IndexingService.start: index on :LabelOne(propertyOne) is ONLINE"));
    logger.assertAtLeastOnce(
        info("IndexingService.start: index on :LabelOne(propertyTwo) is POPULATING"));
    logger.assertAtLeastOnce(
        info("IndexingService.start: index on :LabelTwo(propertyTwo) is FAILED"));
  }
예제 #13
0
  @Test
  public void shouldRemoveSchemaRuleFromCacheWhenApplyingTransactionThatDeletesOne()
      throws Exception {
    // GIVEN
    SchemaStore schemaStore = neoStore.getSchemaStore();
    int labelId = 10, propertyKey = 10;
    IndexRule rule =
        IndexRule.indexRule(schemaStore.nextId(), labelId, propertyKey, PROVIDER_DESCRIPTOR);
    Collection<DynamicRecord> records = schemaStore.allocateFrom(rule);
    for (DynamicRecord record : records) {
      schemaStore.updateRecord(record);
    }
    long ruleId = first(records).getId();
    WriteTransaction writeTransaction = newWriteTransaction(NO_INDEXING);

    // WHEN
    writeTransaction.dropSchemaRule(ruleId);
    writeTransaction.prepare();
    writeTransaction.commit();

    // THEN
    verify(cacheAccessBackDoor).removeSchemaRuleFromCache(ruleId);
  }
예제 #14
0
  @Test
  public void shouldCreateEqualNodePropertyUpdatesOnRecoveryOfCreatedNode() throws Exception {
    /* There was an issue where recovering a tx where a node with a label and a property
     * was created resulted in two exact copies of NodePropertyUpdates. */

    // GIVEN
    long nodeId = 1;
    int labelId = 5, propertyKeyId = 7;
    NodePropertyUpdate expectedUpdate =
        NodePropertyUpdate.add(nodeId, propertyKeyId, "Neo", new long[] {labelId});

    // -- an index
    long ruleId = 0;
    WriteTransaction tx = newWriteTransaction(NO_INDEXING);
    SchemaRule rule = IndexRule.indexRule(ruleId, labelId, propertyKeyId, PROVIDER_DESCRIPTOR);
    tx.createSchemaRule(rule);
    prepareAndCommit(tx);

    // -- and a tx creating a node with that label and property key
    IndexingService index = mock(IndexingService.class);
    CommandCapturingVisitor commandCapturingVisitor = new CommandCapturingVisitor();
    tx = newWriteTransaction(index, commandCapturingVisitor);
    tx.nodeCreate(nodeId);
    tx.addLabelToNode(labelId, nodeId);
    tx.nodeAddProperty(nodeId, propertyKeyId, "Neo");
    prepareAndCommit(tx);
    verify(index, times(1)).updateIndexes(argThat(matchesAll(expectedUpdate)));
    reset(index);

    // WHEN
    // -- later recovering that tx, there should be only one update
    tx = newWriteTransaction(index);
    commandCapturingVisitor.injectInto(tx);
    prepareAndCommitRecovered(tx);
    verify(index, times(1)).updateIndexes(argThat(matchesAll(expectedUpdate)));
  }
예제 #15
0
 private IndexRule newIndexRule(long id, int label, int propertyKey) {
   return IndexRule.indexRule(id, label, propertyKey, PROVIDER_DESCRIPTOR);
 }
예제 #16
0
 private static IndexDescriptor descriptor(IndexRule ruleRecord) {
   return new IndexDescriptor(ruleRecord.getLabel(), ruleRecord.getPropertyKey());
 }