Siirry sisältöön

Kolmen tilan yhdistäminen

Kolmen tilan yhdistämisessä verrataan kahta muutosjoukkoa yhteiseen kantatilaan ja yhdistetään ne yhdeksi tulokseksi. merql käyttää tätä algoritmia tiedostorivien sijaan tietokannan riveihin.

PHP
use Merql\Merge\ThreeWayMerge;

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

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

Kolme tilaa

Jokainen yhdistäminen edellyttää täsmälleen kolmea tilannevedosta:

  • Perusta -- tietokannan tila siinä vaiheessa, kun haarat erkanivat toisistaan.
  • Meidän puolemme -- yksi haara muutostensa jälkeen, esimerkiksi muokattu hiekkalaatikkokopio.
  • Heidän puolensa -- toinen haara muutostensa jälkeen, esimerkiksi käynnissä pysynyt tuotantotietokanta.

Meidän ja heidän puolensa on kumpikin tallennettava tietokannasta, jossa kyseinen haara sijaitsee. Yhdistämissäännöt käsittelevät molempia puolia samalla tavalla; nimet määrittävät kunkin toiminnon source, ristiriitatyyppien nimet (update_delete tarkoittaa, että me päivitimme ja he poistivat) sekä sen, kumpaa puolta ConflictPolicy::OursWins ja TheirsWins suosivat.

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

Ilman yhteistä perustaa et voi erottaa lisäystä muuttumattomasta. Kahden tilan vertailussa nähdään, että puolella A on arvo ja puolelta B se puuttuu, mutta ei voida päätellä, lisäsikö A sen vai poistiko B sen. Perusta antaa vastauksen.

Muutossarjojen laskeminen

Differ vertaa kumpaakin tilannevedosta perustaan ja tuottaa kaksi muutossarjaa. Kummassakin muutossarjassa on kolmenlaisia toimintoja:

Perusta Nykyinen Toiminto
Rivi on olemassa Rivi on olemassa, sama sormenjälki Ei muutosta
Rivi on olemassa Rivi on olemassa, eri sormenjälki UPDATE (sarakkeittainen diff)
Rivi on olemassa Rivi puuttuu DELETE
Rivi puuttuu Rivi on olemassa INSERT

Sormenjäljet (SHA-256 normalisoidun rivisisällön hajautusarvot) tarjoavat nopean käsittelypolun. Jos kaksi sormenjälkeä täsmää, rivi on muuttumaton eikä sarakekohtaista vertailua tarvita.

PHP
use Merql\Diff\Differ;

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

Yhdistämissäännöt

Sen jälkeen kaksi muutossarjaa yhdistetään toiminto kerrallaan. Tässä taulukossa esitetään lopputulos jokaiselle yhdistelmälle:

Meidän puolemme Heidän puolensa Tulos
Ei muutosta Ei muutosta Säilytä perusta
Ei muutosta Päivitetty Hyväksy heidän muutoksensa
Päivitetty Ei muutosta Hyväksy meidän muutoksemme
Päivitetty (sama arvo) Päivitetty (sama arvo) Hyväksy (molemmat samaa mieltä)
Päivitetty (eri arvo) Päivitetty (eri arvo) Ristiriita
Ei muutosta Poistettu Hyväksy poisto
Poistettu Ei muutosta Hyväksy poisto
Poistettu Poistettu Hyväksy poisto (molemmat samaa mieltä)
Päivitetty Poistettu Ristiriita
Poistettu Päivitetty Ristiriita
Lisätty (vain meidän puolellamme) -- Hyväksy lisäys
-- Lisätty (vain heidän puolellaan) Hyväksy lisäys
Lisätty (sama PK) Lisätty (sama PK) Ristiriita

Kun molemmat puolet päivittävät samaa riviä, merql ei ilmoita ristiriidasta heti. Se siirtyy saraketason yhdistämiseen ja vertaa jokaista saraketta erikseen. Katso lisätiedot kohdasta saraketason yhdistäminen.

Käyttö julkisivun kautta

Merql-julkisivu käsittelee levylle tallennettuja nimettyjä tilannevedoksia. Kutsu Merql::init()-toimintoa kunkin tilan sisältävällä tietokannalla ennen tilannevedoksen ottamista:

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');

Älä ota kaikkia kolmea tilannevedosta peräkkäin samasta tietokannasta. Heidän tilannevedoksensa sisältäisi silloin myös meidän muutoksemme, joten jokainen meidän lisäämämme rivi näyttäisi olevan lisätty molemmilla puolilla ja aiheuttaisi insert_insert-ristiriidan.

Merql::merge(), Merql::patch() ja Merql::plan() luovat ThreeWayMerge-tuloksen ilman CellMergeConfig-toimintoa, joten yhdistäminen tapahtuu vain saraketasolla. Solutason yhdistämistä varten lataa tilannevedokset ja käytä suoraan luokkaa, kuten alla.

Luokkien suora käyttö

Voit hallita toimintaa tarkemmin luomalla komponentit itse. Snapshotter::capture() ei tallenna mitään, joten pidä tilannevedokset muistissa tai tallenna ne SnapshotStore::save()-toiminnolla:

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'),
);

Pikakuvake korjaustiedoston käyttöön

Kun vain toisella puolella on muutoksia (samanaikaisia muokkauksia ei ole), käytä patch()-toimintoa. Kyseessä on kahden tilan yhdistäminen, jossa meidän puolemme vastaa perustaa, joten ristiriitoja ei voi syntyä:

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

Julkisivun kautta:

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

patch() vastaa toimintoa merge($base, $base, $changes). Koska meidän puolemme ei koskaan eronnut perustasta, kaikki heidän muutoksensa hyväksytään ilman ristiriitoja.

Skeemapoikkeamien tunnistus

Jos tauluun lisättiin tai siitä poistettiin sarakkeita tilannevedosten välillä, yhdistäminen jatkuu mutta poikkeamat kirjataan. Muuttuneita saraketyyppejä ei verrata, ja uudelleennimetty sarake näkyy yhtenä poistettuna ja yhtenä lisättynä; katso skeeman validointi.

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

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

merql ei siirrä skeemaa automaattisesti. Skeemamuutokset ovat kutsujan vastuulla. Yhdistäminen ilmoittaa niistä, jotta voit päättää, miten jatkat.

MergeResult

Tulosolio sisältää kaiken tarvittavan:

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

Jokaisella MergeOperation-toiminnolla on tyyppi (insert, update tai delete), taulun nimi, rivin avain, sarakearvot ja lähde (ours, theirs tai merged). merged merkitsee riviä, jonka molemmat puolet päivittivät (sarakkeet yhdistettiin) tai jonka molemmat puolet poistivat.

Yhdistämistuloksen käyttökohde

Yhdistämistulos kuvaa, miten perusta muutetaan yhdistetyksi tilaksi. Sen toiminnot sisältävät molempien puolten muutokset: sekä meidän että heidän tekemänsä lisäys näkyy lisäyksenä.

  • Merql::apply() (tai Applier) suorittaa kaikki toiminnot yhdistetyssä tietokannassa. Se soveltuu sellaisenaan tietokantaan, jossa on edelleen perusta, kuten uuteen kopioon perustilasta. Jos tietokanta sisältää jo toisen puolen muutokset, olemassa olevan rivin lisäys epäonnistuu ja tapahtuma peruutetaan.
  • Jos haluat tuoda meidän muutoksemme tietokantaan, jossa on jo heidän muutoksensa, esimerkiksi siirtää hiekkalaatikon muutokset käytössä olevaan ympäristöön, ota käyttöön vain toiminnot, joita tietokannasta puuttuu: lähteen ours toiminnot sekä merged-päivitykset. Valitse ne yhdistämissuunnitelman avulla ja kirjoita ne tietokantaan Suojatun käyttöönoton avulla käyttämällä käytössä olevien rivien ennakkoehtoja.