Preskoči na vsebino

Trismerno združevanje

Trismerno združevanje primerja dva nabora sprememb glede na skupnega prednika in ju združi v en rezultat. merql ta algoritem uporablja za vrstice zbirke podatkov namesto za vrstice datotek.

PHP
use Merql\Merge\ThreeWayMerge;

$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);

echo $result->operationCount(); // resolved operations
echo $result->conflictCount();  // unresolved conflicts

Tri stanja

Vsako združevanje zahteva natanko tri posnetke:

  • Base -- stanje zbirke podatkov, ko sta se veji razšli.
  • Ours -- ena veja po svojih spremembah, na primer urejena peskovniška kopija.
  • Theirs -- druga veja po svojih spremembah, na primer živa zbirka podatkov, ki je še naprej delovala.

Ours in theirs morata biti vsak zajeta iz zbirke podatkov, ki hrani ustrezno vejo. Pravila združevanja obravnavajo obe strani enako; imeni določata source posamezne operacije, poimenovanje vrst konfliktov (update_delete pomeni, da je ours posodobil, theirs pa izbrisal) ter strani, ki jima ConflictPolicy::OursWins in TheirsWins dajeta prednost.

Koda
         Base (snapshot at fork time)
        /                              \
   Ours (our changes)                   Theirs (their changes)
        \                              /
         --------- MERGE ----------
                     |
              Merged result
              + conflicts (if any)

Brez skupne osnove ni mogoče razlikovati med »dodano« in »nespremenjeno«. Dvosmerna primerjava pokaže, da ima stran A vrednost, stran B pa je nima, ne more pa ugotoviti, ali jo je dodala A ali izbrisala B. Na to vprašanje odgovori base.

Kako se izračunajo nabori sprememb

Differ primerja vsak posnetek z osnovo in ustvari dva nabora sprememb. Vsak nabor vsebuje tri vrste operacij:

Osnova Trenutno Operacija
Vrstica obstaja Vrstica obstaja, enak prstni odtis Brez spremembe
Vrstica obstaja Vrstica obstaja, drugačen prstni odtis UPDATE (razlika po stolpcih)
Vrstica obstaja Vrstica manjka DELETE
Vrstica manjka Vrstica obstaja INSERT

Prstni odtisi (SHA-256 zgoščene vrednosti normalizirane vsebine vrstice) omogočajo hitrejšo obdelavo. Če se dva prstna odtisa ujemata, vrstica ni spremenjena in primerjava po posameznih stolpcih ni potrebna.

PHP
use Merql\Diff\Differ;

$differ = new Differ();
$oursChangeset = $differ->diff($base, $ours);
$theirsChangeset = $differ->diff($base, $theirs);

Pravila združevanja

Nabora sprememb se nato združita operacijo za operacijo. Ta tabela določa rezultat za vsako kombinacijo:

Ours Theirs Rezultat
Brez spremembe Brez spremembe Ohranite base
Brez spremembe Posodobljeno Sprejmite theirs
Posodobljeno Brez spremembe Sprejmite ours
Posodobljeno (enaka vrednost) Posodobljeno (enaka vrednost) Sprejmite (obe se ujemata)
Posodobljeno (drugačna vrednost) Posodobljeno (drugačna vrednost) Konflikt
Brez spremembe Izbrisano Sprejmite izbris
Izbrisano Brez spremembe Sprejmite izbris
Izbrisano Izbrisano Sprejmite izbris (obe strani se strinjata)
Posodobljeno Izbrisano Konflikt
Izbrisano Posodobljeno Konflikt
Vstavljeno (samo ours) -- Sprejmite vstavitev
-- Vstavljeno (samo theirs) Sprejmite vstavitev
Vstavljeno (enak PK) Vstavljeno (enak PK) Konflikt

Ko obe strani posodobita isto vrstico, merql takoj ne razglasi konflikta. Preide na združevanje na ravni stolpcev in vsak stolpec primerja posebej. Podrobnosti so v razdelku Združevanje na ravni stolpcev.

Uporaba vmesnika facade

Vmesnik facade Merql deluje z imenovanimi posnetki, shranjenimi na disku. Pred ustvarjanjem posnetka pokličite Merql::init() za zbirko podatkov, ki hrani posamezno stanje:

PHP
use Merql\Connection;
use Merql\Merql;

$live    = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');

Merql::init($live);
Merql::snapshot('base');      // before the sandbox is copied from live

// ... copy live.sqlite to sandbox.sqlite, then both databases change ...

Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');

$result = Merql::merge('base', 'ours', 'theirs');

Ne ustvarite vseh treh posnetkov zaporedoma iz ene zbirke podatkov. Theirs bi potem vseboval tudi spremembe ours, zato bi bila vsaka vrstica, ki jo je vstavil ours, videti kot vstavljena na obeh straneh in bi bila prijavljena kot konflikt insert_insert.

Merql::merge(), Merql::patch() in Merql::plan() ustvarijo ThreeWayMerge brez CellMergeConfig, zato združujejo samo na ravni stolpcev. Za združevanje na ravni celic naložite posnetke in uporabite razred neposredno, kot je prikazano spodaj.

Neposredna uporaba razredov

Za več nadzora sami ustvarite primerke komponent. Snapshotter::capture() ničesar ne shranjuje, zato posnetke ohranite v pomnilniku ali jih shranite z SnapshotStore::save():

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Snapshot\Snapshotter;
use Merql\Snapshot\SnapshotStore;

$base   = (new Snapshotter($live))->capture('base');
// ... copy live to the sandbox, then both databases change ...
$ours   = (new Snapshotter($sandbox))->capture('ours');
$theirs = (new Snapshotter($live))->capture('theirs');

$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);

// Snapshots saved earlier, merged with cell-level merge for TEXT and JSON columns.
$merge = new ThreeWayMerge(CellMergeConfig::auto());
$result = $merge->merge(
    SnapshotStore::load('base'),
    SnapshotStore::load('ours'),
    SnapshotStore::load('theirs'),
);

Bližnjica za popravek

Kadar so spremembe samo na eni strani (brez sočasnih sprememb), uporabite patch(). Gre za dvosmerno združevanje, pri katerem je ours enak base, zato so konflikti nemogoči:

PHP
$result = $merge->patch($base, $changes);
// Always clean: ours is identical to base.

Prek vmesnika facade:

PHP
$result = Merql::patch('base', 'changes');

patch() je enakovreden merge($base, $base, $changes). Ker se ours nikoli ni razšel od base, so vse spremembe s strani theirs sprejete brez konflikta.

Zaznavanje neskladij shem

Če so bili med posnetki tabeli dodani ali iz nje odstranjeni stolpci, se združevanje kljub temu izvede, neskladja pa se zabeležijo. Spremenjene vrste stolpcev se ne primerjajo, preimenovan stolpec pa se prikaže kot odstranjen in dodan; glejte Preverjanje sheme.

PHP
$result = $merge->merge($base, $ours, $theirs);

if ($result->hasSchemaMismatches()) {
    foreach ($result->schemaMismatches() as $mismatch) {
        echo $mismatch->getMessage() . "\n";
    }
}

merql shem ne seli samodejno. Za spremembe sheme je odgovoren klicatelj. Združevanje jih zabeleži, da se lahko odločite, kako nadaljevati.

MergeResult

Rezultatni objekt vsebuje vse, kar potrebujete:

PHP
$result->isClean();            // true if no conflicts
$result->operations();         // list of MergeOperation objects
$result->conflicts();          // list of Conflict objects
$result->operationCount();     // number of resolved operations
$result->conflictCount();      // number of unresolved conflicts
$result->hasSchemaMismatches(); // true if schemas differ
$result->baseSnapshot();       // the base snapshot used for the merge

Vsak MergeOperation ima vrsto (insert, update ali delete), ime tabele, ključ vrstice, vrednosti stolpcev in vir (ours, theirs ali merged). merged označuje vrstico, ki sta jo posodobili obe strani (stolpec za stolpcem), ali vrstico, ki sta jo obe izbrisali.

Kje uporabiti rezultat združevanja

Rezultat združevanja opisuje, kako pretvoriti base v združeno stanje. Njegove operacije vključujejo spremembe obeh strani: vstavljanje, ki ga je izvedel ours, in vstavljanje, ki ga je izvedel theirs, sta prikazana kot vstavljanji.

  • Merql::apply() (ali Applier) izvede vsako operacijo v povezani zbirki podatkov. Brez težav se uporabi v zbirki podatkov, ki še vedno vsebuje base, na primer v sveži kopiji osnovnega stanja. V zbirki podatkov, ki že vsebuje spremembe ene strani, vstavljanje obstoječe vrstice ne uspe in transakcija se povrne.
  • Če želite prenesti spremembe ours v zbirko podatkov, ki že vsebuje theirs, na primer uveljaviti peskovniške popravke v živi zbirki, uporabite samo operacije, ki tej zbirki podatkov manjkajo: tiste z virom ours ter posodobitve merged. Uporabite načrt združevanja, da jih izberete, in Zaščiteno uporabo, da jih zapišete s predpogoji za žive vrstice.