public override bool VisitSchemaRuleCommand(Command.SchemaRuleCommand command)
 {
     // This shows that this transaction is a schema transaction, so it cannot have commands
     // updating any counts anyway. Therefore the counts updater is closed right away.
     // This also breaks an otherwise deadlocking scenario between check pointer, this applier
     // and an index population thread wanting to apply index sampling to the counts store.
     Debug.Assert(!_haveUpdates, "Assumed that a schema transaction wouldn't also contain data commands affecting " +);
     "counts store, but was proven wrong with this transaction";
     CloseCountsUpdaterIfOpen();
     return(false);
 }
Exemplo n.º 2
0
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void extractCommands(java.util.Collection<org.neo4j.storageengine.api.StorageCommand> commands) throws org.neo4j.internal.kernel.api.exceptions.TransactionFailureException
        public override void ExtractCommands(ICollection <StorageCommand> commands)
        {
            Debug.Assert(!_prepared, "Transaction has already been prepared");

            _integrityValidator.validateTransactionStartKnowledge(_lastCommittedTxWhenTransactionStarted);

            int noOfCommands = _recordChangeSet.changeSize() + (_neoStoreRecord != null ? _neoStoreRecord.changeSize() : 0);

            foreach (RecordAccess_RecordProxy <LabelTokenRecord, Void> record in _recordChangeSet.LabelTokenChanges.changes())
            {
                commands.Add(new Command.LabelTokenCommand(record.Before, record.ForReadingLinkage()));
            }
            foreach (RecordAccess_RecordProxy <RelationshipTypeTokenRecord, Void> record in _recordChangeSet.RelationshipTypeTokenChanges.changes())
            {
                commands.Add(new Command.RelationshipTypeTokenCommand(record.Before, record.ForReadingLinkage()));
            }
            foreach (RecordAccess_RecordProxy <PropertyKeyTokenRecord, Void> record in _recordChangeSet.PropertyKeyTokenChanges.changes())
            {
                commands.Add(new Command.PropertyKeyTokenCommand(record.Before, record.ForReadingLinkage()));
            }

            // Collect nodes, relationships, properties
            Command[] nodeCommands    = _emptyCommands;
            int       skippedCommands = 0;

            if (_recordChangeSet.NodeRecords.changeSize() > 0)
            {
                nodeCommands = new Command[_recordChangeSet.NodeRecords.changeSize()];
                int i = 0;
                foreach (RecordAccess_RecordProxy <NodeRecord, Void> change in _recordChangeSet.NodeRecords.changes())
                {
                    NodeRecord record = Prepared(change, _nodeStore);
                    _integrityValidator.validateNodeRecord(record);
                    nodeCommands[i++] = new Command.NodeCommand(change.Before, record);
                }
                Arrays.sort(nodeCommands, _commandComparator);
            }

            Command[] relCommands = _emptyCommands;
            if (_recordChangeSet.RelRecords.changeSize() > 0)
            {
                relCommands = new Command[_recordChangeSet.RelRecords.changeSize()];
                int i = 0;
                foreach (RecordAccess_RecordProxy <RelationshipRecord, Void> change in _recordChangeSet.RelRecords.changes())
                {
                    relCommands[i++] = new Command.RelationshipCommand(change.Before, Prepared(change, _relationshipStore));
                }
                Arrays.sort(relCommands, _commandComparator);
            }

            Command[] propCommands = _emptyCommands;
            if (_recordChangeSet.PropertyRecords.changeSize() > 0)
            {
                propCommands = new Command[_recordChangeSet.PropertyRecords.changeSize()];
                int i = 0;
                foreach (RecordAccess_RecordProxy <PropertyRecord, PrimitiveRecord> change in _recordChangeSet.PropertyRecords.changes())
                {
                    propCommands[i++] = new Command.PropertyCommand(change.Before, Prepared(change, _propertyStore));
                }
                Arrays.sort(propCommands, _commandComparator);
            }

            Command[] relGroupCommands = _emptyCommands;
            if (_recordChangeSet.RelGroupRecords.changeSize() > 0)
            {
                relGroupCommands = new Command[_recordChangeSet.RelGroupRecords.changeSize()];
                int i = 0;
                foreach (RecordAccess_RecordProxy <RelationshipGroupRecord, int> change in _recordChangeSet.RelGroupRecords.changes())
                {
                    if (change.Created && !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.Before, Prepared(change, _relationshipGroupStore));
                }
                relGroupCommands = i < relGroupCommands.Length ? Arrays.copyOf(relGroupCommands, i) : relGroupCommands;
                Arrays.sort(relGroupCommands, _commandComparator);
            }

            AddFiltered(commands, Command.Mode.CREATE, propCommands, relCommands, relGroupCommands, nodeCommands);
            AddFiltered(commands, Command.Mode.UPDATE, propCommands, relCommands, relGroupCommands, nodeCommands);
            AddFiltered(commands, Command.Mode.DELETE, propCommands, relCommands, relGroupCommands, nodeCommands);

            if (_neoStoreRecord != null)
            {
                foreach (RecordAccess_RecordProxy <NeoStoreRecord, Void> change in _neoStoreRecord.changes())
                {
                    commands.Add(new Command.NeoStoreCommand(change.Before, change.ForReadingData()));
                }
            }
            //noinspection unchecked
            IList <Command>[] schemaChangeByMode = new System.Collections.IList[Command.Mode.values().length];
            for (int i = 0; i < schemaChangeByMode.Length; i++)
            {
                schemaChangeByMode[i] = new List <Command>();
            }
            foreach (RecordAccess_RecordProxy <SchemaRecord, SchemaRule> change in _recordChangeSet.SchemaRuleChanges.changes())
            {
                if (change.ForReadingLinkage().inUse())
                {
                    _integrityValidator.validateSchemaRule(change.AdditionalData);
                }
                Command.SchemaRuleCommand cmd = new Command.SchemaRuleCommand(change.Before, change.ForChangingData(), change.AdditionalData);
                schemaChangeByMode[cmd.Mode.ordinal()].Add(cmd);
            }
            commands.addAll(schemaChangeByMode[Command.Mode.DELETE.ordinal()]);
            commands.addAll(schemaChangeByMode[Command.Mode.CREATE.ordinal()]);
            commands.addAll(schemaChangeByMode[Command.Mode.UPDATE.ordinal()]);
            Debug.Assert(commands.Count == noOfCommands - skippedCommands, format("Expected %d final commands, got %d " + "instead, with %d skipped", noOfCommands, commands.Count, skippedCommands));

            _prepared = true;
        }