Pāriet uz saturu

Ievads

merql ir tīra PHP bibliotēka trīspusējai datubāzes stāvokļa apvienošanai. Tā izveido tabulu momentuzņēmumus, aprēķina izmaiņu kopas starp tiem, apvieno divas izmaiņu kopas, salīdzinot ar kopīgu bāzi, un nosaka konfliktus kolonnu līmenī. Tas pats algoritms, ko git izmanto avota failiem, tikai rindu un kolonnu, nevis rindu tekstā apvienošanai.

Bez ārējiem rīkiem. Atbalsta MySQL un SQLite, izmantojot pieslēdzamus savienojuma adapterus un dialektu draiverus.

Īss piemērs

Apvienošanai nepieciešami trīs viena un tā paša datu kopuma stāvokļi: bāze, no kuras sāka abas kopijas, un abas kopijas pēc neatkarīgām izmaiņām. Šeit smilškaste tika izveidota, kopējot reāllaika datubāzi, un kopš tā laika ir rediģētas abas.

PHP
use Merql\Connection;
use Merql\Merql;

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

// Base: live at the moment the sandbox was copied from it.
Merql::init($live);
Merql::snapshot('base');

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

// Ours: the sandbox with our edits. Theirs: live with its own changes.
Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');

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

if ($result->isClean()) {
    foreach ($result->operations() as $operation) {
        echo "{$operation->type} {$operation->table} #{$operation->rowKey} ({$operation->source})\n";
    }
} else {
    echo "Conflicts: {$result->conflictCount()}\n";
}

Katrs momentuzņēmums tiek iegūts no datubāzes ar atbilstošo stāvokli. Visu trīs secīga iegūšana no vienas datubāzes neattēlo divas atšķīrušās kopijas: theirs jau ietvertu ours izmaiņas, un katra ours ievietotā rinda tiktu uzrādīta kā insert_insert konflikts.

Rezultātā ir uzskaitītas darbības, kas pārveido base par apvienoto stāvokli, ietverot abu pušu izmaiņas, un katrai norādīts tās avots (ours, theirs vai merged). Lai pārnestu smilškastes izmaiņas uz reāllaika datubāzi, lietojiet tikai darbības, kuru tajā vēl nav, izmantojot Nosacītā lietošana.

Vai no CLI, kas izveido savienojumu ar snapshot norādīto datubāzi katram MERQL_DB_DSN:

Apvalks
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
# ... copy live.sqlite to sandbox.sqlite, then both databases change ...
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs

vendor/bin/merql merge base ours theirs --dry-run

Kāpēc izvēlēties merql

Lielākā daļa datubāzu rīku, kas salīdzina stāvokļus, darbojas rindu līmenī: ja starp divām versijām atšķiras kaut viena rindas kolonna, visa rinda tiek atzīmēta kā konflikts. Tādēļ kļūdaini konflikti rodas, ja divi cilvēki rediģē vienas rindas dažādas kolonnas.

merql apvieno kolonnu līmenī. Ja viena puse mainīja title, bet otra — status, izmaiņas tiek veiksmīgi apvienotas bez konflikta. Konflikts rodas tikai tad, ja abas puses maina vienu un to pašu kolonnu uz atšķirīgām vērtībām.

TEXT un JSON kolonnām merql var iet vēl vienu līmeni dziļāk un veikt apvienošanu šūnu līmenī. Divas izmaiņas dažādās teksta kolonnas rindās vai dažādās JSON kolonnas atslēgās var veiksmīgi apvienot, izmantojot to pašu trīspusējo algoritmu. Šūnu līmeņa apvienošana jāieslēdz atsevišķi: nododiet CellMergeConfig uz ThreeWayMerge. Fasāde Merql un CLI apvieno tikai kolonnu līmenī. Skatiet sadaļu Šūnu līmeņa apvienošana.

Apvienošanas modelis

Kods
         Base (snapshot at fork time)
        /                              \
   Ours (one copy's changes)            Theirs (the other copy's changes)
        \                              /
         --------- MERGE ----------
                     |
              Merged result
              + conflicts (if any)

Trīs stāvokļi, tāpat kā git. Base ir kopīgais priekštecis. Ours un theirs ir abas kopijas pēc to atšķiršanās; katra iegūta no savas datubāzes. Apvienošanas noteikumi abām pusēm ir vienādi. Šie nosaukumi parādās katras darbības laukā source, konfliktu veidos (update_delete nozīmē, ka ours atjaunināja, bet theirs izdzēsa) un atrisināšanas politikās OursWins un TheirsWins. Bez kopīgas bāzes nevar atšķirt “pievienots” no “nemainīts”.

Apvienošana pati par sevi neko neraksta. Tās darbības pārveido base par apvienoto stāvokli, tāpēc Merql::apply() tās visas var veiksmīgi izpildīt tikai datubāzē, kurā joprojām ir base stāvoklis. Lai pārnestu vienas puses izmaiņas datubāzē, kurā jau ir otras puses izmaiņas, piemēram, pārnestu smilškastes rediģējumus uz reāllaika datubāzi, lietojiet tikai trūkstošās darbības; skatiet Nosacītā lietošana.

Prasības

  • PHP 8.2 vai jaunāka versija.
  • ext-mbstring un ext-zlib, kas nepieciešami pitmaster/pitmaster atkarībai teksta atšķirību noteikšanai.
  • Izmantotajam adapterim vajadzīgs datubāzes paplašinājums: ext-pdo ar ext-pdo_sqlite vai ext-pdo_mysql, vai ext-mysqli. merql composer.json tikai iesaka ext-pdo un ext-mysqli, tāpēc Composer tos nepārbauda.
  • Datubāze MySQL vai SQLite. Citām sistēmām nepieciešams pielāgots draiveris.

Kas tas nav

merql nav shēmas migrācijas rīks. Tas nereplicē datubāzes un nesinhronizē tās reāllaikā. Tas risina vienu konkrētu problēmu: no trim datubāzes stāvokļiem izveidot ceturto, apvienoto stāvokli, nosakot konfliktus.

Dokumentācija