On this page· 5
Change records
- file format 6
- Rust SDK 1.0 preview
Plain words: change notes
Goal: read a log of changes, and know the rules a log follows.
A change record, kind mut, states one change to one record: put this record, or delete that one. A pack that holds only mut records is a change log.
Note
The Rust SDK reads mut records as opaque records. Applications build, check and apply the log themselves, as below.
One change record, as written:
{"k":"mut","v":1,"id":"00000000000000000001","gen":7,"lsn":1,"op":"put_record","rk":"ent","rid":"e1","rec":{"k":"ent","v":1,"id":"e1","t":"Person","name":"Anna","stub":false}}
| Member | Type | Rule |
|---|---|---|
k | string | mut |
v | integer | 1 |
id | string | the sequence number in decimal, padded with zeros to 20 digits. Never an entity id. |
gen | u64 | the generation: which run of the log the change belongs to |
lsn | u64 | the log sequence number: the change's position in its generation |
op | string | put_record or delete_record; other operation names are reserved for future use |
rk | string | the kind of the record being changed; required for put_record and delete_record |
rid | string | the primary id of the record being changed; required for put_record and delete_record |
rec | object | for put_record only: the whole new record, whose kind and primary id equal rk and rid. delete_record carries no rec. |
Members are written in that order, then any others.
- One file holds one generation. Sequence numbers restart when the generation changes.
- Within a generation, sequence numbers have no gaps, and changes apply in sequence order. The records sort into that order on their own:
mutsorts after every typed kind, byid, and a 20-digit padded number sorts as text in number order. - There is no partial update.
put_recordcarries the complete record. rkandridname the changed record;idnever does. Ifidheld an entity id, a put and a delete of one record would share a key.- A log is ordered, not a set. A producer does not combine two logs with merge.
To apply a log, check each step:
- 1. Open the pack with verification on.
- 2. Check that every record has kind
mutand the members above, and thatidequalslsnpadded to 20 digits. - 3. Check that every record has the same
gen, and that the firstlsnfollows the last change already applied. - 4. Apply the changes in order:
put_recordinserts or replaces the recordrk,ridwithrec;delete_recordremoves it. - 5. Refuse a record with any other
op.
Note
A line with "k":"mut" is not proof of a valid change record. Because the kind is opaque, any JSON object under that name opens. Check the members before acting on one.
The Rust SDK returns mut records as ordinary records. kind() returns mut, and to_json_value() gives the members.
lsn | op | rk | rid |
|---|---|---|---|
| 1 | put_record | ent | e1 |
| 2 | delete_record | ent | e2 |
| 3 | put_record | ent | e3 |
A writer emits records in sort-key order, so the three come out in sequence order whatever order they were given in: all three have kind mut, and their ids are padded numbers that sort as text in number order. Spec §5.3
Merge treats a mut record like any record that is not ent: two logs that each hold a change numbered 1 share one dedup key. Under latest the second log's change is kept; under every other strategy, the first's. Either way one change is lost, conflicts stays at 0, and no error is raised. The rule against merging logs is the producer's to keep. Spec §8.1