Search in sources :

Example 6 with StorageCommand

use of org.neo4j.storageengine.api.StorageCommand in project neo4j by neo4j.

the class RaftContentByteBufferMarshalTest method shouldSerializeTransactionRepresentation.

@Test
public void shouldSerializeTransactionRepresentation() throws Exception {
    // given
    CoreReplicatedContentMarshal serializer = new CoreReplicatedContentMarshal();
    Collection<StorageCommand> commands = new ArrayList<>();
    IndexCommand.AddNodeCommand addNodeCommand = new IndexCommand.AddNodeCommand();
    addNodeCommand.init(0, 0, 0, 0);
    commands.add(addNodeCommand);
    byte[] extraHeader = new byte[0];
    PhysicalTransactionRepresentation txIn = new PhysicalTransactionRepresentation(commands);
    txIn.setHeader(extraHeader, -1, -1, 0, 0, 0, 0);
    ReplicatedTransaction in = ReplicatedTransactionFactory.createImmutableReplicatedTransaction(txIn);
    // when
    ByteBuf buf = Unpooled.buffer();
    serializer.marshal(in, new NetworkFlushableByteBuf(buf));
    ReplicatedTransaction out = (ReplicatedTransaction) serializer.unmarshal(new NetworkReadableClosableChannelNetty4(buf));
    TransactionRepresentation txOut = ReplicatedTransactionFactory.extractTransactionRepresentation(out, extraHeader);
    // then
    assertEquals(in, out);
    assertEquals(txIn, txOut);
}
Also used : NetworkFlushableByteBuf(org.neo4j.causalclustering.messaging.NetworkFlushableByteBuf) ReplicatedTransaction(org.neo4j.causalclustering.core.state.machines.tx.ReplicatedTransaction) StorageCommand(org.neo4j.storageengine.api.StorageCommand) TransactionRepresentation(org.neo4j.kernel.impl.transaction.TransactionRepresentation) PhysicalTransactionRepresentation(org.neo4j.kernel.impl.transaction.log.PhysicalTransactionRepresentation) ArrayList(java.util.ArrayList) ByteBuf(io.netty.buffer.ByteBuf) NetworkFlushableByteBuf(org.neo4j.causalclustering.messaging.NetworkFlushableByteBuf) NetworkReadableClosableChannelNetty4(org.neo4j.causalclustering.messaging.NetworkReadableClosableChannelNetty4) CoreReplicatedContentMarshal(org.neo4j.causalclustering.messaging.CoreReplicatedContentMarshal) IndexCommand(org.neo4j.kernel.impl.index.IndexCommand) PhysicalTransactionRepresentation(org.neo4j.kernel.impl.transaction.log.PhysicalTransactionRepresentation) Test(org.junit.Test)

Example 7 with StorageCommand

use of org.neo4j.storageengine.api.StorageCommand in project neo4j by neo4j.

the class TransactionRecordState method extractCommands.

@Override
public void extractCommands(Collection<StorageCommand> commands) throws TransactionFailureException {
    assert !prepared : "Transaction has already been prepared";
    integrityValidator.validateTransactionStartKnowledge(lastCommittedTxWhenTransactionStarted);
    int noOfCommands = recordChangeSet.changeSize() + (neoStoreRecord != null ? neoStoreRecord.changeSize() : 0);
    for (RecordProxy<Integer, LabelTokenRecord, Void> record : recordChangeSet.getLabelTokenChanges().changes()) {
        commands.add(new Command.LabelTokenCommand(record.getBefore(), record.forReadingLinkage()));
    }
    for (RecordProxy<Integer, RelationshipTypeTokenRecord, Void> record : recordChangeSet.getRelationshipTypeTokenChanges().changes()) {
        commands.add(new Command.RelationshipTypeTokenCommand(record.getBefore(), record.forReadingLinkage()));
    }
    for (RecordProxy<Integer, PropertyKeyTokenRecord, Void> record : recordChangeSet.getPropertyKeyTokenChanges().changes()) {
        commands.add(new Command.PropertyKeyTokenCommand(record.getBefore(), record.forReadingLinkage()));
    }
    // Collect nodes, relationships, properties
    Command[] nodeCommands = EMPTY_COMMANDS;
    int skippedCommands = 0;
    if (recordChangeSet.getNodeRecords().changeSize() > 0) {
        nodeCommands = new Command[recordChangeSet.getNodeRecords().changeSize()];
        int i = 0;
        for (RecordProxy<Long, NodeRecord, Void> change : recordChangeSet.getNodeRecords().changes()) {
            NodeRecord record = prepared(change, nodeStore);
            integrityValidator.validateNodeRecord(record);
            nodeCommands[i++] = new Command.NodeCommand(change.getBefore(), record);
        }
        Arrays.sort(nodeCommands, COMMAND_SORTER);
    }
    Command[] relCommands = EMPTY_COMMANDS;
    if (recordChangeSet.getRelRecords().changeSize() > 0) {
        relCommands = new Command[recordChangeSet.getRelRecords().changeSize()];
        int i = 0;
        for (RecordProxy<Long, RelationshipRecord, Void> change : recordChangeSet.getRelRecords().changes()) {
            relCommands[i++] = new Command.RelationshipCommand(change.getBefore(), prepared(change, relationshipStore));
        }
        Arrays.sort(relCommands, COMMAND_SORTER);
    }
    Command[] propCommands = EMPTY_COMMANDS;
    if (recordChangeSet.getPropertyRecords().changeSize() > 0) {
        propCommands = new Command[recordChangeSet.getPropertyRecords().changeSize()];
        int i = 0;
        for (RecordProxy<Long, PropertyRecord, PrimitiveRecord> change : recordChangeSet.getPropertyRecords().changes()) {
            propCommands[i++] = new Command.PropertyCommand(change.getBefore(), prepared(change, propertyStore));
        }
        Arrays.sort(propCommands, COMMAND_SORTER);
    }
    Command[] relGroupCommands = EMPTY_COMMANDS;
    if (recordChangeSet.getRelGroupRecords().changeSize() > 0) {
        relGroupCommands = new Command[recordChangeSet.getRelGroupRecords().changeSize()];
        int i = 0;
        for (RecordProxy<Long, RelationshipGroupRecord, Integer> change : recordChangeSet.getRelGroupRecords().changes()) {
            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 or HA.
                     *
                     * 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(change.getBefore(), prepared(change, relationshipGroupStore));
        }
        relGroupCommands = i < relGroupCommands.length ? Arrays.copyOf(relGroupCommands, i) : relGroupCommands;
        Arrays.sort(relGroupCommands, COMMAND_SORTER);
    }
    addFiltered(commands, Mode.CREATE, propCommands, relCommands, relGroupCommands, nodeCommands);
    addFiltered(commands, Mode.UPDATE, propCommands, relCommands, relGroupCommands, nodeCommands);
    addFiltered(commands, Mode.DELETE, propCommands, relCommands, relGroupCommands, nodeCommands);
    if (neoStoreRecord != null) {
        for (RecordProxy<Long, NeoStoreRecord, Void> change : neoStoreRecord.changes()) {
            commands.add(new Command.NeoStoreCommand(change.getBefore(), change.forReadingData()));
        }
    }
    for (RecordProxy<Long, SchemaRecord, SchemaRule> change : recordChangeSet.getSchemaRuleChanges().changes()) {
        integrityValidator.validateSchemaRule(change.getAdditionalData());
        commands.add(new Command.SchemaRuleCommand(change.getBefore(), change.forChangingData(), change.getAdditionalData()));
    }
    assert commands.size() == noOfCommands - skippedCommands : format("Expected %d final commands, got %d " + "instead, with %d skipped", noOfCommands, commands.size(), skippedCommands);
    prepared = true;
}
Also used : RelationshipTypeTokenRecord(org.neo4j.kernel.impl.store.record.RelationshipTypeTokenRecord) RelationshipRecord(org.neo4j.kernel.impl.store.record.RelationshipRecord) SchemaRule(org.neo4j.storageengine.api.schema.SchemaRule) PropertyKeyTokenRecord(org.neo4j.kernel.impl.store.record.PropertyKeyTokenRecord) NodeRecord(org.neo4j.kernel.impl.store.record.NodeRecord) NeoStoreRecord(org.neo4j.kernel.impl.store.record.NeoStoreRecord) PropertyRecord(org.neo4j.kernel.impl.store.record.PropertyRecord) SchemaRecord(org.neo4j.kernel.impl.store.record.SchemaRecord) LabelTokenRecord(org.neo4j.kernel.impl.store.record.LabelTokenRecord) PrimitiveRecord(org.neo4j.kernel.impl.store.record.PrimitiveRecord) RelationshipGroupRecord(org.neo4j.kernel.impl.store.record.RelationshipGroupRecord) StorageCommand(org.neo4j.storageengine.api.StorageCommand) Command(org.neo4j.kernel.impl.transaction.command.Command)

Example 8 with StorageCommand

use of org.neo4j.storageengine.api.StorageCommand in project neo4j by neo4j.

the class KernelTransactionImplementation method commit.

private long commit() throws TransactionFailureException {
    boolean success = false;
    long txId = READ_ONLY;
    try (CommitEvent commitEvent = transactionEvent.beginCommitEvent()) {
        // Trigger transaction "before" hooks.
        if (hasDataChanges()) {
            try {
                hooksState = hooks.beforeCommit(txState, this, storageEngine.storeReadLayer(), storageStatement);
                if (hooksState != null && hooksState.failed()) {
                    TransactionHookException cause = hooksState.failure();
                    throw new TransactionFailureException(Status.Transaction.TransactionHookFailed, cause, "");
                }
            } finally {
                beforeHookInvoked = true;
            }
        }
        // Convert changes into commands and commit
        if (hasChanges()) {
            // grab all optimistic locks now, locks can't be deferred any further
            statementLocks.prepareForCommit();
            // use pessimistic locks for the rest of the commit process, locks can't be deferred any further
            Locks.Client commitLocks = statementLocks.pessimistic();
            // Gather up commands from the various sources
            Collection<StorageCommand> extractedCommands = new ArrayList<>();
            storageEngine.createCommands(extractedCommands, txState, storageStatement, commitLocks, lastTransactionIdWhenStarted);
            if (hasLegacyIndexChanges()) {
                legacyIndexTransactionState.extractCommands(extractedCommands);
            }
            /* Here's the deal: we track a quick-to-access hasChanges in transaction state which is true
                 * if there are any changes imposed by this transaction. Some changes made inside a transaction undo
                 * previously made changes in that same transaction, and so at some point a transaction may have
                 * changes and at another point, after more changes seemingly,
                 * the transaction may not have any changes.
                 * However, to track that "undoing" of the changes is a bit tedious, intrusive and hard to maintain
                 * and get right.... So to really make sure the transaction has changes we re-check by looking if we
                 * have produced any commands to add to the logical log.
                 */
            if (!extractedCommands.isEmpty()) {
                // Finish up the whole transaction representation
                PhysicalTransactionRepresentation transactionRepresentation = new PhysicalTransactionRepresentation(extractedCommands);
                TransactionHeaderInformation headerInformation = headerInformationFactory.create();
                long timeCommitted = clock.millis();
                transactionRepresentation.setHeader(headerInformation.getAdditionalHeader(), headerInformation.getMasterId(), headerInformation.getAuthorId(), startTimeMillis, lastTransactionIdWhenStarted, timeCommitted, commitLocks.getLockSessionId());
                // Commit the transaction
                success = true;
                TransactionToApply batch = new TransactionToApply(transactionRepresentation);
                txId = transactionId = commitProcess.commit(batch, commitEvent, INTERNAL);
                commitTime = timeCommitted;
            }
        }
        success = true;
        return txId;
    } catch (ConstraintValidationException | CreateConstraintFailureException e) {
        throw new ConstraintViolationTransactionFailureException(e.getUserMessage(new KeyReadTokenNameLookup(currentTransactionOperations.keyReadOperations())), e);
    } finally {
        if (!success) {
            rollback();
        } else {
            afterCommit(txId);
        }
    }
}
Also used : ConstraintViolationTransactionFailureException(org.neo4j.kernel.api.exceptions.ConstraintViolationTransactionFailureException) KeyReadTokenNameLookup(org.neo4j.kernel.api.KeyReadTokenNameLookup) StorageCommand(org.neo4j.storageengine.api.StorageCommand) ConstraintValidationException(org.neo4j.kernel.api.exceptions.schema.ConstraintValidationException) ArrayList(java.util.ArrayList) Locks(org.neo4j.kernel.impl.locking.Locks) StatementLocks(org.neo4j.kernel.impl.locking.StatementLocks) TransactionHookException(org.neo4j.kernel.api.exceptions.TransactionHookException) TransactionFailureException(org.neo4j.kernel.api.exceptions.TransactionFailureException) ConstraintViolationTransactionFailureException(org.neo4j.kernel.api.exceptions.ConstraintViolationTransactionFailureException) CommitEvent(org.neo4j.kernel.impl.transaction.tracing.CommitEvent) PhysicalTransactionRepresentation(org.neo4j.kernel.impl.transaction.log.PhysicalTransactionRepresentation) CreateConstraintFailureException(org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException)

Example 9 with StorageCommand

use of org.neo4j.storageengine.api.StorageCommand in project neo4j by neo4j.

the class BatchingTransactionAppenderTest method singleCreateNodeCommand.

private Collection<StorageCommand> singleCreateNodeCommand(long id) {
    Collection<StorageCommand> commands = new ArrayList<>();
    NodeRecord before = new NodeRecord(id);
    NodeRecord after = new NodeRecord(id);
    after.setInUse(true);
    commands.add(new NodeCommand(before, after));
    return commands;
}
Also used : NodeRecord(org.neo4j.kernel.impl.store.record.NodeRecord) StorageCommand(org.neo4j.storageengine.api.StorageCommand) ArrayList(java.util.ArrayList) NodeCommand(org.neo4j.kernel.impl.transaction.command.Command.NodeCommand)

Example 10 with StorageCommand

use of org.neo4j.storageengine.api.StorageCommand in project neo4j by neo4j.

the class PhysicalLogicalTransactionStoreTest method singleCreateNodeCommand.

private Collection<StorageCommand> singleCreateNodeCommand() {
    Collection<StorageCommand> commands = new ArrayList<>();
    long id = 0;
    NodeRecord before = new NodeRecord(id);
    NodeRecord after = new NodeRecord(id);
    after.setInUse(true);
    commands.add(new Command.NodeCommand(before, after));
    return commands;
}
Also used : NodeRecord(org.neo4j.kernel.impl.store.record.NodeRecord) StorageCommand(org.neo4j.storageengine.api.StorageCommand) Command(org.neo4j.kernel.impl.transaction.command.Command) StorageCommand(org.neo4j.storageengine.api.StorageCommand) ArrayList(java.util.ArrayList)

Aggregations

StorageCommand (org.neo4j.storageengine.api.StorageCommand)77 ArrayList (java.util.ArrayList)39 Test (org.junit.jupiter.api.Test)34 CommandReader (org.neo4j.storageengine.api.CommandReader)23 InMemoryClosableChannel (org.neo4j.kernel.impl.transaction.log.InMemoryClosableChannel)22 RepeatedTest (org.junit.jupiter.api.RepeatedTest)19 PhysicalTransactionRepresentation (org.neo4j.kernel.impl.transaction.log.PhysicalTransactionRepresentation)14 LongArrayList (org.eclipse.collections.impl.list.mutable.primitive.LongArrayList)10 Test (org.junit.Test)10 NodeRecord (org.neo4j.kernel.impl.store.record.NodeRecord)9 RelationshipGroupRecord (org.neo4j.kernel.impl.store.record.RelationshipGroupRecord)9 PropertyRecord (org.neo4j.kernel.impl.store.record.PropertyRecord)8 Command (org.neo4j.kernel.impl.transaction.command.Command)7 NodeCommand (org.neo4j.kernel.impl.transaction.command.Command.NodeCommand)7 LogEntryCommand (org.neo4j.kernel.impl.transaction.log.entry.LogEntryCommand)7 SchemaRuleCommand (org.neo4j.internal.recordstorage.Command.SchemaRuleCommand)6 NeoStores (org.neo4j.kernel.impl.store.NeoStores)6 IOException (java.io.IOException)5 PropertyCommand (org.neo4j.internal.recordstorage.Command.PropertyCommand)5 IndexDescriptor (org.neo4j.internal.schema.IndexDescriptor)5