Add a write correlator to group all attributes of a single write across TRoE and MongoDB#1965
Add a write correlator to group all attributes of a single write across TRoE and MongoDB#1965cfreyfh wants to merge 24 commits into
Conversation
Every write now carries a correlator that identifies the write operation,
taken from the new "NGSILD-Correlator" request header (falling back to
"Fiware-Correlator"); if neither is present one is generated as
"urn:ngsi-ld:correlator:<uuid>". Any "; cbnotif=N" suffix is stripped.
The correlator is resolved once per request (correlatorGet) and stored:
- on the entity in MongoDB ("lastCorrelator"), on every write path
(full rebuild via dbModelFromApiEntity, and the partial $set updates
for PATCH entity, add/replace/delete attribute);
- on every TRoE row (entities, attributes, subAttributes) in a new
"correlator" column.
This gives a guaranteed-unique key (for generated correlators) linking all
attributes of one write - something instanceId (per attribute), observedAt
and ts cannot provide. As the correlator is client-influenced, it is stripped
of quotes and SQL-escaped before being embedded in the TRoE INSERTs.
uuid is added to ftClient's link libraries since the correlator resolver
(which uses uuidGenerate) is now reachable from the entity write paths.
https://claude.ai/code/session_01BBQ1eEcF8F3EFEDrUhetpw
pgCommands only checked for a NULL PGresult, but PQexec returns a non-NULL result with an error status when the statement itself fails (e.g. a missing column on an un-migrated schema). Such failures were silently dropped: no log, the transaction aborted and COMMIT acted as ROLLBACK, so the temporal write was lost without a trace. Check PQresultStatus explicitly and, on error, log the status, the Postgres error message and the offending SQL, then roll back. https://claude.ai/code/session_01BBQ1eEcF8F3EFEDrUhetpw
Functional test (deterministic via client-supplied NGSILD-Correlator): all attributes of a write share the correlator in TRoE; entities, attributes and subAttributes share it; two writes get two correlators; the entity stores it in MongoDB lastCorrelator; the grouping query returns the co-written attributes; and a header-less write gets a generated urn:ngsi-ld:correlator: value. https://claude.ai/code/session_01BBQ1eEcF8F3EFEDrUhetpw
Add write correlator stored on the entity and TRoE rows
Sync to Main Repo
Covers all four write paths (create, append, patch, delete) plus the auto-generated correlator, asserting the entity's MongoDB 'lastCorrelator' field after each write. Runs without TRoE/Postgres.
Add functional test verifying the write correlator is stored in MongoDB
mongoCmd2 prints 'MongoDB shell version', 'connecting to:', 'MongoDB server version:' and a trailing 'bye' around the queried value. Add these (as REGEX) to the expected output of both correlator tests so they pass.
Match mongoCmd2 shell wrapper lines in correlator test expectations
The 201 response from orionCurl emits a trailing blank line, so there are three blank lines (not two) before the postgresCmd 'prefix' output.
Fix blank-line count before TRoE step 08 prefix output
|
CLA Assistant Lite bot: I have read the CLA Document and I hereby sign the CLA 2 out of 3 committers have signed the CLA. |
Claude/gracious turing 2xh p6
The 'lastCorrelator' entity field already existed (NGSIv2 compat) and was empty in NGSI-LD. Storing a generated correlator there changed it to a non-deterministic UUID, breaking ~140 functional tests that dump the entity and expect an empty lastCorrelator. Fix: only mirror the correlator to MongoDB when the client actually supplied one (NGSILD-Correlator / Fiware-Correlator). Generated correlators stay only on the TRoE rows, so the snapshot grouping is unchanged and existing NGSI-LD behaviour is preserved when no correlator header is sent. - correlatorClientProvided() helper - gate the create path (dbModelFromApiEntity) and the four mongoc update paths - update the MongoDB functional test + docs for the no-header case
Mirror correlator to MongoDB lastCorrelator only when client-supplied
Mirror correlator to MongoDB lastCorrelator only when client-supplied
Merge 2b4034c accidentally dropped 6 lines from ngsild_write_correlator_mongodb.test: the '===' underlines of steps 09/10 and the MongoDB shell-version wrapper + 'true' of step 10. This restores them so the test's expected output matches the broker output again.
Restore test lines dropped by a bad merge resolution
|
One very important detail. |
kzangeli
left a comment
There was a problem hiding this comment.
So, all tests pass, all good.
BUT, as I said in a comment, we need to merge the DB model. Any other deployment out there will fail (if they use TRoE) probably at startup once this modification is in, so, we need an automatic "merge" (whatever it's called) of the DB layout.
Can't ship this PR without it.
The broker now versions each TRoE database (a 'metadata' table with a 'schemaVersion' row) and applies pending, idempotent migration steps on startup and for every tenant database - so existing databases are upgraded automatically when the layout changes, with no manual/external step. - pgSchemaMigrate(): versioned, idempotent migration registry guarded by a Postgres advisory lock (safe under concurrent broker instances) - step v1->v2 adds the write 'correlator' column (+ index) to the three tables - hooked into pgDatabasePrepare (runs after table creation, per database) - functional test simulating an old database that gets migrated on restart - docs: new 'Automatic schema migration on startup' section To add a future layout change: bump PG_SCHEMA_VERSION and append a step.
|
What do you think about this? automatic, versioned schema-migration mechanism for the TRoE PostgreSQL database. On startup (and for every tenant database), the broker detects an outdated DB layout and migrates it automatically — no external tooling or manual step required. This is built as a general mechanism (not a one-off for the How it works
Freshly created databases already carry the latest layout, so the steps run as no-ops on them; only pre-existing databases are actually upgraded. |
|
That's perfect. Exactly what I had in mind |
Auto-migrate the TRoE Postgres schema on startup
Auto-migrate the TRoE Postgres schema on startup
|




Problem
TRoE rows have no key that links all attributes written by a single operation
("entity snapshot"):
instanceIdis unique per attributeobservedAtis a business timestamp, sometimes NULL and not uniquets(request time) is shared within a request but not guaranteed uniqueSo a query like "give me all attributes written together with
OriginSource = OPC_Server_01" cannot be answered reliably.Solution
Introduce a write correlator: a single value per write operation, shared by
every row that write produces.
NGSILD-Correlatorrequest header.(
urn:ngsi-ld:correlator:<uuid>), so the grouping key always exists.correlatorGet()) and then writteninto every row of that write.
Where it is stored
correlatorcolumn onentities,attributesand
subAttributes. All rows of one write share the same value.the
lastCorrelatorfield. It is updated by every write path: entity create,attribute append, attribute patch/replace and attribute delete.
This provides a guaranteed-unique key grouping all attributes of one snapshot: