Search in sources :

Example 16 with SchemaRule

use of org.neo4j.internal.schema.SchemaRule in project neo4j by neo4j.

the class LogCommandSerializationV3_0_10 method readSchemaRule.

private static SchemaRule readSchemaRule(Collection<DynamicRecord> recordsBefore) {
    // TODO: Why was this assertion here?
    // assert first(recordsBefore).inUse() : "Asked to deserialize schema records that were not in
    // use.";
    SchemaRule rule;
    ByteBuffer deserialized = AbstractDynamicStore.concatData(recordsBefore, new byte[100]);
    try {
        rule = SchemaRuleSerialization35.deserialize(Iterables.first(recordsBefore).getId(), deserialized);
    } catch (MalformedSchemaRuleException e) {
        return null;
    }
    return rule;
}
Also used : MalformedSchemaRuleException(org.neo4j.internal.kernel.api.exceptions.schema.MalformedSchemaRuleException) SchemaRule(org.neo4j.internal.schema.SchemaRule) ByteBuffer(java.nio.ByteBuffer)

Example 17 with SchemaRule

use of org.neo4j.internal.schema.SchemaRule in project neo4j by neo4j.

the class LogCommandSerializationV4_0 method readSchemaRuleCommand.

@Override
protected Command readSchemaRuleCommand(ReadableChannel channel) throws IOException {
    long id = channel.getLong();
    byte schemaRulePresence = channel.get();
    boolean hasSchemaRule = schemaRulePresence == SchemaRecord.COMMAND_HAS_SCHEMA_RULE;
    SchemaRecord before = readSchemaRecord(id, channel);
    SchemaRecord after = readSchemaRecord(id, channel);
    markAfterRecordAsCreatedIfCommandLooksCreated(before, after);
    SchemaRule schemaRule = null;
    if (hasSchemaRule) {
        schemaRule = readSchemaRule(id, channel);
    }
    return new Command.SchemaRuleCommand(this, before, after, schemaRule);
}
Also used : SchemaRecord(org.neo4j.kernel.impl.store.record.SchemaRecord) SchemaRule(org.neo4j.internal.schema.SchemaRule)

Example 18 with SchemaRule

use of org.neo4j.internal.schema.SchemaRule in project neo4j by neo4j.

the class SchemaStorage35 method loadAllSchemaRules.

/**
 * Scans the schema store and loads all {@link SchemaRule rules} in it. This method is written with the assumption
 * that there's no id reuse on schema records.
 *
 * @param returnType type of {@link SchemaRule} to load.
 * @return {@link Iterator} of the loaded schema rules, lazily loaded when advancing the iterator.
 */
private <ReturnType extends SchemaRule> Iterator<ReturnType> loadAllSchemaRules(final Class<ReturnType> returnType, CursorContext cursorContext, ThrowingConsumer<Exception, RuntimeException> malformedExceptionHandler) {
    return new PrefetchingIterator<>() {

        private final long highestId = schemaStore.getHighestPossibleIdInUse(cursorContext);

        private long currentId = 1;

        /*record 0 contains the block size*/
        private final byte[] scratchData = newRecordBuffer();

        private final DynamicRecord record = schemaStore.newRecord();

        @Override
        protected ReturnType fetchNextOrNull() {
            while (currentId <= highestId) {
                try {
                    long id = currentId++;
                    schemaStore.getRecord(id, record, RecordLoad.LENIENT_CHECK, cursorContext);
                    if (!record.inUse()) {
                        continue;
                    }
                    schemaStore.getRecord(id, record, RecordLoad.NORMAL, cursorContext);
                    if (record.isStartRecord()) {
                        // that we're reading and that rule may have spanned multiple dynamic records.
                        try {
                            Collection<DynamicRecord> records;
                            try {
                                records = schemaStore.getRecords(id, RecordLoad.NORMAL, false, cursorContext);
                            } catch (InvalidRecordException e) {
                                // This may have been due to a concurrent drop of this rule.
                                continue;
                            }
                            SchemaRule schemaRule = SchemaStore35.readSchemaRule(id, records, scratchData);
                            if (returnType.isInstance(schemaRule)) {
                                return returnType.cast(schemaRule);
                            }
                        } catch (MalformedSchemaRuleException e) {
                            throw new RuntimeException(e);
                        }
                    }
                } catch (Exception e) {
                    malformedExceptionHandler.accept(e);
                }
            }
            return null;
        }
    };
}
Also used : DynamicRecord(org.neo4j.kernel.impl.store.record.DynamicRecord) PrefetchingIterator(org.neo4j.internal.helpers.collection.PrefetchingIterator) MalformedSchemaRuleException(org.neo4j.internal.kernel.api.exceptions.schema.MalformedSchemaRuleException) SchemaRule(org.neo4j.internal.schema.SchemaRule) InvalidRecordException(org.neo4j.kernel.impl.store.InvalidRecordException) InvalidRecordException(org.neo4j.kernel.impl.store.InvalidRecordException) MalformedSchemaRuleException(org.neo4j.internal.kernel.api.exceptions.schema.MalformedSchemaRuleException)

Example 19 with SchemaRule

use of org.neo4j.internal.schema.SchemaRule in project neo4j by neo4j.

the class SchemaStorage method streamAllSchemaRules.

@VisibleForTesting
Stream<SchemaRule> streamAllSchemaRules(boolean ignoreMalformed, CursorContext cursorContext) {
    long startId = schemaStore.getNumberOfReservedLowIds();
    long endId = schemaStore.getHighId();
    Stream<IndexDescriptor> nli = Stream.empty();
    KernelVersion currentVersion;
    try {
        currentVersion = versionSupplier.kernelVersion();
    } catch (IllegalStateException ignored) {
        // If KernelVersion is missing we are an older store.
        currentVersion = KernelVersion.V4_2;
    }
    if (currentVersion.isLessThan(KernelVersion.VERSION_IN_WHICH_TOKEN_INDEXES_ARE_INTRODUCED)) {
        nli = Stream.of(IndexDescriptor.INJECTED_NLI);
    }
    return Stream.concat(LongStream.range(startId, endId).mapToObj(id -> schemaStore.getRecord(id, schemaStore.newRecord(), RecordLoad.LENIENT_ALWAYS, cursorContext)).filter(AbstractBaseRecord::inUse).flatMap(record -> readSchemaRuleThrowingRuntimeException(record, ignoreMalformed, cursorContext)), nli);
}
Also used : KernelVersion(org.neo4j.kernel.KernelVersion) SchemaRule(org.neo4j.internal.schema.SchemaRule) CursorContext(org.neo4j.io.pagecache.context.CursorContext) KernelVersion(org.neo4j.kernel.KernelVersion) Value(org.neo4j.values.storable.Value) ConstraintDescriptor(org.neo4j.internal.schema.ConstraintDescriptor) ArrayList(java.util.ArrayList) Values(org.neo4j.values.storable.Values) IntObjectMap(org.eclipse.collections.api.map.primitive.IntObjectMap) KernelVersionRepository(org.neo4j.storageengine.api.KernelVersionRepository) IntObjectProcedure(org.eclipse.collections.api.block.procedure.primitive.IntObjectProcedure) PropertyBlock(org.neo4j.kernel.impl.store.record.PropertyBlock) AbstractBaseRecord(org.neo4j.kernel.impl.store.record.AbstractBaseRecord) VisibleForTesting(org.neo4j.util.VisibleForTesting) MalformedSchemaRuleException(org.neo4j.internal.kernel.api.exceptions.schema.MalformedSchemaRuleException) SchemaRuleNotFoundException(org.neo4j.internal.kernel.api.exceptions.schema.SchemaRuleNotFoundException) MemoryTracker(org.neo4j.memory.MemoryTracker) PropertyStore(org.neo4j.kernel.impl.store.PropertyStore) Record(org.neo4j.kernel.impl.store.record.Record) LongStream(java.util.stream.LongStream) Iterator(java.util.Iterator) Collection(java.util.Collection) SchemaStore(org.neo4j.kernel.impl.store.SchemaStore) PropertyRecord(org.neo4j.kernel.impl.store.record.PropertyRecord) SchemaRecord(org.neo4j.kernel.impl.store.record.SchemaRecord) DuplicateSchemaRuleException(org.neo4j.internal.kernel.api.exceptions.schema.DuplicateSchemaRuleException) Stream(java.util.stream.Stream) KernelException(org.neo4j.exceptions.KernelException) TokenHolders(org.neo4j.token.TokenHolders) SchemaDescriptor(org.neo4j.internal.schema.SchemaDescriptor) SchemaDescriptorSupplier(org.neo4j.internal.schema.SchemaDescriptorSupplier) IndexDescriptor(org.neo4j.internal.schema.IndexDescriptor) RecordLoad(org.neo4j.kernel.impl.store.record.RecordLoad) IndexRef(org.neo4j.internal.schema.IndexRef) AbstractBaseRecord(org.neo4j.kernel.impl.store.record.AbstractBaseRecord) IndexDescriptor(org.neo4j.internal.schema.IndexDescriptor) VisibleForTesting(org.neo4j.util.VisibleForTesting)

Example 20 with SchemaRule

use of org.neo4j.internal.schema.SchemaRule in project neo4j by neo4j.

the class TransactionRecordState method extractCommands.

@Override
public void extractCommands(Collection<StorageCommand> commands, MemoryTracker memoryTracker) throws TransactionFailureException {
    assert !prepared : "Transaction has already been prepared";
    integrityValidator.validateTransactionStartKnowledge(lastCommittedTxWhenTransactionStarted);
    int noOfCommands = recordChangeSet.changeSize();
    var labelTokenChanges = recordChangeSet.getLabelTokenChanges().changes();
    memoryTracker.allocateHeap(labelTokenChanges.size() * Command.LabelTokenCommand.HEAP_SIZE);
    for (RecordProxy<LabelTokenRecord, Void> record : labelTokenChanges) {
        commands.add(new Command.LabelTokenCommand(commandSerialization, record.getBefore(), record.forReadingLinkage()));
    }
    var relationshipTypeTokenChanges = recordChangeSet.getRelationshipTypeTokenChanges().changes();
    memoryTracker.allocateHeap(relationshipTypeTokenChanges.size() * Command.RelationshipTypeTokenCommand.HEAP_SIZE);
    for (RecordProxy<RelationshipTypeTokenRecord, Void> record : relationshipTypeTokenChanges) {
        commands.add(new Command.RelationshipTypeTokenCommand(commandSerialization, record.getBefore(), record.forReadingLinkage()));
    }
    var propertyKeyTokenChanges = recordChangeSet.getPropertyKeyTokenChanges().changes();
    memoryTracker.allocateHeap(propertyKeyTokenChanges.size() * Command.PropertyKeyTokenCommand.HEAP_SIZE);
    for (RecordProxy<PropertyKeyTokenRecord, Void> record : propertyKeyTokenChanges) {
        commands.add(new Command.PropertyKeyTokenCommand(commandSerialization, record.getBefore(), record.forReadingLinkage()));
    }
    // Collect nodes, relationships, properties
    Command[] nodeCommands = EMPTY_COMMANDS;
    int skippedCommands = 0;
    var nodeChanges = recordChangeSet.getNodeRecords().changes();
    if (!nodeChanges.isEmpty()) {
        memoryTracker.allocateHeap(nodeChanges.size() * Command.NodeCommand.HEAP_SIZE);
        nodeCommands = new Command[nodeChanges.size()];
        int i = 0;
        for (RecordProxy<NodeRecord, Void> change : nodeChanges) {
            NodeRecord record = prepared(change, nodeStore);
            IntegrityValidator.validateNodeRecord(record);
            nodeCommands[i++] = new Command.NodeCommand(commandSerialization, change.getBefore(), record);
        }
        Arrays.sort(nodeCommands, COMMAND_COMPARATOR);
    }
    Command[] relCommands = EMPTY_COMMANDS;
    var relationshipChanges = recordChangeSet.getRelRecords().changes();
    if (!relationshipChanges.isEmpty()) {
        memoryTracker.allocateHeap(relationshipChanges.size() * Command.RelationshipCommand.HEAP_SIZE);
        relCommands = new Command[relationshipChanges.size()];
        int i = 0;
        for (RecordProxy<RelationshipRecord, Void> change : relationshipChanges) {
            relCommands[i++] = new Command.RelationshipCommand(commandSerialization, change.getBefore(), prepared(change, relationshipStore));
        }
        Arrays.sort(relCommands, COMMAND_COMPARATOR);
    }
    Command[] propCommands = EMPTY_COMMANDS;
    var propertyChanges = recordChangeSet.getPropertyRecords().changes();
    if (!propertyChanges.isEmpty()) {
        memoryTracker.allocateHeap(propertyChanges.size() * Command.PropertyCommand.HEAP_SIZE);
        propCommands = new Command[propertyChanges.size()];
        int i = 0;
        for (RecordProxy<PropertyRecord, PrimitiveRecord> change : propertyChanges) {
            propCommands[i++] = new Command.PropertyCommand(commandSerialization, change.getBefore(), prepared(change, propertyStore));
        }
        Arrays.sort(propCommands, COMMAND_COMPARATOR);
    }
    Command[] relGroupCommands = EMPTY_COMMANDS;
    var relationshipGroupChanges = recordChangeSet.getRelGroupRecords().changes();
    if (!relationshipGroupChanges.isEmpty()) {
        memoryTracker.allocateHeap(relationshipGroupChanges.size() * Command.RelationshipGroupCommand.HEAP_SIZE);
        relGroupCommands = new Command[relationshipGroupChanges.size()];
        int i = 0;
        for (RecordProxy<RelationshipGroupRecord, Integer> change : relationshipGroupChanges) {
            if (change.isCreated() && !change.forReadingLinkage().inUse()) {
                /*
                     * This is an edge case that may come up and which we must handle properly. Relationship groups are
                     * not managed by the tx state, since they are created as side effects rather than through
                     * direct calls. However, they differ from say, dynamic records, in that their management can happen
                     * through separate code paths. What we are interested in here is the following scenario.
                     * 0. A node has one less relationship that is required to transition to dense node. The relationships
                     *    it has belong to at least two different types
                     * 1. In the same tx, a relationship is added making the node dense and all the relationships of a type
                     *    are removed from that node. Regardless of the order these operations happen, the creation of the
                     *    relationship (and the transition of the node to dense) will happen first.
                     * 2. A relationship group will be created because of the transition to dense and then deleted because
                     *    all the relationships it would hold are no longer there. This results in a relationship group
                     *    command that appears in the tx as not in use. Depending on the final order of operations, this
                     *    can end up using an id that is higher than the highest id seen so far. This may not be a problem
                     *    for a single instance, but it can result in errors in cases where transactions are applied
                     *    externally, such as backup.
                     *
                     * The way we deal with this issue here is by not issuing a command for that offending record. This is
                     * safe, since the record is not in use and never was, so the high id is not necessary to change and
                     * the store remains consistent.
                     */
                skippedCommands++;
                continue;
            }
            relGroupCommands[i++] = new Command.RelationshipGroupCommand(commandSerialization, change.getBefore(), prepared(change, relationshipGroupStore));
        }
        relGroupCommands = i < relGroupCommands.length ? Arrays.copyOf(relGroupCommands, i) : relGroupCommands;
        Arrays.sort(relGroupCommands, COMMAND_COMPARATOR);
    }
    addFiltered(commands, Mode.CREATE, propCommands, relCommands, relGroupCommands, nodeCommands);
    addFiltered(commands, Mode.UPDATE, propCommands, relCommands, relGroupCommands, nodeCommands);
    addFiltered(commands, Mode.DELETE, relCommands, relGroupCommands, nodeCommands);
    EnumMap<Mode, List<Command>> schemaChangeByMode = new EnumMap<>(Mode.class);
    var schemaRuleChange = recordChangeSet.getSchemaRuleChanges().changes();
    memoryTracker.allocateHeap(schemaRuleChange.size() * Command.SchemaRuleCommand.HEAP_SIZE);
    for (RecordProxy<SchemaRecord, SchemaRule> change : schemaRuleChange) {
        SchemaRecord schemaRecord = change.forReadingLinkage();
        SchemaRule rule = change.getAdditionalData();
        if (schemaRecord.inUse()) {
            integrityValidator.validateSchemaRule(rule);
        }
        Command.SchemaRuleCommand cmd = new Command.SchemaRuleCommand(commandSerialization, change.getBefore(), change.forChangingData(), rule);
        schemaChangeByMode.computeIfAbsent(cmd.getMode(), MODE_TO_ARRAY_LIST).add(cmd);
    }
    commands.addAll(schemaChangeByMode.getOrDefault(Mode.DELETE, Collections.emptyList()));
    commands.addAll(schemaChangeByMode.getOrDefault(Mode.CREATE, Collections.emptyList()));
    commands.addAll(schemaChangeByMode.getOrDefault(Mode.UPDATE, Collections.emptyList()));
    // Add deleted property commands last, so they happen after the schema record changes.
    // This extends the lifetime of property records just past the last moment of use,
    // and prevents reading and deleting of schema records from racing, and making the
    // schema records look malformed.
    addFiltered(commands, Mode.DELETE, propCommands);
    assert commands.size() == noOfCommands - skippedCommands : format("Expected %d final commands, got %d " + "instead, with %d skipped", noOfCommands, commands.size(), skippedCommands);
    if (groupDegreesUpdater.degrees != null) {
        memoryTracker.allocateHeap(groupDegreesUpdater.degrees.size() * Command.GroupDegreeCommand.SHALLOW_SIZE);
        groupDegreesUpdater.degrees.forEachKeyValue((key, delta) -> {
            if (delta.longValue() != 0) {
                long groupId = Command.GroupDegreeCommand.groupIdFromCombinedKey(key);
                RelationshipDirection direction = Command.GroupDegreeCommand.directionFromCombinedKey(key);
                commands.add(new Command.GroupDegreeCommand(groupId, direction, delta.longValue()));
            }
        });
    }
    prepared = true;
}
Also used : RelationshipDirection(org.neo4j.storageengine.api.RelationshipDirection) RelationshipTypeTokenRecord(org.neo4j.kernel.impl.store.record.RelationshipTypeTokenRecord) RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord) SchemaRule(org.neo4j.internal.schema.SchemaRule) PropertyKeyTokenRecord(org.neo4j.kernel.impl.store.record.PropertyKeyTokenRecord) NodeRecord(org.neo4j.kernel.impl.store.record.NodeRecord) PropertyRecord(org.neo4j.kernel.impl.store.record.PropertyRecord) SchemaRecord(org.neo4j.kernel.impl.store.record.SchemaRecord) List(java.util.List) ArrayList(java.util.ArrayList) EnumMap(java.util.EnumMap) LabelTokenRecord(org.neo4j.kernel.impl.store.record.LabelTokenRecord) PrimitiveRecord(org.neo4j.kernel.impl.store.record.PrimitiveRecord) RelationshipGroupRecord(org.neo4j.kernel.impl.store.record.RelationshipGroupRecord) Mode(org.neo4j.internal.recordstorage.Command.Mode) StorageCommand(org.neo4j.storageengine.api.StorageCommand)

Aggregations

SchemaRule (org.neo4j.internal.schema.SchemaRule)29 SchemaRecord (org.neo4j.kernel.impl.store.record.SchemaRecord)12 Test (org.junit.jupiter.api.Test)8 ArrayList (java.util.ArrayList)7 MalformedSchemaRuleException (org.neo4j.internal.kernel.api.exceptions.schema.MalformedSchemaRuleException)5 ConstraintDescriptor (org.neo4j.internal.schema.ConstraintDescriptor)5 TokenHolders (org.neo4j.token.TokenHolders)5 NamedToken (org.neo4j.token.api.NamedToken)5 RepeatedTest (org.junit.jupiter.api.RepeatedTest)4 IndexDescriptor (org.neo4j.internal.schema.IndexDescriptor)4 NeoStores (org.neo4j.kernel.impl.store.NeoStores)4 DynamicRecord (org.neo4j.kernel.impl.store.record.DynamicRecord)3 PropertyRecord (org.neo4j.kernel.impl.store.record.PropertyRecord)3 OptionalLong (java.util.OptionalLong)2 MutableLongSet (org.eclipse.collections.api.set.primitive.MutableLongSet)2 LongHashSet (org.eclipse.collections.impl.set.mutable.primitive.LongHashSet)2 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)2 MethodSource (org.junit.jupiter.params.provider.MethodSource)2 DefaultIdGeneratorFactory (org.neo4j.internal.id.DefaultIdGeneratorFactory)2 SchemaStore (org.neo4j.kernel.impl.store.SchemaStore)2