Carl's DbSync library set?

Elozmeny: http://hup.hu/node/129710?comments_per_page=9999

Ugy tunik, ezt a web, iOS es Android kozti db szinkronizalos kiegeszitest magamnak kell megirnom. Jelenleg valami ilyesmi terv van a fejemben (mellyel kapcsolatban barmilyen jellegu epito es rombolo jellegu kritikat elfogadok ma):

-Adott egy nagy DB (tovabbiakban FULL DB) - ezt hasznalja a webszerver (tobbek kozott). Ez altalaban Postgresql, Mysql/MariaDB/Percona, vagy Oracle DB
-Adottak kis DB-k (PARTIAL DB) - ezt hasznaljak iOS-es es Androidos alkalmazasok futo peldanyai. Ez gyakrolatilag mindig SQLite lesz, ugyhogy talalni kell majd egy okos konverzios megoldast SQLite es mas DB engine-ek kozt odavissza

Elso nehezseg: a CREATE TABLE/ALTER TABLE-oket es CONSTRAINT-eket tudja szintakitakailag egyikbol a masikba alakitani (pl. a MySQL-es CREATE TABLE-bol tudjun csinalni PostgreSQL-est es SQLite-ost, stb.) Ebbol nyilvan kovetkezik, hogy csak olyan elemeket fogad el a rendszer, amit valamilyen formaban minden db motor tamogat (pl. Oracle oszlopobjetum itt nem fog mukodni, es a Postgresql-es tombattributum sem emiatt, de pl. a date/timestamo konverzio mar okosan meg lesz oldva egymas kozt)

Cel: mind Androidon, mind iOS-en, mind a szerver appban egy "import lib" es egy "sync" utasitas elegendo legyen arra, hogy transzparensen lekezelje az adatbaziselemek reszleges szinkronizalasat (altalaban azt a szeletet, amihez az eppen belepett user hozza kell hogy ferjen). Magyarul mind a webappban, mind az iOS appban, mind az Android appban ugyanazokat a query-ket kelljen megirnunk.

Tehat mi is tortenik majd, ha belep a user az alkalmazasba? Az adott adatbazis szeletet megkapja a tegnap emlitett modon:
0. A users tabla semajat is a programozo adja meg, de az kiemelt helyet kap a configban, leven az a fo szempontja a db-nk szeletelesenek
1. Alapeset: le akarunk kerdezni minden adatot, ahol a userunk aki epp be van lepve a FOREIGN KEY a tobbi adathoz, ezeket letoltjuk a mobilapphoz tartozo PARTIAL DB-jebe
2. Azoknak a tovabbi FOREIGN KEY-eihez tartozo adatokat is le akarjuk kerdezni a FULL DB-BOL a PARTIAL DB-be
3. Rajovunk, hogy ez igy nem eleg, van par statikus adattabla amit midenkeppen le akarunk kerdezni egeszben a FULL DB-bol a PARTIAL DB-be (pl. egy user jogosultsagokat vagy kategoria ID-kat tartalmazo altalaban kismeretu tabla), mert anelkul nem mukodik transzparensen az app offline (ezt mondjuk be tudjuk allitani egy config file-ban vagy egy include-ban)
4. Ha mar van configunk/include-unk, a FOREIGN KEY-ekkel meg nem jelolheto (pl. mas db-ben levo, vagy egy tablaban egyszerre ket oszlopban is elofordulo (pl. contact1: x user es contact2: y user es az is kell ahol a userunk x es az is ahol a userunk y)) adatokat is jo ha le tudjuk menteni, erre jo ha kulon meg tudunk adni szabalyokat, hogy "ezzel azt is fetch-eld le mindig a FULL DB-bol a PARTIAL DB-be".

Honnan tudjuk majd, hogy melyik a lokalisan keszitett adat, es melyik a szerverrol szedett/szerveren levo?
-Ez konfiguralhato lesz, de alapbeallitas szerint minden autoincrementes ID a szerveren 10001-tol kezdodik, ami azalatti, azt az app csinalta lokalisan, amikor offline volt/nem volt connection/megszakadt a connection commit elott es rollback-elt minden kliens es szerver oldalon is. Nyilvan ebben az esetben ha lokalban tulleptuk az amugy minden szinkronizalaskor resetalt autoincrementes ID-kkal a 10000-et, utana kivetelt/hibakodot tartalmazo NSObjectet dobunk a local appnak, amit a programozo majd lekezel, es kiirja a user ele, hogy ehhez mostmar lassan internetre kene kapcsolodni.

Ebbol mar is szuletett egy limitacio: a db semanak csak azon elemeibol lehet lokalisan uj peldanyt kesziteni, amelyiken a PRIMARY KEY egy numerikus ID. (egyetem kozepe ota nem lattam ettol eltero peldat, halistennek)
A user tablad olyan, hogy a nickname vagy az email a PRIMARY KEY? Semmi problema, csak akkor abba lokalisan nem insertalhatsz. Ezert lesz egy master connection string is, amin keresztul a FULL DB-be insertalhatsz, es a FULL DB-bol kerdezhetsz le amennyiben van halozat (kivetelt (Java/Androidon) vagy mas hibakodot dob, ha nem volt connection vagy eltimeoutolt, nem vegzodott committal, stb.).

Felmerult mar eddigre talan olvasonkban, hogy azt valahogy meg kellene oldani, hogy ne mindig toltson be 1000 sort a PARTIAL DB a FULL DB-bol, mikor a sync utasitas csak 5-10 sort valtoztatna. Ennek megoldasara lesz egy edit_log tabla amit a szerver oldal es a kliens oldal is vezet es a legutobbi szinkronizalasi datum utani elemeket cserelgetik majd ki. Nos, ez a tabla nagyon tele lesz, ezert egyreszt toroljuk belole azokat az elemeket mondjuk naponta, amiknek a status-a mar "will never need anymore", masreszt alapbeallitaskent 30 naponta uj tablat csinalunk belole, es emiatt lesz pl. edit_log_2013_04_03 , edit_log_2013_05_03, edit_log_2013_06_03, stb. tabla. Ennek az oka az, hogy ugyan ne sokszazmillio rekordnal tartson mindossze egyetlen egy tabla, inkabb kerdezzunk le ket tablabol is azoknak a mobilappoknak edit adatot, akik hetek ota nem frissitettek. Ha az edit_logban nincs benne a mobil app ID-ja, vagy "force full sync" az edit_log rekord statusza, akkor full db sync kovetkezik (ezzel nyilvan performance okok miatt ovatosan kell hogy banjon majd a programozo).

Idonkent valtoztatunk a tablakon (ALTER TABLE ADD COLUMN), ez ha pl. a szerveren (FULL DB, amit a webapp hasznal) megtortenik, akkor arrol valahogy (pl. verzioszam valtoztatasaval) szerezzen tudomast a szinkronizalasi kiserletnel az iOS/Android app (PARTIAL DB) is, mielott barmi tortenne, es modositsa a sajat semait ennek megfeleloen. Ez performance issue-khoz vezethet, ha egyszerre tobbszazezer user kezdi el frissiteni a db semajat es kezdi el nullarol felhuzni a db-jet. Az sem megoldas tobbgigas DB eseten, hogy fenntartunk egyet a regi semaval es egyet az ujjal es megadjuk hogy pl. egyszerre csak 5-en sync-elhetnek, tobbiek a regi DB adatait kapjak (bar lehet ennek ellenere lesz ilyen opcio, ha valakinek ez lenne optimalis). Erre majd meg ki fogok talalni valami jobbat is, ezen agyalnom kell.

Szerintem a szerver oldalon a legjobb eszkoz amivel dolgozhatok, az egy JSP+JDBC paros. Egy JSP-ben irt daemonban remekul el tudom cache-elni a memoriaban a surun lekerdezett tablakat es adatokat, JDBC-nel jobban meg nem hiszem hogy barmi is lekezelne ezt a sok kulonbozo SQL drivert. Valahogy meg kene oldani, hogy PHP-sok is tudjanak benne jatszani, meg ha ott ugrik is a hatekony app serveres cache-eles es az app server daemon, igy ezen a reszen meg gondolkodni fogok.

A vegeredmenybol a programozo ennyit fog latni:
-egy Androidos lib (mappa forrasba bemasol, import libnev, config forrasfajl edital connection stringgel stb.-vel, uj peldany, syncForUserID utasitas (addicionalisan masterDbQuery es masterDBResultSet utasitasok)). Ez csak es kizarolag Java-ban irva, Androidos jol mukodo SQLite libet felhasznalva
-egy iOS-es lib (mappa forrasba bemasol, #import libnev.h, config forrasfajl edital connection stringgel stb.-vel, uj peldany, syncForUserID utasitas (addicionalisan masterDbQuery es masterDBResultSet utasitasok)). Ez csak es kizarolag Objective-C-ben megirva, de ezen kivul tartalmazni es igenyelni fog a projekt egy SQLite-ot kenyelmesebbe es Objective-C-sebbe tevo libet is (melyben a mar mas frameworkokbol megszokott sorobjektumok mellett lehet majd egy egyszeru NSMutableDictonary-be is gyujteni attributumonkent az adatbazis sorait es oszlopait pl.).
-egy core process JSP+JDBC alapokon amit csak el kell inditani
-config fajl a core process-hez (connection creditentials, ID hol kezdodik, adatbazis fuggosegi fa szeleteleshez (es annak manualis kiegeszitese), korabban emlitett mindenkeppen szukseges tablak, egyidoben max hany full sync (nullarol inditott app/"force full sync"/semamodositas) futhat, fejlesztoi/elo kornyezet konfigja jol kulonvalasztva, stb.)
-a core process config fajlja amennyire csak lehet, hasonlitani fog az Objective C-s es Androidos lib altal kezelt config file-okra.
-JSP lib a webapp lefeljlesztesehez, mely szepen ki van talalva arra, hogy kommunikaljon a mar megirt, hozzanyulast nem igenylo szinten JSP+JDBC-s daemon folyamattal
-??TALAN egy lib PHP-hoz PDO alapokon (forrasba bemasol, config beallit, uj peldany, SQL query-k a JSP-s daemon fele mennek), csak itt azert nagy a kisertes, hogy sokan csak fogjak minden olvasas nelkul a connection stringet es beviszik a maguk mysqli megoldasukba pl. Attol viszont meg az edit_log nem fog valtozni, ami sok bajt okozhat. Ezert talan megoldanam azt, hogy triggerek is allitgathassak az edit logot, meg azt is, hogy a JSP-s daemon allitgassa, configtol fuggoen. Csak kerdes, hogy hogyan "tiltom le" a PHPistikeket a sajat webszerveruk sajat DB-jerol, ha nem triggerekkel akarjak az edit_logot insertalgatni.

Kerdeseim:
-Szerintetek eletkepes az otlet? (igen, tudom, ez nem az a kod, amit csak ugy eladhatok es ahhoz kepest sok a munka vele, de itt inkabb arra gondolok, hogy hasznalnatok ha kesz, es teszemazt free?)
-Ti mit csinalnatok maskepp/mit oldanatok meg mas technologiaval mint a tervezett?
-Erdekelni fog titeket ha elkeszult?
-Van valami, amire nem gondoltam "tervezes" kozben?

Hozzászólások

Szia!

Bocsi, engem nem annyira érint, de esetleg a különböző Migrations projektek megfelelő alapot nyújthatnának. (Csak átfutottam amit írtál, lehet, hogy mégsem.) Pl.: Scala Migrations Ha mégsem, legalább a tervezéshez adhatnak ötletet.
Így nem kellene mindent kitalálnod, kompatíbilitást érhetnél el. (Az iOS rész problémás lehet, de erre a migeran megoldást nyújthat majd, de ezt sem ismerem.)
Annyi mig kezdetű link került be... Lehet, hogy a végén a Te projekted neve is azzal fog kezdődni. :D

Az első (Scala Migrations) valóban hasznos lesz, tevezés szempontjából mindenképp tanulságos lesz a projektet áttekinteni, a második link viszont nem érint annyira, mert minél natívabban akarom megoldani iOS-en a dolgot (tehát csak az Objective-C, meg az amiatt eleve működő (és SQLite esetén egyébként is jelenleg egyetlen megoldást nyújtó) ANSI C nyelvek használatán kívül minél kevesebb nyelvet szeretnék belerángatni az iOS-es portba (leginkább semennyit)). A tegnapi couchdb-vel is pont az volt a bajom, hogy már egy erlang meg egy js is belekerül a végső appba (meg az is baj volt vele, hogy nem SQL).

Az elsodleges problemad ugyis az lesz, hogy egy csomo tipust nem fogsz tudni megengedni a master oldalon, mert az sqlite-nak merhetetlenul minimalis az abrazolokepessege, raadasul a hivatalosan ismert tipusok egy reszet is stringkent tarolja, es beparzolja ha kell. Ezt mindenkepp el kell valahogy kezelned, dinamikus konvertalassal peldaul.

En az edit_log tablaban csak a ket kapcsolodasi ido kozti adatot tartanam a kliensen, a tobbit eldobnam. Felesleges tobbezer evnyi tortenelmet felhalmozni, a kliensnek akar korlatozott kapacitasa is lehet, raadasul adott esetben a szerveren ugyis ott a teljes edit_log.

Oszinten szolva en nem vagyok hive a "kossunk ossze sok kulonfele SQL szervert, mert az jo lesz" elvnek, mert valaki biztos olyasmit akar csinalni, ami nem mukodik a rendszerben, es csak anyazasok vannak. Inkabb csinalnek valami nagyon egyszeru kozos formatum feletti szinkronizalast (JSON pl. tipikusan alkalmas a celra), es mindenki epitgessen maganak sajat DB-t. Igy nincsenek abrazolasi problemak, nincsenek CONSTRAINT problemak, mindket oldalon az lehet, ami szem-szajnak ingere, es egy kozos formatumon futtyennek ossze, ha epp arra van szukseg.

A semavaltas meg legyen az app fejlesztojenek a felelossege, nem egy ordongosseg egyebkent megirni SQLite-ban a migraciokat, plusz amugy is kell frissitest kitolni (altalaban egy sema modositast nem ok nelkul lepnek meg), szoval mindegy. A kozos formatum meg el tudja rejteni azokat a semamodositasokat, amik nem tartoznak a kliensre (nem semabovulesrol van szo).
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. 

"Az elsodleges problemad ugyis az lesz, hogy egy csomo tipust nem fogsz tudni megengedni a master oldalon, mert az sqlite-nak merhetetlenul minimalis az abrazolokepessege"

Nem baj, ezt a belso create table atalakito motor blokkolni fogja, hogy sqlite-ra atalakithato maradjon minden. Pl szeretem az Oracle oszlopobjektumait, de azt pont emiatt nem fogja peldaul tamogatni, az ilyenekhez majd kiirja a semahoz az adminfelulet hogy "unsupported, please reconsider your schema without x feature".

Igen, tudom, lesz egy ket pattern-beli beleegetett korlat emiatt, amin sose fogok tudni segiteni, de szerintem meg igy is transzparens marad a megoldas, es a nullarol tervezett web+mobilappok 70-80%-at szerintem ez egy alkalmas eszkoz lesz kiszolgalni, ha az ember tudja, hogy milyen semat tervezzen (de SQLite-ra eddig se tudott a mobil reszhez masmilyet).

Az edit_logot en is hasonloan terveztem megoldani ahogy te, azzal nincs gond, max kotelezo lesz midennhol modified_at oszlop is, lehet ugy jobb. De a nagy reszet az edit_lognak termeszetesen csak a szerver oldal tarolja majd

"Inkabb csinalnek valami nagyon egyszeru kozos formatum feletti szinkronizalast (JSON pl. tipikusan alkalmas a celra), es mindenki epitgessen maganak sajat DB-t"

A parent topikban emlitett couchdb mintha pont hasonlo lenne.

De ennek ellenere pont ebbol lett elegem, ezert oldom meg igy (elso kanyarban magamnak, de az a celom, hogy mindenki pillanatok alatt el tudja gyorsan es transzparensen sajatitani ezt a par plusz rovid sort igenylo megoldast, aki programozott mar Androidra, iOS-re).

"...nincsenek CONSTRAINT problemak..."

Amit a Constraint okoz az NEM problema, pont arra van, hogy szoljon hogy valami rosszul kerult be a DB-be egy kod altal. A Constraint feature, meg ha esszel is kell hasznalni (de mit nem kell azzal?).

"A semavaltas meg legyen az app fejlesztojenek a felelossege"

Az ove lesz, csak szeretnem, ha lenne ehhez a kezeben nehany, nem csak egyfajta megoldast nyujto segedeszkoz a szerver oldalon, melyek kozul egy gigantikus db melle is talal maganak megoldast es alternativat az oszlopaddolas atveszelesere.

A CONSTRAINT problemak alatt en konkretan arra gondoltam, hogy az SQLite a felet sem tudja azoknak a constrainteknek abrazolni, amire szukseg lenne - tenyleg nagyon minimalis feature settel dolgozik. Sajnos, en mar szaladtam bele korlatokba amikor egy eredetileg nem SQLite-ra tervezett appot probaltam meg belegyomoszolni.

Nem ertek annyira a mobilos appfejleszteshez, hogy megiteljem: hasznos-e vagy sem ez a cucc amin dolgozol. Reszben mert mar vannak a felvetett problemakra megoldasok, reszben pedig mert eleg sok korlatja van - ez esetleg elriaszthatja a jovobeni felhasznalokat. Egy ujfajta megkozelitesnek elsosorban akkor erdemes idot szanni, ha hatekony elonyokhoz juttathat - pusztan egy alternativ megoldasi ut miatt nem biztos, hogy megeri. De ez persze csak az en privat velemenyem - szkepticizmusommal nem akarlak eltantoritani a projekttol, csak engem nem gyozott meg, amit hallottam.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. 

Emlékeim szerint ilyesmi van Androidra. Nem lenne egyszerűbb annak a funkcionalitását átvinni a többire?