This page is based on 'Conflict detection and resolution - research'.
Introduction
Conflict scenarios:
- Update-update
Occurs when the same object was updated at more than one node. - Update-delete
Occurs if a row was updated at one node, but the same row was deleted at another node. - Delete-delete
Occurs when a row was deleted from more than one node.
Conflict Detection
Conflict detection is based on hash codes. Every object has its own Sync hash code which can be generated basing on that object. During pull or push operation a child instance compares hash codes of a local object, parent's object and recently saved parent's object. The hash code of recently saved parent's object is persisted in the database. We have to establish some shortcuts before we explain when the conflict is detected:
- #C : a hash code of the child instance object
- #P : a hash code of the parent instance object
- #lastP : a last saved hash code of the parent instance object.
The conflict is detected when (#lastP != #P) && (#C != #P).
Note! We have added a new row in a database sync_parent_object_hashcode table for each object pulled from its Parent instance. We keep only the most current hash code of each object.
Conflict Resolution
PULL:
- RULE 1
If hash code of an object on Parent instance is NOT equal to hash code of an object on Child instance* it means that there is a new version of this object on Parent →- if object on Child instance was NOT modified (calculated hash code of modified object is equal to hash code saved on Child's instance*) →
- void current object's fields on Child instance,
- save fields of object from Parent instance to Child.
- if object on Child instance was modified (calculated hash code of modified object is NOT equal to hash code saved on Child's instance*) →
- these two objects have to be merged**, then
- saved on Child and Parent instance;
- hash codes on both Child and Parent instance have to be updated.
- if object on Child instance was NOT modified (calculated hash code of modified object is equal to hash code saved on Child's instance*) →
* REMEMBER: This is a hash code of an object that was calculated and saved on the last pull of this object from Parent. This hash code is stored in a separate table than pulled object.
** See Merge
PUSH:
- RULE 2
If hash code of an object on Parent instance is NOT equal to hash code of an object on Child instance* it means that the object was updated on Parent instance after the last pull to Child (we are pushing modifications of outdated version of object) →- if object on Child instance was NOT modified (calculated hash code of modified object is equal to hash code saved on Child's instance*) → PUSH operation of this object will not take place
- if object on Child instance was modified (calculated hash code of modified object is NOT equal to hash code saved on Child's instance*) →
- these two objects have to be merged**, then
- saved on Child and Parent instance;
- hash codes on both Child and Parent instance have to be updated.
- if object on Child instance was NOT modified (calculated hash code of modified object is equal to hash code saved on Child's instance*) → PUSH operation of this object will not take place
* REMEMBER: This is a hash code of an object that was calculated and saved on the last pull of this object from Parent. This hash code is stored in a separate table than pulled object.
** See Merge
Merge
Once a conflict was detected two objects will have to be merged. To do this, a new database table "Conflicts" will have to be created.
This table will have columns: openmrs_class, first_object, second_object and more if needed.
It will be possible to insert any type of object into child_object and parent_object due to its type: it will be either JSON, (TINY)BLOB, TEXT or else.
All conflicted objects will be put into this table and queued just like AuditLog does this.
However, there should be only the most recent merge conflict for any object. The old ones should be voided.
Then either chosen strategy or UI will be used to:
- determine if child_object, parent_object or mixed object will be preserved,
- determine what operation should be taken after merging (push / pull / ...)
When the conflict is resolved we should save parent's object as voided in child's database.
UI for merging will use openmrs_class field to determine what class are child_object and parent_object.
Fields of determined class will be displayed as text-boxes or buttons for each of two objects.
User will be able to choose which value he wants to keep.
Please read Merging extension points if you want to implement your own merge behaviour.