LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

2019ko udazkenean, Mail.ru Cloud iOS taldean itxaroten zen gertaera bat gertatu zen. Aplikazioen egoera iraunkorra biltegiratzeko datu-base nagusia oso exotikoa bihurtu da mugikorren mundurako Lightning memoria-mapatutako datu-basea (LMDB). Ebakiaren azpian haren berrikuspen zehatza eskaintzen dizugu lau zatitan. Lehenik eta behin, hitz egin dezagun hautu ez-huts eta zailaren arrazoiei buruz. Ondoren, LMDB arkitekturaren muinean dauden hiru zutabeak kontuan hartuko ditugu: memorian mapatutako fitxategiak, B+-zuhaitza, kopia-idazketa ikuspegia transakzionaltasuna eta multibertsioa ezartzeko. Azkenik, postrerako - zati praktikoa. Bertan, hainbat taula dituen datu-base eskema bat nola diseinatu eta inplementatu aztertuko dugu, indizea barne, maila baxuko gako-balioaren APIaren gainean.

Edukia

  1. Ezartzeko motibazioa
  2. LMDB Posizionamendua
  3. LMDBren hiru zutabe
    3.1. Balea #1. Memoriarekin mapatutako fitxategiak
    3.2. Balea #2. B+-zuhaitza
    3.3. Balea #3. Kopiatu-idazketa
  4. Datu-eskema bat diseinatzea gako-balioaren APIaren gainean
    4.1. Oinarrizko abstrakzioak
    4.2. Mahaiaren modelizazioa
    4.3. Taulen arteko erlazioak modelatzea

1. Ezartzeko motibazioa

2015ean urtebete, gure aplikazioaren interfazea zenbateraino geratzen den neurtzeko ardura hartu genuen. Hau arrazoi bategatik egin dugu. Kexa gehiago jaso ditugu batzuetan aplikazioak erabiltzaileen ekintzei erantzutea uzten duelako: ezin dira botoiak sakatu, zerrendak ez dira korritzen, etab. Neurketen mekanikari buruz esan AvitoTech-en, beraz, hemen zenbakien ordena bakarrik ematen dut.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Neurketaren emaitzak dutxa hotz bihurtu ziren guretzat. Agertu zen izozteek eragindako arazo askoz gehiago daudela beste edozein baino. Gertaera honetaz konturatu aurretik kalitatearen adierazle tekniko nagusia kraskadurarik gabekoa bazen, orduan fokuaren ondoren lekuz aldatuta izozterik gabe.

Eraikituta izozketak dituen aginte-panela eta gastatu ondoren kuantitatiboa и kalitatea haien arrazoien azterketa, etsai nagusia argi geratu zen - aplikazioaren hari nagusian exekutaturiko negozio logika astuna. Desohore honen erreakzio naturala lan-korronteetara sartzeko gogoa izan zen. Arazo hau sistematikoki konpontzeko, aktore arinetan oinarritutako hari anitzeko arkitekturara jo dugu. iOS mundurako bere egokitzapenari eskaini nion bi hari Twitter kolektiboan eta Habréri buruzko artikulua. Egungo kontakizunaren baitan, datu-basearen aukeraketan eragin zuten erabakiaren alderdi horiek azpimarratu nahi ditut.

Sistema antolatzeko aktore-ereduak bere gain hartzen du multithreading bere bigarren esentzia bihurtzen dela. Bertan dauden objektu modeloek korronteen mugak zeharkatzea gustatzen zaie. Eta hori ez dute egiten batzuetan eta han eta hemen, baina ia etengabe eta nonahi

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Datu-basea aurkezten den diagramako oinarrizko osagaietako bat da. Bere zeregin nagusia makro-eredua ezartzea da Datu-base partekatua. Enpresa munduan zerbitzuen arteko datuen sinkronizazioa antolatzeko erabiltzen bada, orduan aktoreen arkitekturaren kasuan - harien arteko datuak. Horrela, hari anitzeko ingurune batean lan egitean zailtasun minimoak ere eragingo ez zituen datu-base bat behar genuen. Bereziki, horrek esan nahi du bertatik lortutako objektuak gutxienez hari-seguruak izan behar direla, eta, hobeki, guztiz aldaezinak izan behar direla. Dakizuenez, azken hau aldi berean erabil daiteke hainbat harietatik inolako blokeorik erabili gabe, eta horrek eragin onuragarria du errendimenduan.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetanDatu-basearen aukeraketan eragin zuen bigarren faktore esanguratsua gure hodeiko APIa izan zen. Git-ek hartutako sinkronizazio ikuspegian inspiratu zen. Bera bezala, helburutzat genuen lineaz kanpoko lehen APIa, hodeiko bezeroentzat egokia dena. Suposatzen zen hodeiaren egoera osoa behin bakarrik aterako zutela eta, ondoren, kasu gehienetan sinkronizazioa gertatuko zela aldaketak zabalduz. Ala ere, aukera hau eremu teorikoan baino ez dago oraindik, eta bezeroek ez dute praktikan adabakiekin lan egiten ikasi. Hainbat arrazoi objektibo daude horretarako, eta, sarrera ez atzeratzeko, parentesiak utziko ditugu. Orain, askoz ere interes handiagoa duena API batek "A" esaten duenean eta bere kontsumitzaileak "B" esaten ez duenean gertatzen denari buruzko ikasgaiaren ondorio didaktikoak dira.

Beraz, git imajinatzen baduzu, pull komando bat exekutatzen denean, tokiko argazki batean adabakiak aplikatu beharrean, bere egoera osoa zerbitzariaren egoerarekin alderatzen duela, orduan sinkronizazioa hodeian nola gertatzen den jakiteko ideia nahiko zehatza izango duzu. bezeroak. Erraza da asmatzea ezartzeko, memorian bi DOM zuhaitz esleitu behar dituzula zerbitzari guztiei eta tokiko fitxategiei buruzko metainformazioarekin. Erabiltzaile batek 500 mila fitxategi gordetzen baditu hodeian, sinkronizatzeko beharrezkoa da milioi bat nodo dituzten bi zuhaitz birsortu eta suntsitzea. Baina nodo bakoitza azpiobjektuen grafiko bat duen agregatua da. Horren harira, profilaren emaitzak espero ziren. Kontuan izan da bateratze-algoritmoa kontuan hartu gabe ere, objektu txiki kopuru handi bat sortzeko eta, ondoren, suntsitzeko prozedurak zentimo polit bat kostatzen duela. Egoera larriagotu egiten da oinarrizko sinkronizazio-eragiketa kopuru handi batean sartuta dagoelako. erabiltzaileen scripten. Ondorioz, datu-base bat aukeratzeko bigarren irizpide garrantzitsua finkatzen dugu - CRUD eragiketak ezartzeko gaitasuna objektuen esleipen dinamikorik gabe.

Beste eskakizun batzuk tradizionalagoak dira eta haien zerrenda osoa honakoa da.

  1. Hariaren segurtasuna.
  2. Multiprozesaketa. Datu-basearen instantzia bera erabiltzeko nahiak agindutako egoera sinkronizatzeko harien artean ez ezik, baita aplikazio nagusiaren eta iOS luzapenen artean ere.
  3. Biltegiratutako entitateak objektu aldaezin gisa irudikatzeko gaitasuna
  4. CRUD eragiketen barruan esleipen dinamikorik ez.
  5. Oinarrizko propietateetarako transakzio-laguntza ACID: atomotasuna, koherentzia, isolamendua eta fidagarritasuna.
  6. Abiadura kasu ezagunenetan.

Baldintza multzo honekin, SQLite aukera ona izan zen eta izaten jarraitzen du. Hala ere, alternatiben azterketaren barruan, liburu batekin egin nuen topo "LevelDB-rekin hastea". Haren gidaritzapean, erreferente bat idatzi zen hodei errealeko eszenatokietan datu-base desberdinekin lanaren abiadura alderatuz. Emaitzek gure itxaropenik basatienak gainditu zituen. Kasurik ezagunenetan - kurtsorea fitxategi guztien zerrenda ordenatu batean eta direktorio jakin baterako fitxategi guztien zerrenda ordenatua lortzea - ​​LMDB SQLite baino 10 aldiz azkarragoa izan da. Aukera nabaria zen.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

2. LMDB Posizionamendua

LMDB oso liburutegi txikia da (10K errenkada baino ez) datu-baseen oinarrizko geruza baxuena inplementatzen duena: biltegiratzea.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Goiko diagramak erakusten du LMDB SQLiterekin alderatzea, maila altuagoak ere inplementatzen dituena, oro har ez dela zuzenagoa SQLite Core Datarekin baino. Lehiakide berdinen biltegiratze-motor berdinak aipatzea bidezkoagoa litzateke: BerkeleyDB, LevelDB, Sophia, RocksDB, etab. LMDB SQLite-ren biltegiratze-motor osagai gisa jarduten duten garapenak ere badaude. Horrelako lehen esperimentua 2012an izan zen gastatu LMDBren eskutik Howard Chu. Findings hain zirraragarria suertatu zen non bere ekimena OSS zaleek hartu zuten eta bere jarraipena pertsonan aurkitu zuen. LumoSQL. 2020ko urtarrilean, proiektu honen egilea Den Shearer izan zen aurkeztua LinuxConfAu-n.

LMDB aplikazioen datu-baseetarako motor gisa erabiltzen da batez ere. Liburutegiak bere itxura garatzaileei zor die OpenLDAP, oso pozik ez zeuden BerkeleyDB beren proiektuaren oinarri gisa. Liburutegi xume batetik abiatuta btree, Howard Chuk gure garaiko alternatiba ezagunenetako bat sortzeko gai izan zen. Istorio honi eskaini zion bere erreportaje oso polita, baita LMDBren barne egiturari ere. "Tximista memoria-mapatutako datu-basea". Biltegiratze-instalazioak konkistatzeko adibide ona Leonid Yuryev-ek (aka yleo) Positive Technologies-ek Highload 2015-en egindako txostenean "LMDB motorra txapeldun berezia da". Bertan, LMDBri buruz hitz egiten du ReOpenLDAP ezartzeko antzeko zeregin baten testuinguruan, eta LevelDB kritika konparatiboa jasan du dagoeneko. Inplementazioaren ondorioz, Positive Technologies are aktiboki garatzen ari den sardexka bat izan zuen MDBX ezaugarri oso zaporetsuekin, optimizazioekin eta akats zuzenketa.

LMDB biltegiratze gisa erabiltzen da askotan. Adibidez, Mozilla Firefox arakatzailea aukeratu hainbat beharretarako, eta, 9. bertsiotik hasita, Xcode hobetsi bere SQLite indizeak gordetzeko.

Mugikorren garapenaren munduan ere marka egin du motorrak. Bere erabileraren aztarnak izan daitezke aurkitu Telegramerako iOS bezeroan. LinkedIn are urrunago joan zen eta LMDB aukeratu zuen bere etxeko datuen cache-esparrurako biltegiratze lehenetsi gisa Rocket Data, horri buruz. esan 2016ko bere artikuluan.

LMDB arrakastaz borrokatzen ari da BerkeleyDBk utzitako nitxoan eguzkitan dagoen leku bat lortzeko Oracleren kontrolpean egon ostean. Liburutegia bere abiadura eta fidagarritasunagatik maite da, baita bere kideekin alderatuta ere. Dakizuenez, ez dago doako bazkaririk, eta LMDB eta SQLiteren artean aukeratzerakoan aurre egin beharko dion truke-off-a azpimarratu nahiko nuke. Goiko diagramak argi erakusten du nola lortzen den abiadura handitzea. Lehenik eta behin, ez dugu ordaintzen diskoaren biltegiratzearen gainean abstrakzio geruza gehigarriengatik. Argi dago arkitektura on batek oraindik ezin duela haiek gabe egin, eta ezinbestean agertuko dira aplikazioaren kodean, baina askoz sotilagoak izango dira. Ez dute edukiko aplikazio zehatz batek eskatzen ez dituen ezaugarriak, adibidez, SQL hizkuntzan kontsultak egiteko laguntza. Bigarrenik, diskorako biltegiratze-eskaeretan aplikazioen eragiketen mapaketa modu egokian ezartzea posible bihurtzen da. SQLite bada nire lanean batez besteko aplikazio baten batez besteko behar estatistikoetan oinarritzen da, orduan zuk, aplikazioen garatzaile gisa, ondo ezagutzen dituzu lan-kargaren eszenatoki nagusiak. Irtenbide produktiboagoa lortzeko, prezioa handitu beharko duzu bai hasierako irtenbidearen garapenagatik, bai ondorengo laguntzagatik.

3. LMDBren hiru zutabe

LMDBri txoritik begiratuta, sakontzeko ordua iritsi zen. Hurrengo hiru atalak biltegiratze-arkitekturaren oinarrian dauden zutabe nagusien azterketari eskainiko zaizkio:

  1. Memoria-mapatutako fitxategiak diskoarekin lan egiteko eta barneko datu-egiturak sinkronizatzeko mekanismo gisa.
  2. B+-zuhaitza gordetako datuen egituraren antolaketa gisa.
  3. Copy-on-write ACID transakzio-propietateak eta multibertsioa eskaintzeko ikuspegi gisa.

3.1. Balea #1. Memoriarekin mapatutako fitxategiak

Memoria-mapatutako fitxategiak hain elementu arkitektoniko garrantzitsuak dira, biltegiaren izenean ere agertzen baitira. Biltegiratutako informaziorako sarbidearen sinkronizazioaren arazoak eta sistema eragilearen esku geratzen dira. LMDBk ez du bere baitan inolako cacherik. Egilearen erabaki kontzientea da, mapatutako fitxategietako datuak zuzenean irakurtzeak motorraren inplementazioan izkin asko moztu ditzakezulako. Jarraian, horietako batzuen zerrenda osotik urrun dago.

  1. Datuen koherentzia mantentzea hainbat prozesutako harekin lan egitean biltegiratzeetan sistema eragilearen ardura bihurtzen da. Hurrengo atalean, mekanika hau xehetasunez eta irudiekin eztabaidatzen da.
  2. Cacherik ez egoteak esleipen dinamikoekin lotutako gainkostuetatik LMDB erabat ezabatzen du. Praktikan datuak irakurtzeak memoria birtualean helbide egokian erakuslea ezartzea dakar eta ezer gehiago. Zientzia fikzioa dirudi, baina biltegiratze-iturburu-kodean calloc-erako dei guztiak biltegiratze-konfigurazio funtzioan kontzentratzen dira.
  3. Cacherik ez egoteak sarbidearen sinkronizazioarekin lotutako blokeorik ez dagoela ere esan nahi du. Irakurleek, aldi berean irakurle kopuru arbitrario bat egon daitekeelarik, ez dute mutex bakar bat ere aurkitzen datuetara bidean. Hori dela eta, irakurketa-abiadurak eskalagarritasun lineal ideala du CPU kopuruaren arabera. LMDB-n, aldatzeko eragiketak soilik sinkronizatzen dira. Idazle bakarra egon daiteke aldi berean.
  4. Cachea eta sinkronizazio logika minimo batek hari anitzeko ingurune batean lan egitearekin lotutako errore mota oso konplexuak ezabatzen ditu. Usenix OSDI 2014 konferentzian datu-baseen azterketa interesgarri bi izan ziren: "Fitxategi-sistema guztiak ez dira berdinak: Crash-ekin bat datozen aplikazioak sortzearen konplexutasunari buruz" и "Dibertsiorako eta irabazietarako datu-baseak torturatzea". Horietatik informazioa lor dezakezu LMDB-ren aurrekaririk gabeko fidagarritasunari eta ACID transakzio-propietateen ia akatsik gabeko inplementazioari buruz, SQLite-k baino handiagoa dena.
  5. LMDB-ren minimalismoari esker, bere kodearen makinaren irudikapena prozesadorearen L1 cachean guztiz kokatu da, ondoriozko abiadura-ezaugarriekin.

Zoritxarrez, iOS-en, memorian mapatutako fitxategiekin, dena ez dago nahi bezain hodeirik gabe. Horiei lotutako gabeziei buruz modu kontzienteagoan hitz egiteko, beharrezkoa da sistema eragileetan mekanismo hau ezartzeko printzipio orokorrak gogoratzea.

Memorian mapatutako fitxategiei buruzko informazio orokorra

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetanExekutatzen den aplikazio bakoitzarekin, sistema eragileak prozesu izeneko entitate bat lotzen du. Prozesu bakoitzari ondoko helbide sorta bat esleitzen zaio eta bertan funtzionatzeko behar duen guztia jartzen du. Helbide baxuenetan kodea eta datu eta baliabide gogor kodetuak dituzten atalak daude. Ondoren, helbide-espazio dinamikoaren bloke gero eta handiagoa dator, heap izenarekin ezaguna zaiguna. Programaren funtzionamenduan zehar agertzen diren entitateen helbideak jasotzen ditu. Goialdean aplikazio pilak erabiltzen duen memoria-eremua dago. Hazten edo uzkurtzen da; hau da, bere tamainak ere izaera dinamikoa du. Pila eta pila bata bestea bultzatzea eta oztopatzea saihesteko, helbide-espazioaren mutur ezberdinetan daude.​ Goiko eta beheko bi atal dinamikoen artean zulo bat dago. Sistema eragileak erdiko atal honetako helbideak erabiltzen ditu prozesuarekin hainbat entitate lotzeko. Bereziki, helbide-multzo jarraitu jakin bat diskoko fitxategi batekin lotu dezake. Fitxategi horri memoria-mapped deitzen zaio

Prozesuari esleitutako helbide-espazioa izugarria da. Teorian, helbide kopurua erakuslearen tamainak soilik mugatzen du, sistemaren bit-ahalmenak zehazten baitu. Memoria fisikoa 1-to-1 mapatuko balitz, lehenengo prozesuak RAM osoa irentsiko luke, eta ez litzateke hitz egingo multiatazaz.

Hala ere, gure esperientziatik badakigu sistema eragile modernoek nahi adina prozesu aldi berean exekutatu ditzaketela. Hori posible da, papereko prozesuei memoria asko esleitzen dietelako soilik, baina errealitatean memoria fisiko nagusian kargatzen dute hemen eta orain eskatzen den zati hori bakarrik. Horregatik, prozesu bati lotutako memoriari birtuala deritzo.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Sistema eragileak memoria birtuala eta fisikoa tamaina jakin bateko orrialdetan antolatzen ditu. Memoria birtualaren orri jakin bat eskatu bezain laster, sistema eragileak memoria fisikoan kargatzen du eta taula berezi batean lotzen ditu. Doako zirrikiturik ez badago, aurretik kargatutako orrietako bat diskoan kopiatzen da, eta eskatzen duenak bere lekua hartzen du. Laster itzuliko dugun prozedura honi swapping deitzen zaio. Beheko irudian deskribatutako prozesua azaltzen da. Bertan, 0 helbidea duen A orria kargatu eta 4 helbidea duen memoria-orri nagusian jarri zen. Gertaera hori 0 zenbakiko gelaxkako korrespondentzia taulan islatu zen.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Istorioa berdina da memorian mapatutako fitxategiekin. Logikoa denez, helbide birtualean etengabe eta guztiz kokatzen omen dira. Hala ere, memoria fisikoa orrialdez orrialde sartzen dute eta eskatuz gero. Horrelako orrialdeen aldaketa diskoko fitxategiarekin sinkronizatzen da. Modu honetan, fitxategien I/O egin dezakezu memoriako byteekin lan eginda; aldaketa guztiak automatikoki transferituko ditu sistema eragilearen nukleoak iturburu fitxategira.

Beheko irudiak erakusten du nola LMDBk bere egoera sinkronizatzen duen prozesu ezberdinetako datu-basearekin lan egiten duenean. Prozesu desberdinen memoria birtuala fitxategi berean mapatuz, de facto sistema eragilea behartzen dugu beren helbide-espazioen bloke batzuk modu iragankorrean sinkronizatzera, LMDB itxura duen tokian.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Ñabardura garrantzitsu bat da LMDBk, lehenespenez, idazteko sistema-deien mekanismoaren bidez datu-fitxategia aldatzen duela eta fitxategia bera irakurtzeko moduan bistaratzen duela. Planteamendu honek bi ondorio garrantzitsu ditu.

Lehenengo ondorioa sistema eragile guztietan komuna da. Bere funtsa datu-baseari nahi gabeko kalteen aurkako babesa gehitzea da kode okerren bidez. Dakizuenez, prozesu baten jarraibide exekutagarriak doakoak dira datuak bere helbide-espazioko edozein lekutatik sartzeko. Aldi berean, gogoratu berri dugun bezala, fitxategi bat irakurketa-idazketa moduan bistaratzeak esan nahi du edozein instrukzio ere alda dezakeela. Hori akatsez egiten badu, adibidez, matrize-elementu bat existitzen ez den indize batean gainidazten saiatzen bada, nahi gabe helbide honetara mapatutako fitxategia alda dezake eta horrek datu-basea hondatuko du. Fitxategia irakurtzeko moduan bistaratzen bada, dagokion helbide-espazioa aldatzeko saiakerak programaren larrialdi-amaiera ekarriko du seinale batekin. SIGSEGV, eta fitxategiak bere horretan jarraituko du.

Bigarren ondorioa iOS-en berariazkoa da dagoeneko. Ez egileak ez beste iturri batek ez du esplizituki aipatzen, baina hori gabe LMDB ez litzateke egokia izango sistema eragile mugikor honetan exekutatzeko. Hurrengo atala bere hausnarketari eskainia dago.

Memorian mapatutako fitxategien berezitasunak iOS-en

2018an WWDCn erreportaje zoragarria izan zen "iOS Memory Deep Dive". Esaten digunez, iOS-en, memoria fisikoan dauden orrialde guztiak 3 motatakoak dira: zikinak, konprimituak eta garbiak.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Memoria garbia memoria fisikotik minik gabe deskargatu daitekeen orrialdeen bilduma da. Daukaten datuak behar bezala kargatu daitezke jatorrizko iturrietatik. Irakurtzeko soilik memorian mapatutako fitxategiak kategoria honetan sartzen dira. iOS-ek ez du inolako beldurrik memoriatik fitxategi batera esleitutako orriak edozein unetan deskargatzeko, diskoko fitxategiarekin sinkronizatzea bermatuta dagoelako.

Aldatutako orrialde guztiek memoria zikinean amaitzen dute, jatorriz non kokatuta zeuden. Bereziki, horiekin lotutako memoria birtualean idatziz aldatutako memoria-mapatutako fitxategiak horrela sailkatuko dira. LMDB irekitzea banderarekin MDB_WRITEMAP, aldaketak egin ondoren, hori pertsonalki egiaztatu dezakezu.​

Aplikazio bat memoria fisiko gehiegi hartzen hasten den bezain laster, iOS-ek orrialde zikinen konpresiopean jartzen du. Orri zikinek eta konprimituek hartzen duten memoria osoa aplikazioaren memoria-aztarna deritzona osatzen du. Atalase-balio jakin batera iristen denean, OOM hiltzaile sistemaren deabrua prozesuaren ondoren dator eta indarrez amaitzen du. Hau da iOS-en berezitasuna mahaigaineko sistema eragileekin alderatuta. Aitzitik, memoria-aztarna murriztea orriak memoria fisikotik diskora aldatuz ez da iOS-en eskaintzen. Arrazoiak soilik asma daitezke. Agian orriak diskora eta atzera era intentsiboan mugitzeko prozedurak energia gehiegi kontsumitzen du gailu mugikorrentzat, edo iOS-ek SSD unitateetan zelulak berridazteko baliabidea gordetzen du, edo agian diseinatzaileak ez zeuden sistemaren errendimendu orokorrarekin konforme, non dena dagoen. etengabe trukatuta. Dena den, gertakariak egitate izaten jarraitzen du.

Berri ona, lehen aipatu duguna, LMDBk lehenespenez ez duela mmap mekanismoa erabiltzen fitxategiak eguneratzeko. Horrek esan nahi du bistaratzen diren datuak iOS-ek memoria garbi gisa sailkatzen dituela eta ez duela memoria-aztarna laguntzen. Hori egiazta dezakezu VM Tracker izeneko Xcode tresna erabiliz. Beheko pantaila-argazkiak Cloud aplikazioaren iOS memoria birtualaren egoera erakusten du funtzionamenduan zehar. Hasieran, 2 LMDB instantzia hasi ziren bertan. Lehenengoari bere fitxategia memoria birtualeko 1GiB-n bistaratzeko baimena eman zitzaion, bigarrenari - 512MiB. Biltegiratze biek memoria egoiliarren kopuru jakin bat okupatzen duten arren, bietako batek ere ez du tamaina zikinik laguntzen.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Eta orain berri txarren garaia da. 64 biteko mahaigaineko sistema eragileetako truke-mekanismoari esker, prozesu bakoitzak bere balizko trukerako disko gogorreko espazio libreak ahalbidetzen duen adina helbide birtual okupa dezake. iOS-en swap konpresioarekin ordezkatzeak maximo teorikoa zeharo murrizten du. Orain prozesu bizi guztiak (RAM irakurtzeko) memorian sartu behar dira, eta kabitzen ez diren guztiak amaitzera behartu behar dira. Hau goian aipatu bezala adierazten da txostena, eta dokumentazio ofiziala. Ondorioz, iOS-ek asko mugatzen du mmap bidez esleitzeko dagoen memoria kopurua. Hemen Hemen Sistema-dei hau erabiliz gailu ezberdinetan esleitu daitekeen memoria-kopuruaren muga enpirikoak ikus ditzakezu. Smartphone modelo modernoenetan, iOS eskuzabal bihurtu da 2 gigabytez, eta iPad-en bertsio gorenetan - 4. Praktikan, noski, onartzen diren gailu modelo baxuenetan zentratu behar duzu, non dena oso triste dagoen. Are okerragoa dena, aplikazioaren memoria-egoera VM Tracker-en begiratuta, LMDB memoria-mapatuta dagoela dioen bakarra urrun dagoela ikusiko duzu. Zati onak jaten dituzte sistemaren esleitzaileak, baliabide-fitxategiak, irudi-esparruak eta beste harrapari txikiago batzuek.

Hodeian egindako esperimentuen emaitzetan oinarrituta, LMDB-k esleitutako memoriarako konpromiso-balio hauetara iritsi ginen: 384 megabyte 32 biteko gailuetarako eta 768 64 biteko gailuetarako. Bolumen hori agortu ondoren, aldaketa-eragiketa guztiak kodearekin amaitzen hasten dira MDB_MAP_FULL. Gure jarraipenean horrelako akatsak ikusten ditugu, baina nahikoa txikiak dira fase honetan alde batera utzi ahal izateko.

Biltegiratzeak gehiegizko memoria kontsumitzearen arrazoi ez den argia iraupen luzeko transakzioak izan daitezke. Bi fenomeno hauek nola lotzen diren ulertzeko, LMDBren gainerako bi zutabeak kontuan hartuta lagunduko digu.

3.2. Balea #2. B+-zuhaitza

Gako-balioen biltegiratze baten gainean taulak emulatzeko, eragiketa hauek egon behar dute bere APIan:

  1. Elementu berri bat txertatzea.
  2. Bilatu gako jakin batekin elementu bat.
  3. Elementu bat kentzea.
  4. Itera ezazu gakoen tarteetan ordenatzen diren ordenan.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetanLau eragiketak erraz ezar ditzakeen datu-egiturarik errazena bilaketa-zuhaitz bitarra da. Bere nodo bakoitzak gako umeen azpimultzo osoa bi azpizuhaitzetan banatzen duen gako bat adierazten du. Ezkerrekoak gurasoa baino txikiagoak dira, eta eskuinekoan handiagoak direnak. Gako-multzo ordenatu bat lortzea zuhaitzen zeharkaldi klasikoetako baten bidez lortzen da

Zuhaitz bitarrak diskoan oinarritutako datu-egitura gisa eraginkorrak izatea eragozten duten oinarrizko bi akats dituzte. Lehenik eta behin, haien oreka-maila ezustekoa da. Arrisku handia dago adar ezberdinen altuerak asko desberdinak izan daitezkeen zuhaitzak lortzeko, eta horrek nabarmen okertzen du bilaketaren konplexutasun algoritmikoa espero denarekin alderatuta. Bigarrenik, nodoen arteko lotura gurutzatuen ugaritasunak memoriako tokiko zuhaitz bitarrei kentzen die.Nodo itxiak (haien arteko konexioei dagokienez) orri guztiz ezberdinetan kokatu daitezke memoria birtualean. Ondorioz, zuhaitz bateko aldameneko hainbat nodo zeharkatzeak pareko orrialde kopuru bat bisitatzea eska dezake. Arazo bat da zuhaitz bitarren eraginkortasunaz hitz egiten dugunean ere memoriako datu-egitura gisa, prozesadorearen cacheko orrialdeak etengabe biratzea ez baita plazer merke bat. Diskotik nodoekin lotutako orriak maiz berreskuratzeko orduan, egoera erabat bihurtzen da tamalgarria.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetanB-zuhaitzek, zuhaitz bitarien bilakaera izanik, aurreko paragrafoan identifikatutako arazoak ebazten dituzte. Lehenik eta behin, beren burua orekatzen dute. Bigarrenik, haien nodo bakoitzak gako umeen multzoa ez 2tan banatzen du, M azpimultzo ordenatuetan baizik, eta M zenbakia nahiko handia izan daiteke, ehunka edo milakaren ingurukoa.

Horrela:

  1. Nodo bakoitzak dagoeneko agindutako gako kopuru handia dauka eta zuhaitzak oso laburrak dira.
  2. Zuhaitzek memorian tokiko propietatea eskuratzen dute, balioz hurbil dauden gakoak modu naturalean elkarren ondoan kokatzen baitira nodo berdinetan edo aldamenean.
  3. Bilaketa-eragiketa batean zuhaitz batetik jaisten denean garraio-nodo kopurua murrizten da.
  4. Barruti-kontsultetan irakurtzen diren helburu-nodoen kopurua murrizten da, horietako bakoitzak dagoeneko ordenatutako gako kopuru handia baitu.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

LMDB-k B+ zuhaitz izeneko B zuhaitzaren aldaera bat erabiltzen du datuak gordetzeko. Goiko diagramak bertan dauden hiru nodo motak erakusten ditu:

  1. Goialdean erroa dago. Biltegi baten barruan datu-basearen kontzeptua baino ez du gauzatzen. LMDB instantzia baten barruan, mapatutako helbide birtual-espazio bat partekatzen duten hainbat datu-base sor ditzakezu. Horietako bakoitza bere errotik hasten da.
  2. Maila baxuenean hostoak daude. Haiek eta haiek bakarrik dituzte datu-basean gordetako gako-balio bikoteak. Bide batez, hau da B+-zuhaitzen berezitasuna. B-zuhaitz erregular batek balio-zatiak maila guztietako nodoetan gordetzen baditu, orduan B+ aldakuntza baxuenean bakarrik dago. Gertaera hori konponduta, LMDBn erabiltzen den zuhaitzaren azpimotari B-zuhaitz besterik gabe deituko diogu.
  3. Erroaren eta hostoen artean 0 maila tekniko edo gehiago daude nabigazio (adar) nodoekin. Beraien zeregina ordenatutako gako multzoa hostoen artean banatzea da.

Fisikoki, nodoak aurrez zehaztutako luzera duten memoria blokeak dira. Haien tamaina sistema eragileko memoria orrien tamainaren multiploa da, goian aipatu duguna. Nodoen egitura behean erakusten da. Goiburuak meta informazioa dauka, eta horietatik agerikoena adibidez checksum da. Ondoren, datuak dituzten gelaxkak dauden desplazamenduei buruzko informazioa dator. Datuak gakoak izan daitezke, nabigazio-nodoez ari bagara, edo gako-balio bikote osoak hostoen kasuan.​ Orrialdeen egiturari buruz gehiago irakurri dezakezu lanean. "Errendimendu handiko gako-balioen biltegien ebaluazioa".

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Orrialde-nodoen barneko edukia landu ondoren, LMDB B zuhaitza modu sinplifikatuan irudikatuko dugu hurrengo formularioan.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Nodoak dituzten orriak sekuentzialki kokatzen dira diskoan. Zenbaki handiagoko orrialdeak fitxategiaren amaieran kokatzen dira. Meta orrialdeak zuhaitz guztien sustraiak aurki daitezkeen desplazamenduei buruzko informazioa du. Fitxategi bat irekitzean, LMDBk fitxategia orriz orrialde eskaneatzen du amaieratik hasierara baliozko meta-orri baten bila eta horren bidez lehendik dauden datu-baseak aurkitzen ditu.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Orain, datuen antolaketaren egitura logiko eta fisikoaren ideia bat izanda, LMDBren hirugarren zutabea aztertzera pasa gaitezke. Bere laguntzarekin biltegiratze-aldaketa guztiak transakzionalki eta elkarrengandik isolatuta gertatzen dira, datu-baseari osotasunean multibertsioaren propietatea emanez.

3.3. Balea #3. Kopiatu-idazketa

B-zuhaitz-eragiketa batzuek bere nodoetan aldaketa batzuk egitea dakar. Adibide bat gako berri bat gehitzea da dagoeneko gehienezko ahalmena lortu duen nodo bati. Kasu honetan, beharrezkoa da, lehenik eta behin, nodoa bitan zatitzea, eta, bigarrenik, bere gurasoan hazten ari den nodo haur berrirako esteka gehitzea. Prozedura hau oso arriskutsua da. Arrazoiren batengatik (istripua, elektrizitatea etetea, etab.) serieko aldaketen zati bat bakarrik gertatzen bada, zuhaitza egoera ez-koherentean geratuko da.

Datu-base bat akats-tolerantea egiteko irtenbide tradizional bat diskoko datu-egitura gehigarri bat gehitzea da B-zuhaitzaren ondoan - transakzioen erregistroa, idazketa aurreratuaren erregistroa (WAL) gisa ere ezaguna. Fitxategi bat da, zeinaren amaieran aurreikusitako eragiketa zorrozki idazten den B-zuhaitza bera aldatu aurretik. Horrela, autodiagnostikoan datuen ustelkeria hautematen bada, datu-baseak erregistroa kontsultatzen du bere burua ordenatzeko.

LMDBk beste metodo bat aukeratu du akatsak jasateko mekanismo gisa, copy-on-write izenekoa. Bere funtsa da lehendik dagoen orrialde batean datuak eguneratu beharrean, lehenik osorik kopiatzen dituela eta kopian aldaketa guztiak egiten dituela.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Ondoren, eguneratutako datuak eskuragarri egon daitezen, beharrezkoa da bere nodo nagusian uneko bihurtu den nodoarekiko esteka aldatzea. Horretarako ere aldatu behar denez, aurretik ere kopiatzen da. Prozesuak modu errekurtsiboan jarraitzen du erroraino. Aldatzeko azken gauza meta orrialdeko datuak dira.​​

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Eguneratze-prozeduran prozesuak bat-batean huts egiten badu, ez da meta orri berririk sortuko edo ez da diskoan guztiz idatziko, eta bere kontrol-sumuma okerra izango da. Bi kasu hauetako batean, orrialde berriak ezin izango dira iritsi, baina zaharrei ez zaie eragingo. Horrek ezabatzen du LMDB-k erregistroa aurretik idazteko beharra datuen koherentzia mantentzeko. De facto, goian deskribatutako diskoan datuak biltegiratzeko egiturak bere funtzioa hartzen du aldi berean. Transakzioen erregistro espliziturik eza datuen irakurketa abiadura handia eskaintzen duen LMDBren ezaugarrietako bat da

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Ondorioz egindako diseinuak, eranskin-bakarrik B-zuhaitza deritzona, transakzioen isolamendua eta bertsio anitzeko aukera ematen du. LMDBn, irekitako transakzio bakoitza unean dagokion zuhaitz-erroarekin lotuta dago. Transakzioa amaitu arte, harekin lotutako zuhaitzaren orriak ez dira inoiz aldatuko edo berrerabiliko datuen bertsio berrietarako. Horrela, nahi duzun denboran lan egin dezakezu momentuan garrantzitsua zen datu multzoarekin. transakzioa ireki zen, nahiz eta biltegiratzea aktiboki eguneratzen jarraitzen duen momentu honetan. Hau da multibertsioaren funtsa, LMDB gure maitearentzat datu-iturri aproposa bihurtuz UICollectionView. Transakzio bat ireki ondoren, ez dago aplikazioaren memoria-aztarna handitu beharrik, uneko datuak azkar ponpatuz memoriako egitura batzuetan, ezer gabe geratzeko beldurrez. Ezaugarri honek LMDB bereizten du SQLite berarengandik, ezin baita erabateko isolamenduz harro. Azken honetan bi transakzio ireki eta horietako batean erregistro jakin bat ezabatu ondoren, ezin izango da erregistro bera lortu geratzen den bigarrenaren barruan.

Txanponaren aldea memoria birtualaren kontsumoa nabarmen handiagoa da. Diapositibak datu-basearen egitura nolakoa izango den erakusten du aldi berean aldatzen bada 3 irakurketa-transakzio irekita datu-basearen bertsio desberdinei begira. LMDBk ezin dituenez uneko transakzioekin lotutako erroetatik eskura daitezkeen nodoak berrerabili, dendak ez du beste laugarren erro bat memorian esleitzea eta berriro ere haren azpian aldatutako orrialdeak klonatu.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Hemen komenigarria litzateke memorian mapatutako fitxategiei buruzko atala gogoratzea. Badirudi memoria birtualaren kontsumo gehigarriak ez gaituela asko kezkatu behar, ez baitu aplikazioaren memoria-aztarna laguntzen. Hala ere, aldi berean, adierazi zen iOS oso zikorrak dela esleitzerakoan, eta ezin dugu, zerbitzari edo mahaigainean bezala, 1 terabyte-ko LMDB eskualde bat eman eta ez dugu funtzio honetan batere pentsatu. Ahal izanez gero, transakzioen bizitza ahalik eta laburrena egiten saiatu beharko zenuke.

4. Datu-eskema bat diseinatzea gako-balioaren APIaren gainean

Hasi gaitezen gure APIaren analisia LMDBk eskaintzen dituen oinarrizko abstrakzioei erreparatuz: ingurunea eta datu-baseak, gakoak eta balioak, transakzioak eta kurtsoreak.

Kode-zerrendei buruzko ohar bat

LMDB API publikoko funtzio guztiek beren lanaren emaitza errore-kode baten moduan itzultzen dute, baina ondorengo zerrenda guztietan bere egiaztapena ez da laburtasunaren mesedetan baztertzen. Praktikan, gurea ere erabili dugu biltegiarekin elkarreragiteko. sardexka C++ bilgarriak lmdbxx, zeinetan erroreak C++ salbuespen gisa gauzatzen diren.

LMDB iOS edo macOSerako proiektu batera konektatzeko modurik azkarrena denez, nire CocoaPod iradokitzen dut POSLMDB.

4.1. Oinarrizko abstrakzioak

Ingurumena

Egitura MDB_env LMDBren barne-egoeraren biltegia da. Aurrizkiaren funtzio familia mdb_env bere propietate batzuk konfiguratzeko aukera ematen du. Kasurik errazenean, motorraren hasierak itxura hau du.

mdb_env_create(env);​
mdb_env_set_map_size(*env, 1024 * 1024 * 512)​
mdb_env_open(*env, path.UTF8String, MDB_NOTLS, 0664);

Mail.ru Cloud aplikazioan, bi parametroren balio lehenetsiak aldatu ditugu.

Lehenengoa biltegiratze-fitxategia mapatzen den helbide birtualeko espazioaren tamaina da. Zoritxarrez, gailu berean ere, balio espezifikoa nabarmen alda daiteke korrika batetik bestera. iOS-en ezaugarri hau kontuan hartzeko, biltegiratze bolumen maximoa dinamikoki hautatzen da. Balio jakin batetik abiatuta, sekuentzialki erdira murrizten da funtziora arte mdb_env_open ez du emaitza desberdina itzuliko ENOMEM. Teorian, alderantzizko modua ere badago: lehenik eta behin memoria minimo bat esleitu motorra, eta gero, akatsak jasotzen direnean, MDB_MAP_FULL, handitu. Hala ere, askoz arantzatsuagoa da. Arrazoia funtzioa erabiliz memoria berriro esleitzeko (remapa) prozedura da mdb_env_set_map_size Motorretik aldez aurretik jasotako entitate guztiak (kurtsoreak, transakzioak, gakoak eta balioak) baliogabetzen ditu. Kodean gertaeren txanda hau kontuan hartzeak bere konplikazio nabarmena ekarriko du. Hala ere, zuretzako memoria birtuala oso garrantzitsua bada, hori izan daiteke urrun joan den sardexka gertutik aztertzeko arrazoia. MDBX, non iragarritako ezaugarrien artean "hegan datu-basearen tamainaren doikuntza automatikoa" dagoen.

Bigarren parametroak, balio lehenetsia ez zitzaigun egokitzen, hariaren segurtasuna bermatzeko mekanika arautzen du. Zoritxarrez, gutxienez iOS 10-k arazoak ditu haria biltegiratzeko tokiko laguntzarekin. Hori dela eta, goiko adibidean, biltegia banderarekin irekitzen da MDB_NOTLS. Honetaz gain, beharrezkoa ere bazen sardexka C++ bilgarria lmdbxxatributu honekin eta bertan dauden aldagaiak mozteko.

Datu baseak

Datu-basea B-zuhaitzaren instantzia bereizia da, goian aipatu duguna. Bere irekiera transakzio baten barruan gertatzen da, hasieran arraro samarra dirudi.

MDB_txn *txn;​
MDB_dbi dbi;​
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);​
mdb_dbi_open(txn, NULL, MDB_CREATE, &dbi);​
mdb_txn_abort(txn);

Izan ere, LMDB-ko transakzio bat biltegiratze-entitate bat da, ez datu-base-entitate zehatz bat. Kontzeptu honek datu-base ezberdinetan dauden entitateetan eragiketa atomikoak egiteko aukera ematen du. Teorian, honek datu-base ezberdinen forman taulak modelatzeko aukera zabaltzen du, baina garai batean beste bide bat hartu nuen, jarraian zehatz-mehatz azalduta.

Gakoak eta balioak

Egitura MDB_val gakoaren eta balioaren kontzeptua modelatzen du. Biltegiak ez du ideiarik haien semantikari buruz. Berarentzat, beste zerbait tamaina jakin bateko byte sorta bat besterik ez da. Gehienezko gakoaren tamaina 512 byte da.

typedef struct MDB_val {​
    size_t mv_size;​
    void *mv_data;​
} MDB_val;​​

Konparagailu bat erabiliz, dendak gakoak goranzko ordenan ordenatzen ditu. Ez baduzu zurea ordezkatzen, lehenetsitakoa erabiliko da, ordena lexikografikoan bytez byte ordenatzen dituena.

Transakzioak

Transakzio-egitura xehetasunez deskribatzen da aurreko kapitulua, beraz, hemen laburki errepikatuko ditut haien propietate nagusiak:

  1. Oinarrizko propietate guztiak onartzen ditu ACID: atomotasuna, koherentzia, isolamendua eta fidagarritasuna. Ezin dut saihestu MDBX-n konpondu zen macOS eta iOS-en iraunkortasunari dagokionez akats bat dagoela. Gehiago irakur dezakezu haien README.
  2. Multithreading-aren ikuspegia "idazle bakarra / irakurle anitz" eskemak deskribatzen du. Idazleek elkar blokeatzen dute, baina ez dituzte irakurleak blokeatzen. Irakurleek ez dituzte idazleak ez elkar blokeatzen.
  3. Habiaratutako transakzioetarako laguntza.
  4. Bertsio anitzeko euskarria.

Multibertsioa LMDB-en hain ona da, ekintzan erakutsi nahi dudala. Beheko kodean ikus dezakezu transakzio bakoitzak ireki zen unean unean zegoen datu-basearen bertsioarekin funtzionatzen duela, ondorengo aldaketa guztietatik erabat isolatuta. Biltegiratzea hasteak eta proba-erregistro bat gehitzeak ez du ezer interesgarririk adierazten, beraz, erritual hauek spoilerren azpian geratzen dira.

Probako sarrera bat gehitzea

MDB_env *env;
MDB_dbi dbi;
MDB_txn *txn;

mdb_env_create(&env);
mdb_env_open(env, "./testdb", MDB_NOTLS, 0664);

mdb_txn_begin(env, NULL, 0, &txn);
mdb_dbi_open(txn, NULL, 0, &dbi);
mdb_txn_abort(txn);

char k = 'k';
MDB_val key;
key.mv_size = sizeof(k);
key.mv_data = (void *)&k;

int v = 997;
MDB_val value;
value.mv_size = sizeof(v);
value.mv_data = (void *)&v;

mdb_txn_begin(env, NULL, 0, &txn);
mdb_put(txn, dbi, &key, &value, MDB_NOOVERWRITE);
mdb_txn_commit(txn);

MDB_txn *txn1, *txn2, *txn3;
MDB_val val;

// Открываем 2 транзакции, каждая из которых смотрит
// на версию базы данных с одной записью.
mdb_txn_begin(env, NULL, 0, &txn1); // read-write
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn2); // read-only

// В рамках первой транзакции удаляем из базы данных существующую в ней запись.
mdb_del(txn1, dbi, &key, NULL);
// Фиксируем удаление.
mdb_txn_commit(txn1);

// Открываем третью транзакцию, которая смотрит на
// актуальную версию базы данных, где записи уже нет.
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn3);
// Убеждаемся, что запись по искомому ключу уже не существует.
assert(mdb_get(txn3, dbi, &key, &val) == MDB_NOTFOUND);
// Завершаем транзакцию.
mdb_txn_abort(txn3);

// Убеждаемся, что в рамках второй транзакции, открытой на момент
// существования записи в базе данных, её всё ещё можно найти по ключу.
assert(mdb_get(txn2, dbi, &key, &val) == MDB_SUCCESS);
// Проверяем, что по ключу получен не абы какой мусор, а валидные данные.
assert(*(int *)val.mv_data == 997);
// Завершаем транзакцию, работающей хоть и с устаревшей, но консистентной базой данных.
mdb_txn_abort(txn2);

Gomendatzen dizut SQLite-rekin trikimailu bera probatzea eta ea zer gertatzen den.

Multibertsioak abantaila oso politak dakarzkio iOS garatzaile baten bizitzari. Propietate hau erabiliz, pantaila-inprimakietarako datu-iturburuaren eguneratze-tasa erraz eta naturalean doi dezakezu, erabiltzailearen esperientzia kontuan hartuta. Adibidez, har dezagun Mail.ru Cloud aplikazioaren ezaugarri bat, hala nola sistemako multimedia-galeriako edukia automatikoki kargatzea. Konexio onarekin, bezeroak segundoko hainbat argazki gehitzeko gai da zerbitzariari. Deskarga bakoitzaren ondoren eguneratzen baduzu UICollectionView erabiltzailearen hodeian multimedia edukiarekin, prozesu honetan zehar 60 fps eta korritze leuna ahaztu ditzakezu. Pantaila maiz eguneratzea saihesteko, nolabait mugatu behar duzu azpiko datuen aldaketaren abiadura UICollectionViewDataSource.

Datu-baseak ez badu multibertsioa onartzen eta uneko uneko egoerarekin soilik lan egiteko aukera ematen badu, datuen argazki denboran egonkor bat sortzeko, kopiatu behar duzu memoriako datu-egitura batera edo aldi baterako taula batera. Planteamendu horietako edozein oso garestia da. Memorian biltegiratzeari dagokionez, kostuak lortzen ditugu bai memorian, eraikitako objektuak gordetzeak eragindakoak, bai denboran, ORM eraldaketa erredundanteekin lotutakoak. Behin-behineko mahaiari dagokionez, plazer are garestiagoa da, kasu ez hutsaletan bakarrik zentzua duena.

LMDB-ren bertsio anitzeko irtenbideak datu-iturburu egonkorra mantentzeko arazoa oso modu dotorean konpontzen du. Nahikoa da transakzio bat irekitzea eta listo - osatu arte, datu multzoa konponduko dela bermatuta dago. Eguneratze-abiaduraren logika aurkezpen-geruzaren esku dago orain, baliabide esanguratsuen gainkosturik gabe.

Kurtsoreak

Kurtsoreek gako-balio bikoteen gainean iterazio ordenatua egiteko mekanismoa eskaintzen dute B zuhaitzen zeharkaldiaren bidez. Horiek gabe, ezinezkoa izango litzateke datu-baseko taulak modu eraginkorrean modelatzea, orain jotzen duguna.

4.2. Mahaiaren modelizazioa

Gakoen ordenamenduaren propietateak oinarrizko abstrakzioen gainean goi-mailako abstrakzio bat eraikitzeko aukera ematen du, adibidez, taula bat. Demagun prozesu hau hodeiko bezero baten taula nagusiaren adibidea erabiliz, erabiltzailearen fitxategi eta karpeta guztiei buruzko informazioa gordetzen duena.

Taula eskema

Karpeta-zuhaitza duen taula-egitura egokitu behar den agertoki arruntetako bat direktorioa jakin batean kokatutako elementu guztiak hautatzea da. Datuak antolatzeko eredu on bat mota honetako kontsulta eraginkorrak egiteko da. Adjacency zerrenda. Gako-balioen biltegiratzearen gainean ezartzeko, beharrezkoa da fitxategien eta karpeten gakoak ordenatzea, gurasoen direktorioko kidetasunaren arabera taldekatuta egon daitezen. Horrez gain, direktorioaren edukia Windows erabiltzailearentzat ezaguna den moduan bistaratzeko (lehenengo karpetak, ondoren fitxategiak, biak alfabetikoki ordenatuta), beharrezkoa da dagozkion eremu osagarriak gakoan sartu.

Beheko irudiak erakusten du nola, esku artean duzun zereginaren arabera, gakoen irudikapena byte-matrize moduan izan daitekeen. Direktorio nagusiaren identifikatzailea duten byteak (gorria) jartzen dira lehenik, ondoren motarekin (berdea) eta buztanean izenarekin (urdina) LMDB konparagailu lehenetsiaren arabera ordenatuta lexikografikoki ordenatuta, ordenatuta daude. behar den modua. Aurrizki gorri bera duten gakoak sekuentzialki zeharkatzeak haien balio elkartuak ematen dizkigu erabiltzailearen interfazean (eskuinean) bistaratu behar diren ordenan, osteko prozesamendu gehigarririk behar izan gabe.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Gakoak eta balioak seriatzea

Munduan objektuak serializatzeko metodo asko asmatu dira. Abiadura beste baldintzarik ez genuenez, ahalik eta azkarrena aukeratu genuen guretzat: C lengoaia-egituraren instantzia batek okupatzen duen memoriaren zabortegia. Horrela, direktorioa elementu baten gakoa honako egitura honekin modelatu daiteke. NodeKey.

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameBuffer[256];​
} NodeKey;

Gorde NodeKey objektuan behar den biltegian MDB_val kokatu datu-erakuslea egituraren hasierako helbidean, eta kalkulatu haien tamaina funtzioarekin sizeof.

MDB_val serialize(NodeKey * const key) {
    return MDB_val {
        .mv_size = sizeof(NodeKey),
        .mv_data = (void *)key
    };
}

Datu-baseen aukeraketa-irizpideei buruzko lehen kapituluan, CRUD eragiketen barruan esleipen dinamikoak minimizatzea aipatu nuen hautapen-faktore garrantzitsu gisa. Funtzio-kodea serialize erakusten du nola LMDB-ren kasuan guztiz saihestu daitezkeen erregistro berriak datu-basean sartzean. Zerbitzaritik sarrerako byte-matrizea pila-egituretan eraldatzen da lehenik, eta gero hutsalki biltegiratzera isurtzen dira. LMDB barruan esleipen dinamikorik ere ez dagoela kontuan hartuta, egoera zoragarria lor dezakezu iOS estandarren arabera - erabili pila-memoria soilik datuekin lan egiteko saretik diskorako bide osoan!

Gakoak ordenatzea konparatzaile bitar batekin

Gako-ordena-erlazioa konparagailu izeneko funtzio berezi batek zehazten du. Motorrak dauzkaten byteen semantikari buruz ezer ez dakienez, konparagailu lehenetsiak ez du gakoak ordena lexikografikoan antolatzea beste aukerarik, bytez byte konparaketara joz. Egiturak antolatzeko erabiltzea aizkora mozteko bizarra egitearen antzekoa da. Hala ere, kasu sinpleetan metodo hau onargarria iruditzen zait. Alternatiba behean deskribatzen da, baina hemen bide honetan zehar sakabanatuta dauden arrasto pare bat ikusiko ditut.

Gogoratu beharreko lehen gauza datu mota primitiboen memoria irudikatzea da. Horrela, Apple gailu guztietan, aldagai osoak formatuan gordetzen dira Endian txikia. Horrek esan nahi du esanguratsu gutxien dagoen bytea ezkerrean egongo dela, eta ezin izango dela ordenatu zenbaki osoak bytez byte konparaketa erabiliz. Adibidez, 0tik 511ra bitarteko zenbaki multzo batekin hau egiten saiatzeak hurrengo emaitza emango du.

// value (hex dump)
000 (0000)
256 (0001)
001 (0100)
257 (0101)
...
254 (fe00)
510 (fe01)
255 (ff00)
511 (ff01)

Arazo hau konpontzeko, zenbaki osoak gakoan gorde behar dira byte-byte konparagailurako egokia den formatuan. Familiaren funtzioek beharrezko eraldaketa egiten lagunduko dizute hton* (zehazki htons adibideko byte bikoitzeko zenbakietarako).

Programazioan kateak irudikatzeko formatua, dakizuenez, osotasun bat da historia. Kateen semantikak eta memorian irudikatzeko erabiltzen den kodeketak karaktere bakoitzeko byte bat baino gehiago egon daitezkeela iradokitzen badu, hobe da lehenetsitako konparagailu bat erabiltzearen ideia berehala alde batera uztea.

Kontuan hartu beharreko bigarren gauza da lerrokatze-printzipioak egitura eremuen konpilatzailea. Hori dela eta, eremuen arteko memorian zabor-balioak dituzten byteak sor daitezke, eta horrek, noski, byte-byte ordenatzea hausten du. Zaborra kentzeko, eremuak zorrozki zehaztutako ordenan deklaratu behar dituzu, lerrokatze-arauak kontuan izanda, edo atributua erabili egitura-deklarazioan. packed.

Kanpoko konparagailu batekin giltzak eskatzea

Gako konparazio-logika konplexuegia izan daiteke konparatzaile bitar batentzat. Arrazoi askotako bat egituren barruan arlo teknikoak egotea da. Horien agerraldia azalduko dut dagoeneko ezaguna zaigun direktorio-elementu baten gako baten adibidea erabiliz.

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameBuffer[256];​
} NodeKey;

Sinplea izan arren, kasu gehienetan memoria gehiegi kontsumitzen du. Izenaren buffer-ak 256 byte hartzen ditu, nahiz eta, batez beste, fitxategi eta karpeten izenak oso gutxitan 20-30 karaktere gainditzen dituen.

Erregistro baten tamaina optimizatzeko teknika estandar bat benetako tamainara "moztea" da. Bere funtsa da luzera aldakorreko eremu guztien edukia buffer batean gordetzen dela egituraren amaieran, eta haien luzerak aldagai bereizietan gordetzen direla.​ Planteamendu honen arabera, gakoa NodeKey honela eraldatzen da.

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameLength;​
    uint8_t nameBuffer[256];​
} NodeKey;

Gainera, serializazioan, ez da datuen tamaina zehazten sizeof egitura osoa, eta eremu guztien tamaina luzera finko bat gehi benetan erabilitako buffer-aren zatiaren tamaina da.

MDB_val serialize(NodeKey * const key) {
    return MDB_val {
        .mv_size = offsetof(NodeKey, nameBuffer) + key->nameLength,
        .mv_data = (void *)key
    };
}

Refactoring-aren ondorioz, giltzek hartzen duten espazioan aurrezpen handia lortu dugu. Hala ere, arlo teknikoa dela eta nameLength, konparatzaile bitar lehenetsia jada ez da gakoen konparaziorako egokia. Ez badugu gurearekin ordezkatzen, izenaren luzera lehentasun handiagoko faktorea izango da ordenatzeko, izena bera baino.

LMDB-k datu-base bakoitzak bere gakoen konparazio funtzioa izan dezake. Hau funtzioa erabiliz egiten da mdb_set_compare zorrozki ireki baino lehen. Ageriko arrazoiengatik, ezin da datu-basearen bizitzan zehar aldatu. Konparatzaileak bi gako formatu bitarrean jasotzen ditu sarrera gisa, eta irteeran konparazioaren emaitza itzultzen du: (-1 baino txikiagoa), (1) baino handiagoa edo (0) berdina. Pseudocode for NodeKey itxura hori.

int compare(MDB_val * const a, MDB_val * const b) {​
    NodeKey * const aKey = (NodeKey * const)a->mv_data;​
    NodeKey * const bKey = (NodeKey * const)b->mv_data;​
    return // ...
}​

Betiere, datu-baseko gako guztiak mota berekoak badira, legezkoa da beren byteen irudikapena baldintzarik gabe igortzea aplikazioaren gakoen egitura motara. Hemen ñabardura bat dago, baina "Irakurketa-erregistroak" azpiatalean aztertuko da jarraian.

Balioak seriatzea

LMDB oso intentsiboki lan egiten du gordetako erregistroen gakoekin. Elkarren arteko konparazioa aplikatutako edozein eragiketaren esparruan gertatzen da, eta soluzio osoaren errendimendua konparagailuaren abiaduraren araberakoa da. Mundu ideal batean, konparatzaile bitar lehenetsiak nahikoa izan beharko luke gakoak alderatzeko, baina zurea erabili behar bazenu, bertan gakoak deserializatzeko prozedura ahalik eta azkarrena izan beharko litzateke.

Datu-baseari ez zaio bereziki interesatzen erregistroaren balioaren zatia (balioa). Bere bytearen irudikapenetik objektu bihurtzea aplikazioaren kodeak dagoeneko eskatzen duenean bakarrik gertatzen da, adibidez, pantailan bistaratzeko. Hori gutxitan gertatzen denez, prozedura honen abiadura-eskakizunak ez dira hain kritikoak, eta inplementazioan askoz askeago gara erosotasunari arreta jartzeko.Adibidez, oraindik deskargatu ez diren fitxategiei buruzko metadatuak serializatzeko, erabiltzen dugu. NSKeyedArchiver.

NSData *data = serialize(object);​
MDB_val value = {​
    .mv_size = data.length,​
    .mv_data = (void *)data.bytes​
};

Hala ere, errendimendua oraindik garrantzitsua den une batzuetan. Adibidez, erabiltzaile-hodei baten fitxategi-egiturari buruzko metainformazioa gordetzean, objektuen memoria-iraulketa bera erabiltzen dugu. Horien errepresentazio seriatua sortzeko zereginaren aipagarriena direktorio bateko elementuak klaseen hierarkia baten arabera modelatzen direla da.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

C hizkuntzan ezartzeko, oinordekoen eremu zehatzak egitura bereizietan jartzen dira, eta oinarriarekin duten lotura mota batasun eremu baten bidez zehazten da. Batasunaren benetako edukiak atributu tekniko motaren bidez zehazten dira.

typedef struct NodeValue {​
    EntityId localId;​
    EntityType type;​
    union {​
        FileInfo file;​
        DirectoryInfo directory;​
    } info;​
    uint8_t nameLength;​
    uint8_t nameBuffer[256];​
} NodeValue;​

Erregistroak gehitzea eta eguneratzea

Serializatutako gakoa eta balioa dendan gehi daitezke. Horretarako, erabili funtzioa mdb_put.

// key и value имеют тип MDB_val​
mdb_put(..., &key, &value, MDB_NOOVERWRITE);

Konfigurazio-fasean, biltegiratzeari gako berarekin hainbat erregistro gordetzea baimendu edo debekatu egin daiteke. Gakoak bikoiztea debekatuta badago, erregistro bat sartzean, lehendik dagoen erregistro bat eguneratzea onartzen den ala ez zehaztu dezakezu. Haustura kodearen errore baten ondorioz soilik gerta badaiteke, hortik babestu zaitezke bandera zehaztuz NOOVERWRITE.

Sarrerak irakurtzea

LMDBko erregistroak irakurtzeko, erabili funtzioa mdb_get. Gako-balio bikotea aurrez botatako egiturek adierazten badute, prozedura honek itxura hau du.

NodeValue * const readNode(..., NodeKey * const key) {​
    MDB_val rawKey = serialize(key);​
    MDB_val rawValue;​
    mdb_get(..., &rawKey, &rawValue);​
    return (NodeValue * const)rawValue.mv_data;​
}

Aurkeztutako zerrendak erakusten du nola egitura-iraulketa bidez serializazioak esleipen dinamikoak kentzeko aukera ematen dizu idaztean ez ezik, datuak irakurtzean ere. Funtziotik eratorria mdb_get erakusleak zehatz-mehatz begiratzen du datu-baseak objektuaren bytearen irudikapena gordetzen duen memoria birtualeko helbidea. Izan ere, datuen irakurketa abiadura oso altua eskaintzen duen ORM moduko bat lortzen dugu ia doan. Planteamenduaren edertasuna izan arren, beharrezkoa da harekin lotutako hainbat ezaugarri gogoratzea.

  1. Irakurtzeko soilik den transakzio baterako, balio-egituraren erakusleak baliozkoak izango direla bermatzen da transakzioa itxi arte. Lehen esan bezala, objektu bat kokatzen den B-zuhaitz-orriek, kopia-idazketa printzipioari esker, aldatu gabe jarraitzen dute, gutxienez transakzio batek erreferentzia egiten dien bitartean. Aldi berean, haiekin lotutako azken transakzioa amaitu bezain laster, orriak datu berrietarako berrerabili ahal izango dira. Objektuak sortu dituen transakziotik bizirik irautea beharrezkoa bada, oraindik kopiatu egin beharko dira.
  2. ​​Irakurketa-transakzio baterako, ondoriozko balio-egituraren erakusleak lehen aldaketa-prozedura arte (datuak idatzi edo ezabatzea) baino ez du balio izango.
  3. Nahiz eta egitura NodeValue ez oso-osorik, baina moztuta (ikus "Gakoak ordenatzea kanpoko konparagailu baten bidez" azpiatala), bere eremuetara segurtasunez sar zaitezke erakuslearen bidez. Garrantzitsuena ez da deserreferentzia egitea!
  4. Inola ere ez da egitura aldatu behar jasotako erakuslearen bidez. Aldaketa guztiak metodoaren bidez bakarrik egin behar dira mdb_put. Dena den, hori egin nahi duzun neurrian, ez da posible izango, egitura hau dagoen memoria-eremua irakurtzeko moduan mapatzen baita.
  5. Birsortu fitxategi bat prozesuko helbide-espaziora, adibidez, funtzioa erabiliz biltegiratze-tamaina maximoa handitzeko mdb_env_set_map_size Erabat baliogabetzen ditu transakzio guztiak eta erlazionatutako entitateak oro har eta objektu jakin batzuetarako erakusleak bereziki.

Azkenik, beste ezaugarri bat hain da maltzurra non bere funtsa agerian uztea ez baita beste paragrafo batean sartzen. B zuhaitzari buruzko kapituluan, bere orriak memorian nola antolatzen diren azaltzen duen diagrama bat eman nuen. Hortik ondorioztatzen da serializatutako datuekin bufferaren hasierako helbidea guztiz arbitrarioa izan daitekeela. Hori dela eta, haien erakuslea egituran jaso MDB_val eta egitura baten erakusle izatera murriztuta, kasu orokorrean lerrokatu gabe geratzen da. Aldi berean, txip batzuen arkitekturak (iOSen kasuan hau armv7 da) eskatzen du edozein daturen helbidea makinaren hitzaren tamainaren multiploa izatea edo, beste era batera esanda, sistemaren bit tamainaren ( armv7rako 32 bitekoa da). Beste era batera esanda, bezalako operazio bat *(int *foo)0x800002 horien gainean ihesaren baliokidea da eta epai batekin exekuziora eramaten du EXC_ARM_DA_ALIGN. Bi modu daude halako patu triste bat ekiditeko.

Lehenengoa datuen aurretiazko kopia egitean datza, jakina den egitura lerrokatu batean. Adibidez, konparatzaile pertsonalizatu batean hau honela islatuko da.

int compare(MDB_val * const a, MDB_val * const b) {
    NodeKey aKey, bKey;
    memcpy(&aKey, a->mv_data, a->mv_size);
    memcpy(&bKey, b->mv_data, b->mv_size);
    return // ...
}

Beste modu bat da aldez aurretik konpilatzaileari jakinaraztea gako-balioen egiturak atributuekin lerrokatuta ez daudela. aligned(1). ARM-en efektu bera izan dezakezu lortu eta packed atributua erabiliz. Egiturak hartzen duen espazioa optimizatzen ere laguntzen duela kontuan hartuta, metodo hau hobetsi iruditzen zait, nahiz eta приводит datuak sartzeko eragiketen kostua handitzeari.

typedef struct __attribute__((packed)) NodeKey {
    uint8_t parentId;
    uint8_t type;
    uint8_t nameLength;
    uint8_t nameBuffer[256];
} NodeKey;

Barrutiko kontsultak

Erregistro talde baten gainean errepikatzeko, LMDBk kurtsorearen abstrakzioa eskaintzen du. Ikus dezagun nola lan egin erabiltzailearen hodeiko metadatuak dagoeneko ezagutzen zaizkigun taula baten adibidea erabiliz.

Direktorio bateko fitxategien zerrenda bistaratzeko zati gisa, beharrezkoa da bere seme-alaba fitxategiak eta karpetak lotzen dituzten gako guztiak aurkitzea. Aurreko azpiataletan gakoak ordenatu ditugu NodeKey hala nola, nagusiki direktorio nagusiaren IDaren arabera ordenatzen dira. Horrela, teknikoki, karpeta baten edukia berreskuratzeko zeregina kurtsorea aurrizki jakin bat duen gako-taldearen goiko mugan jartzera eta, ondoren, beheko mugara iteratzera dator.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Goiko muga zuzenean bilaketa sekuentzialaren bidez aurki daiteke. Horretarako, kurtsorea datu-baseko gakoen zerrenda osoaren hasieran jartzen da eta are gehiago handitzen da, haren azpian direktorioa nagusiaren identifikatzailea duen gako bat agertu arte. Ikuspegi honek 2 desabantaila nabari ditu:

  1. Bilaketa linealaren konplexutasuna, nahiz eta, jakina den bezala, zuhaitzetan orokorrean eta B-zuhaitz batean bereziki denbora logaritmikoan egin daitekeen.
  2. Alferrik, bilatzen denaren aurreko orrialde guztiak fitxategitik memoria nagusira pasatzen dira, eta hori izugarri garestia da.

Zorionez, LMDB APIak hasiera batean kurtsorea kokatzeko modu eraginkorra eskaintzen du. Horretarako, tartearen goiko mugan kokatutako gakoaren balioa, jakina, txikiagoa edo berdina den gako bat sortu behar duzu. Adibidez, goiko irudiko zerrendari dagokionez, eremuaren gako bat egin dezakegu parentId 2ren berdina izango da, eta gainerako guztiak zeroz beteta daude. Partzialki betetako gako hori funtzioaren sarrerari ematen zaio mdb_cursor_get eragiketa adieraziz MDB_SET_RANGE.

NodeKey upperBoundSearchKey = {​
    .parentId = 2,​
    .type = 0,​
    .nameLength = 0​
};​
MDB_val value, key = serialize(upperBoundSearchKey);​
MDB_cursor *cursor;​
mdb_cursor_open(..., &cursor);​
mdb_cursor_get(cursor, &key, &value, MDB_SET_RANGE);

Gako-talde baten goiko muga aurkitzen bada, haren gainean errepikatuko dugu, edo gakoak beste bat elkartu arte. parentId, edo giltzak ez dira batere agortuko.​

do {​
    rc = mdb_cursor_get(cursor, &key, &value, MDB_NEXT);​
    // processing...​
} while (MDB_NOTFOUND != rc && // check end of table​
         IsTargetKey(key));    // check end of keys group​​

Polita da mdb_cursor_get erabiliz iterazioaren zati gisa, gakoa ez ezik, balioa ere lortzen dugula. Laginketa-baldintzak betetzeko, besteak beste, erregistroko balioaren zatiko eremuak egiaztatu behar badituzu, orduan nahiko eskuragarri izango dira keinu gehigarririk gabe.

4.3. Taulen arteko erlazioak modelatzea

Oraingoz, mahai bakarreko datu-base batekin diseinatzeko eta lan egiteko alderdi guztiak kontuan hartzea lortu dugu. Taula bat gako-balio-bikote mota berdinez osatutako ordenatutako erregistroen multzoa dela esan dezakegu. Gako bat laukizuzen gisa eta erlazionatutako balioa paralelepipedo gisa bistaratzen baduzu, datu-basearen diagrama bisual bat lortuko duzu.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Hala ere, bizitza errealean oso gutxitan lortzen da hain odol isurketa gutxirekin. Askotan datu-base batean eskatzen da, lehenik eta behin, hainbat taula edukitzea, eta, bigarrenik, haietan hautaketak egitea gako nagusiaren beste ordena batean. Azken atal hau haien sorrerari eta interkonexioari buruzko gaiei eskainita dago.

Indize-taulak

Hodeiko aplikazioak "Galeria" atala du. Hodei osoko multimedia edukia erakusten du, dataren arabera ordenatuta. Aukeraketa hori modu egokian ezartzeko, mahai nagusiaren ondoan beste bat sortu behar duzu gako mota berri batekin. Fitxategia sortu den datarekin eremu bat edukiko dute, eta hori ordenatzeko irizpide nagusia izango da. Gako berriek taula nagusiko gakoen datu berberak aipatzen dituztenez, indize-gako deitzen zaie. Beheko irudian laranjaz nabarmenduta daude.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Datu-base berean taula ezberdinen gakoak elkarrengandik bereizteko, eremu teknikoko tableId gehigarri bat gehitu zitzaien guztiei. Ordenatzeko lehentasunik handiena bihurtuz, lehenik eta behin gakoak taulen arabera eta taulen barruan taldekatzea lortuko dugu, gure arauen arabera.

Indize-gakoak gako nagusiaren datu berdinak aipatzen ditu. Propietate honen inplementazio zuzena gako nagusiaren balio-zatiaren kopia bat lotuz gero ez da egokiena hainbat ikuspuntutik:

  1. Hartutako espazioari dagokionez, metadatuak nahiko aberatsak izan daitezke.
  2. Errendimenduaren ikuspuntutik, nodo baten metadatuak eguneratzean, bi gako erabiliz berridatzi beharko dituzu.
  3. Kodearen euskarriaren ikuspuntutik, gakoetako baten datuak eguneratzea ahazten bagara, biltegiratzeko datu-inkoherentziaren akats iheskor bat jasoko dugu.

Ondoren, gabezia horiek nola ezabatu aztertuko dugu.

Taulen arteko harremanak antolatzea

Eredua oso egokia da indize-taula taula nagusiarekin lotzeko "gakoa balio gisa". Bere izenak dioen bezala, indize-erregistroaren balioaren zatia gako nagusiaren balioaren kopia bat da. Ikuspegi honek lehen aipatutako erregistroaren balio-zatiaren kopia bat gordetzearekin lotutako desabantaila guztiak ezabatzen ditu. Kostu bakarra indizearen gakoaren arabera balio bat lortzeko, datu-basean 2 kontsulta egin behar dituzula bat izan beharrean. Eskematikoki, ondoriozko datu-basearen eskemak itxura hau du.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Taulen arteko harremanak antolatzeko beste eredu bat da "gako erredundantea". Bere funtsa gakoari atributu gehigarriak gehitzea da, eta ez ordenatzeko beharrezkoak diren gakoa birsortzeko baizik. Mail.ru Cloud aplikazioan erabileraren adibide errealak daude, hala ere, murgiltze sakon bat saihesteko. iOS esparru espezifikoen testuinguruan, fikziozko bat emango dut, baina adibide argiagoa.​

Hodeiko mugikorreko bezeroek erabiltzaileak beste pertsona batzuekin partekatu dituen fitxategi eta karpeta guztiak bistaratzen dituen orrialde bat dute. Fitxategi horiek nahiko gutxi daudenez eta haiei lotutako publizitateari buruzko informazio espezifiko asko dagoenez (nori ematen zaion sarbidea, zein eskubiderekin, etab.), ez da arrazionala izango balorearen zatia zamatzea. grabatu harekin taula nagusian. Hala ere, fitxategi horiek lineaz kanpo bistaratu nahi badituzu, nonbait gorde beharko dituzu oraindik. Irtenbide natural bat mahai bereizi bat sortzea da. Beheko diagraman, bere gakoak "P" aurrizkia du, eta "propname" leku-markak "informazio publikoa" balio zehatzagoarekin ordeztu daiteke.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Metadatu esklusibo guztiak, taula berria sortu den gordetzeko, erregistroko balio zatian jartzen dira. Aldi berean, ez dituzu taula nagusian gordeta dauden fitxategi eta karpetei buruzko datuak bikoiztu nahi. Horren ordez, datu erredundanteak "P" gakoari gehitzen zaizkio "nodoaren IDa" eta "denboraren zigilua" eremuen moduan. Horiei esker, indize-gako bat eraiki dezakezu, eta bertatik gako nagusi bat lor dezakezu, eta, azkenik, nodoen metadatuak lor ditzakezu.

Ondorioa

LMDBren ezarpenaren emaitzak positiboki baloratzen ditugu. Horren ostean, aplikazioak izozteen kopurua % 30 murriztu zen.

LMDB gako-balioen datu-basearen distira eta pobrezia iOS aplikazioetan

Egindako lanaren emaitzek oihartzuna izan zuten iOS taldetik haratago. Gaur egun, Android aplikazioko "Fitxategiak" atal nagusietako bat LMDB erabiltzera ere aldatu da, eta beste zati batzuk bidean daude. C lengoaia, zeinetan gako-balioen biltegia inplementatzen den, laguntza ona izan zen hasieran C++-n plataforma anitzeko aplikazio-esparru bat sortzeko. Kode-sorgailu bat erabili zen ondoriozko C++ liburutegia Objective-C eta Kotlin-en plataforma-kodearekin konektatzeko. Djinni Dropbox-etik, baina hori guztiz bestelako istorio bat da.

Iturria: www.habr.com

Gehitu iruzkin berria