From Port389
Separate Conflict and Tombstone Entry
Entry format
conflict entry:
current format dn: nsuniqueid=<UNIQID>+<RDN>,<PARENTDN> <attr>: <value> [...] nsds5ReplConflict: namingConflict <DN>
proposing format (internal; Slapi_Entry) dn: <RDN>,<PARENTDN> objectclass: nsConflict <attr>: <value> [...] nsdsEntryType: 1 nsds5ReplConflict: namingConflict <DN>
proposing format (external; search result/exported) dn: nsuniqueid=<UNIQID>+<RDN>,<PARENTDN> objectclass: nsConflict <attr>: <value> [...] nsdsEntryType: 1 nsds5ReplConflict: namingConflict <DN>
tombstone entry:
current format dn: nsuniqueid=<UNIQID>,<RDN>,<PARENTDN> objectclass: nsTombstone <attr>: <value> [...]
proposing format (internal; Slapi_Entry) dn: <RDN>,<PARENTDN> objectclass: nsTombstone <attr>: <value> [...] nsdsEntryType: 2
proposing format (external; search result/exported) dn: nsuniqueid=<UNIQID>,<RDN>,<PARENTDN> objectclass: nsTombstone <attr>: <value> [...] nsdsEntryType: 2
ordinary entry (no changes):
dn: <RDN>,<PARENTDN> <attr>: <value> [...]
Goal
General
- Separate conflict entries and tombstone entries from ordinary entries.
- No change in the DN of the conflict entry and the tombstone entry in the DB (id2entry.db/entryrdn.db).
- The entries remain in id2entry.db with system attribute specifying the type:
- no type (or nsdsEntryType: 0) is for the ordinary entry
- nsdsEntryType: 1 for conflict
- nsdsEntryType: 2 for tombstone, for instance
The system attribute nsdsEntryType is single-valued and integer. The motivation to have this system attribute is speeding up the entry type checking especially for the search-all "(objectclass=*)" case. We have the type info in the objectclass with the string value "nsConflict/nsTombstone". But checking the type using the string would be much slower than checking the integer value.
- Add conflict_entryrdn for the conflict entry and tombstone_entryrdn for the tombstone entry. DN of the ordinary entries are managed in the entryrdn index; the conflict entries are in the conflict_entryrdn index / the tombstone entries are in the tombstone_entryrdn index.
- Add "objectclass: nsConflict" for the conflict entry as "objectclass: nsTombstone" for the tombstone entry.
- The internal entry does not include the special "nsuniqueid=<UNIQID>" in the DN.
- An entry could be a conflict and a tombstone entry at the same time. The entry would look like this and the RDN list is both in the conflict_entryrdn and tombstone_entryrdn.
dn: <RDN>,<PARENTDN>
objectclass: nsConflict
objectclass: nsTombstone
<attr>: <value>
[...]
nsdsEntrytype: 3 <== 1 | 2
nsds5ReplConflict: namingConflict <DN>
- We may not put the conflict / tombstone entry and its DN into the entry / DN cache not to waste the memory with the less prioritised objects, respectively.
Search
- Search requires "(objectclass=nsConflict)" / "(objectclass=nsTombstone)" in the filter to return the conflict / tombstone entry, respectively.
- DN in the returned entry has the following format to support multiple conflict/tombstone entries originated from the same DN.
- conflict entry nsuniqueid=<UNIQID>+<RDN>,<PARENTDN>
- tombstone entry nsuniqueid=<UNIQID>,<RDN>,<PARENTDN>
- conflict entry nsuniqueid=<UNIQID>+<RDN>,<PARENTDN>
- BaseDN in the search could include the special "nsuniqueid=<UNIQID>". In the current plan, both 2 cases return the same entry:
case 1
BaseDN: "nsuniqueid=<UNIQID>+<RDN>,<PARENTDN>
Filter: (&(objectclass=nsConflict)(nsuniqueid=<UNIQID_N>))
case 2
BaseDN: "<RDN>,<PARENTDN>
Filter: (&(objectclass=nsConflict)(nsuniqueid=<UNIQID_N>))
Returned DN
nsuniqueid=<UNIQID>+<RDN>,<PARENTDN>
- The same is true for the tombstone entry.
- Extra task for the search-all: search with "(objectclass=*)" needs to check the nsdsEntryType value and ignore the conflict/tombstone marked entries.
Add conflict entry
- Add the conflict entry with "objectclass: nsConflict" and "nsdsEntryType: 1" to id2entry.
- Add the DN (a list of RDNs) to the conflict_entryrdn index.
- The conflict_entryrdn could store the intermediate DNs which are not conflict entries. (the nodes could be marked as ordinary).
Delete entry/Add tombstone entry
- Modify the entry adding "objectclass: nsTombstone" (already implemented) and "nsdsEntryType: 2" in id2entry
- Delete the DN from the entryrdn.
- Add the DN (a list of RDNs) to the tombstone_entryrdn.
- The tombstone_entryrdn could store the intermediate DNs which are not tombstone entries. (the nodes could be marked as ordinary).
Export
If '-r' is added to the command line, conflict / tombstone entries are exported. The DN contains the special "nsuniqueid=<UNIQID>".
Import
Support the current ldif (no objectClass: nsConflict; no nsdsEntryType) as well as the new ldif.
Resurrection steps users take
- If an ordinary entry with the same DN exists in the DB, delete it.
- Modify the entry: removing "(objectclass=nsConflict)" / "(objectclass=nsTombstone)"
- Internally, the modify is translated to.
- removing "(objectclass=nsConflict)" / "(objectclass=nsTombstone)"
- removing nsdsEntryType (if not specified)
- removing nsds5ReplConflict (if not specified; just for the conflict entry)
- removing the DN from conflict_entryrdn / tombstone_entryrdn, respectively.
- adding the DN to entryrdn.
Upgrade
- Scan id2entry.
- If an entry's RDN is "nsuniqueid=<UNIQID>+<RDN>" and nsds5ReplConflict is in the attr,
- rename the RDN to <RDN>
- add "objectclass: nsConflict"
- remove the DN from entryrdn and add it to conflict_entryrdn
- If an entry's RDN is "nsuniqueid=<UNIQID>,<RDN>" and objectclass contains "nsTombstone",
- rename the RDN to <RDN>
- remove the DN from entryrdn and add it to tombstone_entryrdn
entrydn support
By setting "nsslapd-subtree-rename-switch: off" in cn=config, we could go back to the entrydn indexing. We have to introduce extra index files: conflict_entrydn and tombstone_entrydn, as well.
Internal format
To support the multiple conflict / tombstone entries having the same original DN, we allow entries having the same RDN and parentid in id2entry. (Note: the conflict / tombstone entries only)
dbscan -f id2entry.db output
id N
rdn: <RDN>
nsuniqueid: <UNIQID_N>
parentid: M
entryid: N
id N+1
rdn: <RDN>
nsuniqueid: <UNIQID_N+1>
parentid: M
entryid: N+1
Plus conflict_/tombstone_entryrdn should be able to store a list of entryids instead of one. (Again, this is only for the conflict/tombstone entries.)
Another approach to use the special suffix: The following change could be considered
conflict entry dn: <RDN>,<PARENTDN>,<CONFLICTSUFFIX> objectclass: nsConflict <attr>: <value> [...] entrytype: 1
tombstone entry dn: <RDN>,<PARENTDN>,<TOMBSTONESUFFIX> objectclass: nsTombstone <attr>: <value> [...] entrytype: 2
Comments on this approach
- Adding the conflict / tombstone entry looks like a move in DIT, but it is not a move in terms of DN (since the original <SUFFIX> itself is not moved to <CONFLICTSUFFIX> or <TOMBSTONESUFFIX>, but a delete + add.
- ldbm_entryrdn code needs to have a knowledge about the special suffixes; currently, it only takes one "suffix".
- One entryrdn index file instead of 3 (entryrdn, conflict_entryrdn, tombstone_entryrdn).
- Search with -b "<CONFLICTSUFFIX>" / "<TOMBSTONESUFFIX>" is executed on multiple backends if there are multiple.
Related Ticket/Bug
Ticket #160 -- Make replication plugin put conflicts and tombstones in a special suffix
Bug 695797 - Invalid host record created during client enrollment with failover
Bug 747701 - [RFE] Make replication plugin put conflicts in a special suffix
Bug 772294 - Replication conflics resolution
