Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The server sends and the client stores incorrect observed_transaction_data #1212

Open
alco opened this issue Apr 30, 2024 · 2 comments
Open
Labels
bug Something isn't working

Comments

@alco
Copy link
Member

alco commented Apr 30, 2024

When the sync service sends SatOpAdditionalBegin and SatOpAdditionalCommit ops, it includes the so-called move_in_ref in their payload. The client stores additional data refs into its local seenAdditionalData meta row, as a comma-separated list of integeres encoded into a string:

async _applyAdditionalData(data: AdditionalData) {
// Server sends additional data on move-ins and tries to send only data
// the client has never seen from its perspective. Because of this, we're writing this
// data directly, like subscription data
return this._applySubscriptionData(data.changes, this._lsn!, [
this._addSeenAdditionalDataStmt(data.ref.toString()),
])
}

_addSeenAdditionalDataStmt(ref: string): Statement {
const meta = this.opts.metaTable.toString()
const sql = `
INSERT INTO ${meta} (key, value) VALUES ('seenAdditionalData', ?)
ON CONFLICT (key) DO
UPDATE SET value = value || ',' || excluded.value
`
const args = [ref]
return { sql, args }
}

This seenAdditionalData is later fetched, parsed, and included in the SatInStartReplicationReq message's observed_transaction_data field:

const observedTransactionData = await this._getMeta('seenAdditionalData')
const { error } = await this.client.startReplication(
this._lsn,
schemaVersion,
subscriptionIds.length > 0 ? subscriptionIds : undefined,
observedTransactionData
.split(',')
.filter((x) => x !== '')
.map((x) => Long.fromString(x))
)

request = SatInStartReplicationReq.fromPartial({
lsn,
subscriptionIds,
observedTransactionData,
})

When the sync service processes that message, it expects the observed_transaction_data field to contain a list of transaction IDs, though:

including_data: observed_txn_data,

txids = Keyword.fetch!(opts, :including_data)

@alco alco added the bug Something isn't working label Apr 30, 2024
Copy link

linear bot commented Apr 30, 2024

@alco
Copy link
Member Author

alco commented Apr 30, 2024

The same problem is present in the SatOpLogAck message. The protocol definition for this message defines the additional_data_source_ids field:

/** Transaction IDs for which additional data was received immediately after this transaction */
repeated uint64 additional_data_source_ids = 5;

However, on the client, move_in_refs from SatOpAdditionalCommit messages are used to popoulate this field:

if (op.additionalCommit) {
if (replication.incomplete !== 'additionalData')
throw new Error(
'Unexpected additionalCommit message while not waiting for additionalData'
)
const ref = op.additionalCommit!.ref
// TODO: We need to include these in the ACKs as well
this.emitter.enqueueEmit(
'additionalData',
replication.additionalData[lastDataIdx],
() => {
this.inbound.seenAdditionalDataSinceLastTx.dataRefs.push(ref)
this.maybeSendAck('additionalData')

additionalDataSourceIds:
this.inbound.seenAdditionalDataSinceLastTx.dataRefs,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant