use of org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException in project neo4j by neo4j.
the class ConstraintIndexCreator method createUniquenessConstraintIndex.
/**
* You MUST hold a schema write lock before you call this method.
* However the schema write lock is temporarily released while populating the index backing the constraint.
* It goes a little like this:
* <ol>
* <li>Prerequisite: Getting here means that there's an open schema transaction which has acquired the
* SCHEMA WRITE lock.</li>
* <li>Index schema rule which is backing the constraint is created in a nested mini-transaction
* which doesn't acquire any locking, merely adds tx state and commits so that the index rule is applied
* to the store, which triggers the index population</li>
* <li>Release the SCHEMA WRITE lock</li>
* <li>Await index population to complete</li>
* <li>Acquire the SCHEMA WRITE lock (effectively blocking concurrent transactions changing
* data related to this constraint, and it so happens, most other transactions as well) and verify
* the uniqueness of the built index</li>
* <li>Leave this method, knowing that the uniqueness constraint rule will be added to tx state
* and this tx committed, which will create the uniqueness constraint</li>
* </ol>
*/
public long createUniquenessConstraintIndex(KernelStatement state, SchemaReadOperations schema, LabelSchemaDescriptor descriptor) throws TransactionFailureException, CreateConstraintFailureException, DropIndexFailureException, UniquePropertyValueValidationException {
UniquenessConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForSchema(descriptor);
NewIndexDescriptor index = createConstraintIndex(descriptor);
boolean success = false;
boolean reacquiredSchemaLock = false;
Client locks = state.locks().pessimistic();
try {
long indexId = schema.indexGetCommittedId(state, index);
// Release the SCHEMA WRITE lock during index population.
// At this point the integrity of the constraint to be created was checked
// while holding the lock and the index rule backing the soon-to-be-created constraint
// has been created. Now it's just the population left, which can take a long time
releaseSchemaLock(locks);
awaitConstrainIndexPopulation(constraint, indexId);
// Index population was successful, but at this point we don't know if the uniqueness constraint holds.
// Acquire SCHEMA WRITE lock and verify the constraints here in this user transaction
// and if everything checks out then it will be held until after the constraint has been
// created and activated.
acquireSchemaLock(state, locks);
reacquiredSchemaLock = true;
indexingService.getIndexProxy(indexId).verifyDeferredConstraints(propertyAccessor);
success = true;
return indexId;
} catch (SchemaRuleNotFoundException | IndexNotFoundKernelException e) {
throw new IllegalStateException(String.format("Index (%s) that we just created does not exist.", descriptor));
} catch (IndexEntryConflictException e) {
throw new UniquePropertyValueValidationException(constraint, VERIFICATION, e);
} catch (InterruptedException | IOException e) {
throw new CreateConstraintFailureException(constraint, e);
} finally {
if (!success) {
if (!reacquiredSchemaLock) {
acquireSchemaLock(state, locks);
}
dropUniquenessConstraintIndex(index);
}
}
}
use of org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException in project neo4j by neo4j.
the class BatchInserterImpl method repopulateAllIndexes.
private void repopulateAllIndexes() throws IOException, IndexEntryConflictException {
if (!labelsTouched) {
return;
}
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.
final NewIndexDescriptor[] descriptors = new NewIndexDescriptor[rules.length];
for (int i = 0; i < rules.length; i++) {
IndexRule rule = rules[i];
descriptors[i] = rule.getIndexDescriptor();
populators[i] = schemaIndexProviders.apply(rule.getProviderDescriptor()).getPopulator(rule.getId(), descriptors[i], new IndexSamplingConfig(config));
populators[i].create();
}
Visitor<NodeUpdates, IOException> propertyUpdateVisitor = updates -> {
for (int i = 0; i < descriptors.length; i++) {
Optional<IndexEntryUpdate> update = updates.forIndex(descriptors[i].schema());
if (update.isPresent()) {
try {
populators[i].add(Collections.singletonList(update.get()));
} catch (IndexEntryConflictException conflict) {
throw conflict.notAllowed(descriptors[i]);
}
}
}
return true;
};
List<NewIndexDescriptor> descriptorList = Arrays.asList(descriptors);
int[] labelIds = descriptorList.stream().mapToInt(index -> index.schema().getLabelId()).toArray();
int[] propertyKeyIds = descriptorList.stream().flatMapToInt(d -> Arrays.stream(d.schema().getPropertyIds())).toArray();
InitialNodeLabelCreationVisitor labelUpdateVisitor = new InitialNodeLabelCreationVisitor();
StoreScan<IOException> storeScan = indexStoreView.visitNodes(labelIds, (propertyKeyId) -> PrimitiveIntCollections.contains(propertyKeyIds, propertyKeyId), propertyUpdateVisitor, labelUpdateVisitor, true);
storeScan.run();
for (IndexPopulator populator : populators) {
populator.verifyDeferredConstraints(indexStoreView);
populator.close(true);
}
labelUpdateVisitor.close();
}
use of org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException in project neo4j by neo4j.
the class BatchInsertTest method uniquenessConstraintShouldBeCheckedOnBatchInserterShutdownAndFailIfViolated.
@Test
public void uniquenessConstraintShouldBeCheckedOnBatchInserterShutdownAndFailIfViolated() throws Exception {
// Given
Label label = label("Foo");
String property = "Bar";
String value = "Baz";
BatchInserter inserter = newBatchInserter();
// When
inserter.createDeferredConstraint(label).assertPropertyIsUnique(property).create();
inserter.createNode(Collections.<String, Object>singletonMap(property, value), label);
inserter.createNode(Collections.<String, Object>singletonMap(property, value), label);
// Then
try {
inserter.shutdown();
fail("Node that violates uniqueness constraint was created by batch inserter");
} catch (RuntimeException ex) {
// good
assertEquals(new IndexEntryConflictException(0, 1, value), ex.getCause());
}
}
use of org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException in project neo4j by neo4j.
the class SimpleUniquenessVerifier method verify.
@Override
public void verify(PropertyAccessor accessor, int[] propKeyIds, List<Object> updatedPropertyValues) throws IndexEntryConflictException, IOException {
try {
DuplicateCheckingCollector collector = DuplicateCheckingCollector.forProperties(accessor, propKeyIds);
for (Object propertyValue : updatedPropertyValues) {
collector.reset();
Query query = LuceneDocumentStructure.newSeekQuery(propertyValue);
indexSearcher().search(query, collector);
}
} catch (IOException e) {
Throwable cause = e.getCause();
if (cause instanceof IndexEntryConflictException) {
throw (IndexEntryConflictException) cause;
}
throw e;
}
}
use of org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException in project neo4j by neo4j.
the class ContractCheckingIndexProxyTest method shouldNotCloseWhileUpdating.
@Test(expected = /* THEN */
IllegalStateException.class)
public void shouldNotCloseWhileUpdating() throws IOException {
// GIVEN
final DoubleLatch latch = new DoubleLatch();
final IndexProxy inner = new IndexProxyAdapter() {
@Override
public IndexUpdater newUpdater(IndexUpdateMode mode) {
return super.newUpdater(mode);
}
};
final IndexProxy outer = newContractCheckingIndexProxy(inner);
outer.start();
// WHEN
runInSeparateThread(() -> {
try (IndexUpdater updater = outer.newUpdater(IndexUpdateMode.ONLINE)) {
updater.process(null);
latch.startAndWaitForAllToStartAndFinish();
} catch (IndexEntryConflictException e) {
throw new RuntimeException(e);
}
});
try {
latch.waitForAllToStart();
outer.close();
} finally {
latch.finish();
}
}
Aggregations