Skip to content

Conversation

@XaBbl4
Copy link
Contributor

@XaBbl4 XaBbl4 commented Jan 14, 2026

Add a new method to the replication API to ensure generators are always replicated (both on commit and rollback).

Previously, if execute:

select gen_id(t_gen, 1) from rdb$database;
rollback;

The generator on the master and replica stored different values.

If decide to backport this to 5.0, might consider:

version: // 5.0 => 5.0.4
    void flushSequences(Status status);

version: // 5.0.4 => 6.0 Alpha1
    void setSequence2(...);

@dyemanov
Copy link
Member

In practice this PR avoids inconsistent replica when applications use an attachment-level sequence cache (IDs are prefetched and distributed among rows being inserted). This does not allow sharing the cached IDs among different attachments, but so far we haven't seen such an use case.

Custom replication plugins are free to choose between synchronous or delayed (conditional or unconditional) sequence replication.

if (replicator)
{
FbLocalStatus status;
replicator->flushSequences(&status);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no replicator on commit/rollback, it means that setSequence was never called and there is nothing to flush. Replication plugin already has an opportunity to push changed sequences to replica on rollback, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no replicator on commit/rollback, it means that setSequence was never called and there is nothing to flush.

Yes, it can be change to attachment->att_replicator

Replication plugin already has an opportunity to push changed sequences to replica on rollback, right?

Previously, when a transaction was rollback, sequences were not transferred to the replica, only during the first commit in the current attachment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, when a transaction was rollback, sequences were not transferred to the replica, only during the first commit in the current attachment.

But it was the choice of the standard replication plugin (only). Why API changes are required if you can limit changes to plugin code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, when a transaction was rollback, sequences were not transferred to the replica, only during the first commit in the current attachment.

But it was the choice of the standard replication plugin (only). Why API changes are required if you can limit changes to plugin code?

Current API does not allow to replicate generators changed in read-only (de-facto) transactions, because the transaction replicator object is not created without I/U/D ops and thus there's no commit/rollback event at the end. Thus a need for the new API hook.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it was the choice of the standard replication plugin (only). Why API changes are required if you can limit changes to plugin code?

This is an optimization of the current plugin implementation, where generator values ​​are first cached and only transmitted to the replica when commit, for example:

select gen_id(t_gen, 1) from rdb$database;
select gen_id(t_gen, 1) from rdb$database;
select gen_id(t_gen, 1) from rdb$database;
commit;

As a result, the generator will be transmitted to the replica with a value of +3, instead of three times for each operation.

Furthermore, there are situations where the generator value changes without an actual transaction, as in the example with select gen_id. In this case, ReplicatedTransaction doesn't yet exist and commit/rollback isn't called. This is why a new method call was added to Publisher.cpp.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No select can be performed outside of transaction thus no REPL_gen_id can be called without transaction. IMHO, it is enough to change call to getReplicator inside of REPL_gen_id to let standard plugin work. Cleanup of attachment-level replicator is optional.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do I care about is creation of plugin instance for single call that may have nothing to work with. Direct usage of att_replicator can solve it though, as you suggested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No select can be performed outside of transaction thus no REPL_gen_id can be called without transaction. IMHO, it is enough to change call to getReplicator inside of REPL_gen_id to let standard plugin work. Cleanup of attachment-level replicator is optional.

setSequence() is a method of IReplicatedSession, not IReplicatedTransaction. Or do you mean just creating a dummy instance of IReplicatedTransaction together with calling IReplicatedSession::setSequence()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setSequence() is a method of IReplicatedSession, not IReplicatedTransaction.

Oops, I forgot that.

Or do you mean just creating a dummy instance of IReplicatedTransaction together with calling IReplicatedSession::setSequence()?

Yes. BTW, moving of setSequence into ReplTransaction is not an option, right?..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants