Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Mnamo msimu wa 2019, tukio lililosubiriwa kwa muda mrefu lilifanyika katika timu ya Mail.ru Cloud iOS. Hifadhidata kuu ya uhifadhi unaoendelea wa hali ya maombi imekuwa ya kigeni kabisa kwa ulimwengu wa rununu Umeme Kumbukumbu-Mapped Database (LMDB). Chini ya kukata, mawazo yako yanaalikwa kwenye mapitio yake ya kina katika sehemu nne. Kwanza, hebu tuzungumze juu ya sababu za uchaguzi huo usio na maana na mgumu. Kisha hebu tuendelee kuzingatia nyangumi tatu kwenye moyo wa usanifu wa LMDB: faili zilizopangwa kwa kumbukumbu, B + mti, mbinu ya nakala-ya-kuandika kwa utekelezaji wa shughuli na multiversioning. Hatimaye, kwa dessert - sehemu ya vitendo. Ndani yake, tutaangalia jinsi ya kubuni na kutekeleza schema msingi na majedwali kadhaa, ikiwa ni pamoja na index moja, juu ya API ya kiwango cha chini cha thamani ya ufunguo.

yaliyomo

  1. Motisha ya Utekelezaji
  2. Kuweka LMDB
  3. Nyangumi watatu LMDB
    3.1. Nyangumi #1. Faili zilizopangwa kwa kumbukumbu
    3.2. Nyangumi #2. B+-mti
    3.3. Nyangumi #3. nakala-kwa-kuandika
  4. Kubuni schema ya data juu ya API ya ufunguo-thamani
    4.1. Vifupisho vya msingi
    4.2. Uundaji wa Jedwali
    4.3. Kuunda uhusiano kati ya meza

1. Motisha ya utekelezaji

Mara moja kwa mwaka, mwaka wa 2015, tulishughulikia kuchukua kipimo, mara ngapi kiolesura cha programu yetu kinachelewa. Hatukufanya hivi tu. Tuna malalamiko zaidi na zaidi juu ya ukweli kwamba wakati mwingine programu huacha kujibu vitendo vya mtumiaji: vifungo havijasisitizwa, orodha hazitembezi, nk. Kuhusu mechanics ya vipimo aliiambia kwenye AvitoTech, kwa hivyo hapa ninatoa mpangilio wa nambari tu.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Matokeo ya kipimo yakawa mvua ya baridi kwetu. Ilibadilika kuwa shida zinazosababishwa na kufungia ni nyingi zaidi kuliko nyingine yoyote. Ikiwa, kabla ya kutambua ukweli huu, kiashiria kikuu cha kiufundi cha ubora kilikuwa cha ajali ya bure, basi baada ya kuzingatia kubadilishwa kwenye kufungia bure.

Baada ya kujenga dashibodi yenye vigandishi na baada ya kutumia kiasi и ubora uchambuzi wa sababu zao, adui kuu ikawa wazi - mantiki nzito ya biashara inayotekelezwa kwenye uzi kuu wa programu. Mwitikio wa asili kwa fedheha hii ilikuwa ni hamu kubwa ya kuisukuma kwenye mikondo ya kazi. Kwa suluhisho la kimfumo la shida hii, tuliamua usanifu wa nyuzi nyingi kulingana na watendaji wepesi. Nilijitolea marekebisho yake kwa ulimwengu wa iOS nyuzi mbili katika twitter ya pamoja na makala kuhusu Habre. Kama sehemu ya hadithi ya sasa, ninataka kusisitiza vipengele hivyo vya uamuzi vilivyoathiri uchaguzi wa hifadhidata.

Mfano wa muigizaji wa shirika la mfumo unafikiri kwamba multithreading inakuwa kiini chake cha pili. Mfano wa vitu ndani yake hupenda kuvuka mipaka ya nyuzi. Na hawafanyi hivi wakati mwingine na katika sehemu zingine, lakini karibu kila wakati na kila mahali.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Hifadhidata ni moja wapo ya vipengee vya msingi katika mchoro uliowasilishwa. Kazi yake kuu ni kutekeleza muundo wa jumla Hifadhidata iliyoshirikiwa. Ikiwa katika ulimwengu wa biashara hutumiwa kuandaa maingiliano ya data kati ya huduma, basi katika kesi ya usanifu wa muigizaji, data kati ya nyuzi. Kwa hivyo, tulihitaji hifadhidata kama hiyo, kufanya kazi nayo ambayo katika mazingira yenye nyuzi nyingi haisababishi ugumu hata kidogo. Hasa, hii ina maana kwamba vitu vinavyotokana nayo lazima iwe angalau thread-salama, na walau si kubadilika wakati wote. Kama unavyojua, mwisho unaweza kutumika wakati huo huo kutoka kwa nyuzi kadhaa bila kutumia aina yoyote ya kufuli, ambayo ina athari ya manufaa kwenye utendaji.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOSJambo la pili muhimu ambalo liliathiri uchaguzi wa hifadhidata ilikuwa API yetu ya wingu. Ilitiwa moyo na mbinu ya git ya maingiliano. Kama yeye tulilenga API ya kwanza ya nje ya mtandao, ambayo inaonekana zaidi kuliko inafaa kwa wateja wa wingu. Ilichukuliwa kuwa mara moja tu wangesukuma hali kamili ya wingu, na kisha usawazishaji katika idadi kubwa ya matukio ungetokea kupitia mabadiliko yanayoendelea. Ole, uwezekano huu bado ni katika eneo la kinadharia tu, na kwa mazoezi, wateja hawajajifunza jinsi ya kufanya kazi na patches. Kuna sababu nyingi za kusudi hili, ambazo, ili si kuchelewesha utangulizi, tutaondoka kwenye mabano. Sasa cha kufurahisha zaidi ni matokeo ya kufundisha ya somo juu ya kile kinachotokea wakati API ilisema "A" na watumiaji wake hawakusema "B".

Kwa hivyo, ikiwa unafikiria git, ambayo, wakati wa kutekeleza amri ya kuvuta, badala ya kutumia viraka kwenye picha ya kawaida, inalinganisha hali yake kamili na seva kamili, basi utakuwa na wazo sahihi la jinsi maingiliano. hutokea kwa wateja wa wingu. Ni rahisi nadhani kwamba kwa utekelezaji wake ni muhimu kutenga miti miwili ya DOM katika kumbukumbu na meta-habari kuhusu seva zote na faili za ndani. Inabadilika kuwa ikiwa mtumiaji huhifadhi faili elfu 500 kwenye wingu, kisha kusawazisha, ni muhimu kuunda tena na kuharibu miti miwili yenye nodi milioni 1. Lakini kila nodi ni jumla iliyo na grafu ya mada ndogo. Kwa mwanga huu, matokeo ya wasifu yalitarajiwa. Ilibadilika kuwa hata bila kuzingatia algorithm ya kuunganisha, utaratibu sana wa kuunda na kisha kuharibu idadi kubwa ya vitu vidogo hugharimu senti nzuri.Hali hiyo inazidishwa na ukweli kwamba operesheni ya msingi ya maingiliano imejumuishwa katika idadi kubwa. maandishi ya mtumiaji. Matokeo yake, tunarekebisha kigezo cha pili muhimu katika kuchagua hifadhidata - uwezo wa kutekeleza shughuli za CRUD bila ugawaji wa nguvu wa vitu.

Mahitaji mengine ni ya kitamaduni zaidi, na orodha yao kamili ni kama ifuatavyo.

  1. Usalama wa thread.
  2. Usindikaji mwingi. Imeamriwa na hamu ya kutumia mfano huo wa hifadhidata kusawazisha hali sio tu kati ya nyuzi, lakini pia kati ya programu kuu na viendelezi vya iOS.
  3. Uwezo wa kuwakilisha huluki zilizohifadhiwa kama vitu visivyoweza kubadilika
  4. Ukosefu wa mgao wa nguvu ndani ya shughuli za CRUD.
  5. Usaidizi wa Muamala kwa Sifa za Msingi ACIDManeno muhimu: atomiki, uthabiti, kutengwa na kuegemea.
  6. Kasi kwenye kesi maarufu zaidi.

Kwa seti hii ya mahitaji, SQLite ilikuwa na bado ni chaguo nzuri. Hata hivyo, kama sehemu ya utafiti wa njia mbadala, nilikutana na kitabu "Kuanza na LevelDB". Chini ya uongozi wake, alama iliandikwa ambayo inalinganisha kasi ya kazi na hifadhidata tofauti katika hali halisi za wingu. Matokeo yalizidi matarajio makubwa zaidi. Katika kesi maarufu zaidi - kupata mshale kwenye orodha iliyopangwa ya faili zote na orodha iliyopangwa ya faili zote kwa saraka fulani - LMDB iligeuka kuwa mara 10 zaidi kuliko SQLite. Chaguo likawa dhahiri.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

2. Nafasi ya LMDB

LMDB ni maktaba, ndogo sana (laini 10 tu) inayotekelezea safu ya chini kabisa ya hifadhidata - hifadhi.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Mchoro hapo juu unaonyesha kuwa kulinganisha LMDB na SQLite, ambayo hutumia viwango vya juu zaidi, kwa ujumla sio sahihi zaidi kuliko SQLite na Data ya Msingi. Itakuwa haki zaidi kutaja injini sawa za kuhifadhi kama washindani sawa - BerkeleyDB, LevelDB, Sophia, RocksDB, n.k. Kuna maendeleo ambapo LMDB hufanya kama sehemu ya injini ya kuhifadhi kwa SQLite. Jaribio la kwanza kama hilo mnamo 2012 alitumia mwandishi LMDB Howard Chu. Matokeo iligeuka kuwa ya kuvutia sana kwamba mpango wake ulichukuliwa na wapenda OSS, na kupata mwendelezo wake mbele ya LumoSQL. Mnamo Januari 2020 mwandishi wa mradi huu ni Den Shearer iliyowasilishwa iko kwenye LinuxConfAu.

Matumizi kuu ya LMDB ni kama injini ya hifadhidata za programu. Maktaba inadaiwa kuonekana kwa watengenezaji OpenLDAP, ambao hawakuridhika vikali na BerkeleyDB kama msingi wa mradi wao. Kusukuma mbali na maktaba ya unyenyekevu btree, Howard Chu aliweza kuunda mojawapo ya njia mbadala maarufu zaidi za wakati wetu. Alitoa ripoti yake nzuri sana kwa hadithi hii, na vile vile muundo wa ndani wa LMDB. "Hifadhi ya kumbukumbu ya Umeme". Leonid Yuriev (aka ileo) kutoka kwa Positive Technologies katika mazungumzo yake katika Highload 2015 "Injini ya LMDB ni bingwa maalum". Ndani yake, anazungumzia LMDB katika muktadha wa kazi sawa ya kutekeleza ReOpenLDAP, na LevelDB tayari imekabiliwa na ukosoaji linganishi. Kama matokeo ya utekelezaji, Positive Technologies hata ilipata uma inayoendelea MDBX na sifa kitamu sana, uboreshaji na marekebisho ya hitilafu.

LMDB mara nyingi hutumiwa kama uhifadhi pia. Kwa mfano, kivinjari cha Mozilla Firefox alichagua kwa idadi ya mahitaji, na, kuanzia toleo la 9, Xcode iliyopendekezwa SQLite yake ya kuhifadhi faharisi.

Injini pia ilishika kasi katika ulimwengu wa maendeleo ya rununu. Athari za matumizi yake zinaweza kuwa kupata katika mteja wa iOS wa Telegraph. LinkedIn ilienda hatua moja zaidi na kuchagua LMDB kama hifadhi chaguomsingi ya mfumo wake wa kuhifadhi data wa nyumbani, Data ya Rocket, ambayo aliiambia katika makala ya 2016.

LMDB inapigania kwa mafanikio mahali pa jua kwenye niche iliyoachwa na BerkeleyDB baada ya mpito chini ya udhibiti wa Oracle. Maktaba inapendwa kwa kasi yake na kuegemea, hata kwa kulinganisha na aina yake. Kama unavyojua, hakuna chakula cha mchana bila malipo, na ningependa kusisitiza biashara ambayo itabidi ukabiliane nayo wakati wa kuchagua kati ya LMDB na SQLite. Mchoro hapo juu unaonyesha wazi jinsi kasi iliyoongezeka inafikiwa. Kwanza, hatulipi kwa tabaka za ziada za uondoaji juu ya hifadhi ya diski. Bila shaka, katika usanifu mzuri, bado hauwezi kufanya bila wao, na bila shaka wataonekana katika msimbo wa maombi, lakini watakuwa nyembamba zaidi. Hawatakuwa na vipengele ambavyo havitakiwi na programu mahususi, kwa mfano, usaidizi wa maswali katika lugha ya SQL. Pili, inawezekana kutekeleza kikamilifu ramani ya shughuli za maombi kwa maombi ya kuhifadhi diski. Ikiwa SQLite katika kazi yangu hutoka kwa mahitaji ya wastani ya programu tumizi, basi wewe, kama msanidi programu, unafahamu vyema hali kuu za upakiaji. Kwa suluhisho lenye tija zaidi, utalazimika kulipa tag ya bei iliyoongezeka kwa maendeleo ya suluhisho la awali na usaidizi wake unaofuata.

3. Nyangumi watatu LMDB

Baada ya kutazama LMDB kutoka kwa mtazamo wa jicho la ndege, ni wakati wa kuingia ndani zaidi. Sehemu tatu zifuatazo zitatolewa kwa uchambuzi wa nyangumi kuu ambazo usanifu wa uhifadhi hutegemea:

  1. Faili zilizopangwa kwa kumbukumbu kama utaratibu wa kufanya kazi na diski na kulandanisha miundo ya data ya ndani.
  2. B+-mti kama shirika la muundo wa data iliyohifadhiwa.
  3. Nakili-kwa-kuandika kama mbinu ya kutoa sifa za muamala za ACID na ugeuzaji anuwai.

3.1. Nyangumi #1. Faili zilizopangwa kwa kumbukumbu

Faili zilizopangwa kwa kumbukumbu ni kipengele muhimu cha usanifu ambacho huonekana hata kwa jina la hifadhi. Masuala ya kuweka akiba na kusawazisha ufikiaji wa habari iliyohifadhiwa ni kwa huruma ya mfumo wa uendeshaji. LMDB haina akiba yoyote ndani yake. Huu ni uamuzi wa ufahamu wa mwandishi, kwa kuwa kusoma data moja kwa moja kutoka kwa faili zilizopangwa inakuwezesha kukata pembe nyingi katika utekelezaji wa injini. Chini ni mbali na orodha kamili ya baadhi yao.

  1. Kudumisha uthabiti wa data katika uhifadhi wakati wa kufanya kazi nayo kutoka kwa michakato kadhaa inakuwa jukumu la mfumo wa uendeshaji. Katika sehemu inayofuata, fundi huyu amejadiliwa kwa kina na kwa picha.
  2. Kutokuwepo kwa kache kunapunguza kabisa LMDB ya kichwa kinachohusiana na mgao wa nguvu. Kusoma data katika mazoezi ni kuweka pointer kwa anwani sahihi katika kumbukumbu pepe na hakuna zaidi. Inaonekana kama njozi, lakini katika chanzo cha hazina, simu zote za calloc zimejilimbikizia katika kipengele cha kukokotoa cha usanidi wa hifadhi.
  3. Kutokuwepo kwa akiba pia kunamaanisha kutokuwepo kwa kufuli zinazohusiana na ulandanishi ili kuzifikia. Wasomaji, ambao nambari ya kiholela inaweza kuwepo kwa wakati mmoja, hawapati mutex moja kwenye njia yao ya data. Kwa sababu ya hii, kasi ya kusoma ina scalability bora ya mstari kulingana na idadi ya CPU. Katika LMDB, shughuli za kurekebisha pekee ndizo zinazosawazishwa. Kunaweza kuwa na mwandishi mmoja tu kwa wakati mmoja.
  4. Kiwango cha chini cha mantiki ya kuweka akiba na ulandanishi huhifadhi msimbo kutoka kwa aina changamano ya hitilafu zinazohusiana na kufanya kazi katika mazingira yenye nyuzi nyingi. Kulikuwa na tafiti mbili za kuvutia za hifadhidata katika mkutano wa Usenix OSDI 2014: "Mifumo Yote ya Faili Haijaundwa Sawa: Kwenye Utata wa Kutengeneza Programu Zinazobadilika Kuacha Kufanya Kazi" и Hifadhidata za Kutesa kwa Furaha na Faida. Kutoka kwao unaweza kupata habari juu ya uaminifu usio na kifani wa LMDB, na utekelezaji usio na dosari wa mali ya ACID ya shughuli, ambayo inaizidi katika SQLite sawa.
  5. Minimalism ya LMDB inaruhusu uwakilishi wa mashine ya msimbo wake kuwekwa kabisa kwenye cache ya L1 ya processor na sifa za kasi zinazosababisha.

Kwa bahati mbaya, katika iOS, faili zilizopangwa kwa kumbukumbu sio nzuri kama tungependa. Ili kuzungumza juu ya hasara zinazohusiana nao kwa uangalifu zaidi, ni muhimu kukumbuka kanuni za jumla za kutekeleza utaratibu huu katika mifumo ya uendeshaji.

Maelezo ya jumla kuhusu faili zilizopangwa kwa kumbukumbu

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOSKwa kila programu inayoweza kutekelezwa, mfumo wa uendeshaji huhusisha huluki inayoitwa mchakato. Kila mchakato umepewa anuwai ya anwani, ambayo huweka kila kitu kinachohitaji kufanya kazi. Anwani za chini kabisa zina sehemu zilizo na msimbo na data na rasilimali zenye msimbo ngumu. Inayofuata inakuja kizuizi kinachokua cha juu cha nafasi ya anwani inayobadilika, inayojulikana kwetu kama lundo. Ina anwani za huluki zinazoonekana wakati wa uendeshaji wa programu. Hapo juu ni eneo la kumbukumbu linalotumiwa na mkusanyiko wa programu. Inakua au kupungua, kwa maneno mengine, ukubwa wake pia una asili ya nguvu. Ili mrundikano na lundo visisukumane na kuingiliana, vinatenganishwa katika ncha tofauti za nafasi ya anwani.Kuna shimo kati ya sehemu mbili zenye nguvu zilizo juu na chini. Anwani katika sehemu hii ya kati hutumiwa na mfumo wa uendeshaji kuhusishwa na mchakato wa vyombo mbalimbali. Hasa, inaweza kuweka seti fulani inayoendelea ya anwani kwenye faili kwenye diski. Faili kama hiyo inaitwa faili iliyopangwa kwa kumbukumbu

Nafasi ya anwani iliyotengwa kwa mchakato ni kubwa. Kinadharia, idadi ya anwani ni mdogo tu kwa ukubwa wa pointer, ambayo imedhamiriwa na kina kidogo cha mfumo. Ikiwa kumbukumbu ya mwili ingepewa 1-in-1, basi mchakato wa kwanza ungeongeza RAM nzima, na hakutakuwa na swali la kufanya kazi nyingi.

Hata hivyo, tunajua kutokana na uzoefu kwamba mifumo ya uendeshaji ya kisasa inaweza kuendesha michakato mingi unavyotaka kwa wakati mmoja. Hii inawezekana kwa sababu ya ukweli kwamba wanatenga kumbukumbu nyingi kwa michakato kwenye karatasi tu, lakini kwa kweli hupakia kwenye kumbukumbu kuu ya mwili tu sehemu hiyo ambayo inahitajika hapa na sasa. Kwa hiyo, kumbukumbu inayohusishwa na mchakato inaitwa virtual.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Mfumo wa uendeshaji hupanga kumbukumbu halisi na ya kimwili katika kurasa za ukubwa fulani. Mara tu ukurasa fulani wa kumbukumbu halisi unapohitajika, mfumo wa uendeshaji hupakia kwenye kumbukumbu ya kimwili na huweka mawasiliano kati yao kwenye meza maalum. Ikiwa hakuna nafasi za bure, basi moja ya kurasa zilizopakiwa hapo awali zinakiliwa kwenye diski, na iliyoombwa inachukua nafasi yake. Utaratibu huu, ambao tutarudi hivi karibuni, unaitwa kubadilishana. Kielelezo hapa chini kinaonyesha mchakato ulioelezwa. Juu yake, ukurasa A wenye anwani 0 ulipakiwa na kuwekwa kwenye ukurasa mkuu wa kumbukumbu wenye anwani 4. Ukweli huu ulionekana katika jedwali la mawasiliano katika nambari ya seli 0.​

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Na faili zilizopangwa kwa kumbukumbu, hadithi ni sawa kabisa. Kimantiki, zinapaswa kuwekwa kwa mfululizo na kabisa katika nafasi ya anwani pepe. Walakini, wanaingia kwenye ukurasa wa kumbukumbu ya mwili kwa ukurasa na kwa mahitaji tu. Marekebisho ya kurasa kama hizo hulinganishwa na faili kwenye diski. Kwa hivyo, unaweza kutekeleza faili I / O, ukifanya kazi tu na ka kwenye kumbukumbu - mabadiliko yote yatahamishwa kiotomatiki na kernel ya mfumo wa uendeshaji hadi faili asili.
â € <
Picha hapa chini inaonyesha jinsi LMDB inasawazisha hali yake wakati wa kufanya kazi na hifadhidata kutoka kwa michakato tofauti. Kwa kuweka kumbukumbu pepe ya michakato tofauti kwenye faili moja, kwa hakika tunalazimisha mfumo wa uendeshaji kusawazisha kwa mpito baadhi ya vizuizi vya nafasi zao za anwani, ambapo LMDB inaonekana.​
â € <

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Nuance muhimu ni kwamba LMDB hurekebisha faili ya data kwa chaguo-msingi kupitia utaratibu wa simu wa mfumo wa kuandika, na faili yenyewe huonyesha katika hali ya kusoma tu. Mbinu hii ina maana mbili muhimu.

Matokeo ya kwanza ni ya kawaida kwa mifumo yote ya uendeshaji. Kiini chake ni kuongeza ulinzi dhidi ya uharibifu usiotarajiwa wa hifadhidata kwa msimbo usio sahihi. Kama unavyojua, maagizo ya kutekelezwa ya mchakato ni bure kupata data kutoka mahali popote katika nafasi yake ya anwani. Wakati huo huo, kama tulivyokumbuka hivi punde, kuonyesha faili katika hali ya kusoma-kuandika inamaanisha kuwa maagizo yoyote yanaweza pia kurekebisha kwa kuongeza. Ikiwa atafanya hivi kimakosa, akijaribu, kwa mfano, kubatilisha kipengee cha safu kwenye faharasa ambayo haipo, basi kwa njia hii anaweza kubadilisha kwa bahati mbaya faili iliyopangwa kwa anwani hii, ambayo itasababisha uharibifu wa hifadhidata. Ikiwa faili imeonyeshwa katika hali ya kusoma tu, basi jaribio la kubadilisha nafasi ya anwani inayolingana nayo itasababisha ajali ya programu na ishara. SIGSEGV, na faili itabaki kuwa sawa.

Matokeo ya pili tayari ni maalum kwa iOS. Si mwandishi wala vyanzo vingine vyovyote vinavyoitaja kwa uwazi, lakini bila hiyo, LMDB haitakuwa sawa kwa uendeshaji wa mfumo huu wa uendeshaji wa simu ya mkononi. Sehemu inayofuata imejitolea kwa kuzingatia kwake.

Maalum ya faili zilizopangwa kwa kumbukumbu katika iOS

Mnamo 2018, kulikuwa na ripoti nzuri katika WWDC iOS Memory Deep Dive. Inasema kwamba katika iOS kurasa zote ziko katika kumbukumbu ya kimwili ni ya moja ya aina 3: chafu, USITUMIE na safi.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Kumbukumbu safi ni mkusanyiko wa kurasa ambazo zinaweza kubadilishwa kwa usalama kutoka kwa kumbukumbu halisi. Data iliyomo inaweza kupakiwa upya kutoka kwa vyanzo vyao asili inavyohitajika. Faili za kumbukumbu za kusoma pekee ziko katika aina hii. iOS haogopi kupakua kurasa zilizopangwa kwa faili kutoka kwa kumbukumbu wakati wowote, kwani zimehakikishiwa kusawazishwa na faili kwenye diski.
â € <
Kurasa zote zilizorekebishwa huingia kwenye kumbukumbu chafu, bila kujali ziko wapi hapo awali. Hasa, faili zilizopangwa kwa kumbukumbu zilizobadilishwa kwa kuandika kwenye kumbukumbu ya kawaida inayohusishwa nao pia zitaainishwa kwa njia hii. Kufungua LMDB na bendera MDB_WRITEMAP, baada ya kuifanyia mabadiliko, unaweza kujionea mwenyewe

Punde tu programu inapoanza kuchukua kumbukumbu nyingi sana, iOS hubana kurasa zake chafu. Mkusanyiko wa kumbukumbu iliyochukuliwa na kurasa chafu na zilizoshinikizwa ni kinachojulikana kama alama ya kumbukumbu ya programu. Inapofikia thamani fulani ya kizingiti, daemon ya mfumo wa muuaji wa OOM huja baada ya mchakato huo na kuikomesha kwa lazima. Huu ndio upekee wa iOS ikilinganishwa na mifumo ya uendeshaji ya eneo-kazi. Kinyume chake, kupunguza alama ya kumbukumbu kwa kubadilisha kurasa kutoka kumbukumbu halisi hadi diski hakutolewa katika iOS. Mtu anaweza tu kukisia kuhusu sababu. Labda utaratibu wa kusonga sana kurasa kwa diski na nyuma unatumia nishati nyingi kwa vifaa vya rununu, au iOS huokoa rasilimali ya kuandika upya seli kwenye viendeshi vya SSD, au labda wabunifu hawakuridhika na utendaji wa jumla wa mfumo, ambapo kila kitu kiko. kubadilishwa mara kwa mara. Iwe hivyo, ukweli unabaki.

Habari njema, iliyotajwa hapo awali, ni kwamba LMDB haitumii utaratibu wa mmap kusasisha faili kwa chaguo-msingi. Inafuata kwamba data iliyotolewa inaainishwa kama kumbukumbu safi na iOS na haichangii alama ya kumbukumbu. Hii inaweza kuthibitishwa kwa kutumia zana ya Xcode inayoitwa VM Tracker. Picha ya skrini iliyo hapa chini inaonyesha hali ya kumbukumbu pepe ya programu ya Wingu la iOS wakati wa operesheni. Mwanzoni, matukio 2 ya LMDB yalianzishwa ndani yake. Ya kwanza iliruhusiwa kuweka faili yake kwa 1GiB ya kumbukumbu halisi, ya pili - 512MiB. Licha ya ukweli kwamba hifadhi zote mbili huchukua kiasi fulani cha kumbukumbu ya mkazi, hakuna hata mmoja wao anayechangia ukubwa wa uchafu.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Sasa ni wakati wa habari mbaya. Shukrani kwa utaratibu wa kubadilishana katika mifumo ya uendeshaji ya eneo-kazi la 64-bit, kila mchakato unaweza kuchukua nafasi nyingi za anwani kama vile nafasi ya bure kwenye diski kuu inavyoruhusu ubadilishanaji wake unaowezekana. Kubadilisha ubadilishanaji na mgandamizo katika iOS hupunguza sana upeo wa kinadharia. Sasa taratibu zote za maisha lazima ziingie kwenye kumbukumbu kuu (soma RAM), na wale wote wasiofaa wanakabiliwa na kukomesha kwa kulazimishwa. Imetajwa kama ilivyo hapo juu ripoti, na nyaraka rasmi. Kwa hivyo, iOS huweka kikomo kwa kiasi kikubwa kiasi cha kumbukumbu kinachopatikana kwa mgao kupitia mmap. Hapa hapa unaweza kuangalia vikomo vya majaribio juu ya kiasi cha kumbukumbu ambacho kinaweza kutengwa kwenye vifaa tofauti kwa kutumia simu ya mfumo huu. Juu ya mifano ya kisasa ya smartphones, iOS imekuwa ukarimu kwa gigabytes 2, na juu ya matoleo ya juu ya iPad - na 4. Katika mazoezi, bila shaka, unapaswa kuzingatia mifano ya vifaa vidogo vilivyoungwa mkono, ambapo kila kitu kinasikitisha sana. Mbaya zaidi, ukiangalia hali ya kumbukumbu ya programu katika VM Tracker, utaona kuwa LMDB iko mbali na ile pekee inayodai kumbukumbu iliyopangwa kwa kumbukumbu. Vipande vyema huliwa na vigawaji vya mfumo, faili za rasilimali, mifumo ya picha, na wadudu wengine wadogo.

Kama matokeo ya majaribio katika Wingu, tulikuja na maadili ya maelewano yafuatayo ya kumbukumbu yaliyotolewa na LMDB: megabaiti 384 kwa vifaa vya 32-bit na 768 kwa 64-bit. Baada ya kiasi hiki kutumika, shughuli zozote za kurekebisha huanza kukamilika na msimbo MDB_MAP_FULL. Tunaona makosa kama haya katika ufuatiliaji wetu, lakini ni ndogo vya kutosha kupuuzwa katika hatua hii.

Sababu isiyo dhahiri ya utumiaji wa kumbukumbu kupita kiasi kwa uhifadhi inaweza kuwa shughuli za muda mrefu. Ili kuelewa jinsi matukio haya mawili yanahusiana, itatusaidia kufikiria nyangumi wawili waliobaki wa LMDB.

3.2. Nyangumi #2. B+-mti

Ili kuiga jedwali juu ya duka la thamani-msingi, shughuli zifuatazo lazima ziwepo katika API yake:

  1. Kuingiza kipengele kipya.
  2. Tafuta kipengele kwa ufunguo fulani.
  3. Kufuta kipengele.
  4. Rudia juu ya vipindi muhimu katika mpangilio wao wa kupanga.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOSMuundo rahisi zaidi wa data ambao unaweza kutekeleza shughuli zote nne kwa urahisi ni mti wa utafutaji wa binary. Kila moja ya nodi zake ni ufunguo unaogawanya sehemu nzima ya funguo za watoto katika subtrees mbili. Upande wa kushoto ni wale ambao ni ndogo kuliko mzazi, na upande wa kulia - wale ambao ni kubwa. Kupata seti iliyoagizwa ya funguo hupatikana kupitia mojawapo ya vipitio vya miti ya kawaida

Miti ya binary ina vikwazo viwili vya kimsingi vinavyozuia kuwa bora kama muundo wa data ya diski. Kwanza, kiwango cha usawa wao haitabiriki. Kuna hatari kubwa ya kupata miti ambayo urefu wa matawi tofauti unaweza kutofautiana sana, ambayo inazidisha kwa kiasi kikubwa utata wa algorithmic wa utafutaji ikilinganishwa na kile kinachotarajiwa. Pili, wingi wa viunganishi baina ya nodi hunyima miti binary ya eneo katika kumbukumbu.Nodi za karibu (kwa suala la viungo kati yao) zinaweza kuwekwa kwenye kurasa tofauti kabisa katika kumbukumbu pepe. Kwa hivyo, hata upitishaji rahisi wa nodi kadhaa za jirani kwenye mti unaweza kuhitaji kutembelea idadi inayolingana ya kurasa. Hili ni shida hata tunapozungumza juu ya ufanisi wa miti ya binary kama muundo wa kumbukumbu ya kumbukumbu, kwani kurasa zinazozunguka kila wakati kwenye kashe ya processor sio nafuu. Linapokuja suala la kuinua mara kwa mara kurasa zinazohusiana na nodi kutoka kwa diski, mambo huwa mabaya sana. ya kusikitisha.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOSB-miti, kuwa mageuzi ya miti ya binary, kutatua matatizo yaliyoainishwa katika aya iliyotangulia. Kwanza, wanajisawazisha. Pili, kila nodi zao hugawanya seti ya funguo za watoto sio 2, lakini kwa sehemu ndogo zilizoamuru M, na nambari M inaweza kuwa kubwa kabisa, kwa mpangilio wa mamia kadhaa au hata maelfu.

Kwa hivyo:

  1. Kila nodi ina idadi kubwa ya funguo zilizoagizwa tayari na miti ni ya chini sana.
  2. Mti hupata mali ya eneo katika kumbukumbu, kwani funguo ambazo ziko karibu kwa thamani ziko karibu na kila mmoja kwenye nodi moja au jirani.
  3. Hupunguza idadi ya nodi za usafiri wakati wa kushuka mti wakati wa shughuli ya utafutaji.
  4. Hupunguza idadi ya nodi lengwa zilizosomwa kwa hoja mbalimbali, kwa kuwa kila moja tayari ina idadi kubwa ya vitufe vilivyoagizwa.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

LMDB hutumia lahaja ya mti B unaoitwa B+ tree kuhifadhi data. Mchoro hapo juu unaonyesha aina tatu za nodi zilizomo:

  1. Juu ni mzizi. Haifanyi chochote zaidi ya wazo la hifadhidata ndani ya hazina. Ndani ya mfano mmoja wa LMDB, unaweza kuunda hifadhidata nyingi zinazoshiriki nafasi ya anwani pepe iliyopangwa. Kila mmoja wao huanza kutoka mizizi yake mwenyewe.
  2. Katika ngazi ya chini ni majani (jani). Ni wao na wao pekee walio na jozi za thamani-msingi zilizohifadhiwa kwenye hifadhidata. Kwa njia, hii ni upekee wa B + -miti. Ikiwa mti wa kawaida wa B huhifadhi sehemu za thamani kwenye nodi za viwango vyote, basi tofauti ya B + iko chini kabisa. Baada ya kurekebisha ukweli huu, katika kile kinachofuata tutaita aina ndogo ya mti unaotumiwa katika LMDB kuwa mti wa B.
  3. Kati ya mzizi na majani, kuna viwango 0 au zaidi vya kiufundi vilivyo na nodi za urambazaji (tawi). Kazi yao ni kugawanya seti iliyopangwa ya funguo kati ya majani.

Kimwili, nodi ni vizuizi vya kumbukumbu ya urefu ulioamuliwa mapema. Ukubwa wao ni nyingi ya ukubwa wa kurasa za kumbukumbu katika mfumo wa uendeshaji, ambao tulizungumzia hapo juu. Muundo wa nodi umeonyeshwa hapa chini. Kichwa kina meta-habari, ambayo ni dhahiri zaidi ambayo, kwa mfano, ni checksum. Inayofuata inakuja habari kuhusu marekebisho, ambayo seli zilizo na data ziko. Jukumu la data linaweza kuwa funguo, ikiwa tunazungumza kuhusu nodi za urambazaji, au jozi zote za thamani-msingi katika kesi ya majani. Unaweza kusoma zaidi kuhusu muundo wa kurasa katika kazi. "Tathmini ya Maduka ya Thamani ya Utendaji wa Juu".

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Baada ya kushughulika na maudhui ya ndani ya nodi za ukurasa, tutawakilisha zaidi mti wa LMDB B kwa njia iliyorahisishwa katika fomu ifuatayo.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Kurasa zilizo na nodi zimepangwa kwa mpangilio kwenye diski. Kurasa zilizo na nambari ya juu ziko kuelekea mwisho wa faili. Kinachojulikana ukurasa wa meta (ukurasa wa meta) una habari kuhusu kukabiliana, ambayo inaweza kutumika kupata mizizi ya miti yote. Faili inapofunguliwa, LMDB huchanganua ukurasa wa faili kwa ukurasa kutoka mwisho hadi mwanzo ili kutafuta ukurasa halali wa meta na kupata hifadhidata zilizopo kupitia hiyo.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Sasa, kwa kuwa na wazo la muundo wa kimantiki na wa kimwili wa shirika la data, tunaweza kuendelea kuzingatia nyangumi wa tatu wa LMDB. Ni kwa msaada wake kwamba marekebisho yote ya hifadhi hutokea kwa shughuli na kwa kutengwa kutoka kwa kila mmoja, kutoa database kwa ujumla pia mali ya multiversion.

3.3. Nyangumi #3. nakala-kwa-kuandika

Baadhi ya shughuli za B-tree zinahusisha kufanya mfululizo mzima wa mabadiliko kwenye nodi zake. Mfano mmoja ni kuongeza ufunguo mpya kwa nodi ambayo tayari imefikia uwezo wake wa juu. Katika kesi hii, ni muhimu, kwanza, kugawanya nodi katika mbili, na pili, kuongeza kiungo kwa nodi mpya ya spun off mtoto katika mzazi wake. Utaratibu huu ni hatari sana. Ikiwa kwa sababu fulani (kuanguka, kukatika kwa umeme, nk) tu sehemu ya mabadiliko kutoka kwa mfululizo hutokea, basi mti utabaki katika hali isiyofaa.

Suluhisho moja la kitamaduni la kufanya hifadhidata istahimili makosa ni kuongeza muundo wa ziada wa data kulingana na diski, logi ya muamala, inayojulikana pia kama logi ya kuandika mbele (WAL), karibu na mti wa B. Ni faili, mwishoni mwa ambayo, madhubuti kabla ya marekebisho ya mti wa B yenyewe, operesheni iliyopangwa imeandikwa. Kwa hivyo, ikiwa uharibifu wa data utagunduliwa wakati wa kujitambua, hifadhidata inashauriana na logi ili kujisafisha.

LMDB imechagua mbinu tofauti kama utaratibu wake wa kustahimili makosa, unaoitwa kunakili-kwa-kuandika. Kiini chake ni kwamba badala ya kusasisha data kwenye ukurasa uliopo, kwanza inakili kabisa na kufanya marekebisho yote tayari kwenye nakala.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Zaidi ya hayo, ili data iliyosasishwa ipatikane, ni muhimu kubadilisha kiungo kwenye nodi ambayo imekuwa ya kisasa katika nodi ya mzazi kuhusiana nayo. Kwa kuwa pia inahitaji kurekebishwa kwa hili, pia imenakiliwa awali. Mchakato unaendelea kujirudia hadi kwenye mizizi. Data iliyo kwenye ukurasa wa meta ndiyo ya mwisho kubadilika. .

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Ikiwa ghafla mchakato unaanguka wakati wa utaratibu wa sasisho, basi ama ukurasa mpya wa meta hautaundwa, au hautaandikwa kwenye diski hadi mwisho, na checksum yake itakuwa sahihi. Katika mojawapo ya visa hivi viwili, kurasa mpya hazitapatikana na zile za zamani hazitaathiriwa. Hii inaondoa hitaji la LMDB kuandika kumbukumbu ya mbele ili kudumisha uthabiti wa data. De facto, muundo wa hifadhi ya data kwenye diski, iliyoelezwa hapo juu, wakati huo huo inachukua kazi yake. Kutokuwepo kwa logi iliyo wazi ya muamala ni mojawapo ya vipengele vya LMDB, ambayo hutoa kasi ya juu ya usomaji wa data.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Muundo unaotokana, unaoitwa append-pekee B-tree, kwa kawaida hutoa utengaji wa shughuli na ugeuzaji anuwai. Katika LMDB, kila shughuli iliyo wazi ina mzizi wa mti uliosasishwa unaohusishwa nayo. Alimradi muamala haujakamilika, kurasa za mti unaohusishwa nazo hazitawahi kubadilishwa au kutumika tena kwa matoleo mapya ya data. Kwa hivyo, unaweza kufanya kazi kwa muda unavyopenda na seti ya data ambayo ilikuwa muhimu katika wakati muamala ulipofunguliwa, hata kama hifadhi itaendelea kusasishwa kikamilifu kwa wakati huu. Hiki ndicho kiini cha ugeuzaji anuwai, na kuifanya LMDB kuwa chanzo bora cha data kwa wapendwa wetu UICollectionView. Baada ya kufungua shughuli, hauitaji kuongeza alama ya kumbukumbu ya programu, haraka kusukuma data ya sasa katika muundo fulani wa kumbukumbu, ukiogopa kuachwa bila chochote. Kipengele hiki kinatofautisha LMDB kutoka kwa SQLite sawa, ambayo haiwezi kujivunia kutengwa kwa jumla. Baada ya kufungua shughuli mbili katika mwisho na kufuta rekodi fulani ndani ya mmoja wao, rekodi sawa haiwezi kupatikana tena ndani ya pili iliyobaki.

Upande wa pili wa sarafu ni uwezekano wa matumizi ya juu zaidi ya kumbukumbu pepe. Slaidi inaonyesha jinsi muundo wa hifadhidata utakavyokuwa ikiwa utarekebishwa kwa wakati mmoja na shughuli 3 za kusoma zilizo wazi zinazoangalia matoleo tofauti ya hifadhidata. Kwa kuwa LMDB haiwezi kutumia tena nodi ambazo zinaweza kufikiwa kutoka kwa mizizi inayohusishwa na miamala halisi, hifadhi haina chaguo ila kutenga mzizi mwingine wa nne kwenye kumbukumbu na kwa mara nyingine tena kuiga kurasa zilizorekebishwa chini yake.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Hapa haitakuwa mbaya sana kukumbuka sehemu kwenye faili zilizopangwa kwa kumbukumbu. Inaonekana kwamba utumiaji wa ziada wa kumbukumbu ya kawaida haupaswi kutusumbua sana, kwani haichangii alama ya kumbukumbu ya programu. Walakini, wakati huo huo, ilibainika kuwa iOS ni mbaya sana katika kuigawa, na hatuwezi kutoa eneo la LMDB la terabyte 1 kwenye seva au eneo-kazi kutoka kwa bega la bwana na tusifikirie juu ya kipengele hiki hata kidogo. Inapowezekana, unapaswa kujaribu kuweka maisha ya shughuli kuwa mafupi iwezekanavyo.

4. Kubuni schema ya data juu ya API ya ufunguo-thamani

Wacha tuanze kuchanganua API kwa kuangalia vifupisho vya msingi vilivyotolewa na LMDB: mazingira na hifadhidata, funguo na maadili, miamala na vielekezi.

Dokezo kuhusu uorodheshaji wa misimbo

Vitendaji vyote katika API ya umma ya LMDB hurejesha matokeo ya kazi yao katika mfumo wa msimbo wa hitilafu, lakini katika orodha zote zinazofuata hundi yake imeachwa kwa ajili ya ufupi. Kwa vitendo, tulitumia msimbo wetu kuingiliana na hazina. uma Vifungashio vya C++ lmdbxx, ambayo makosa hutokea kama ubaguzi wa C++.

Kama njia ya haraka sana ya kuunganisha LMDB kwa mradi wa iOS au macOS, ninatoa CocoaPod yangu POSLMDB.

4.1. Vifupisho vya msingi

Mazingira

Muundo MDB_env ni hifadhi ya hali ya ndani ya LMDB. Familia ya vitendaji vilivyoangaziwa mdb_env hukuruhusu kusanidi baadhi ya sifa zake. Katika kesi rahisi, uanzishaji wa injini inaonekana kama hii.

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

Katika programu ya Wingu la Mail.ru, tulibadilisha maadili ya msingi kwa vigezo viwili tu.

Ya kwanza ni saizi ya nafasi ya anwani pepe ambayo faili ya uhifadhi imepangwa. Kwa bahati mbaya, hata kwenye kifaa sawa, thamani maalum inaweza kutofautiana kwa kiasi kikubwa kutoka kukimbia hadi kukimbia. Ili kuzingatia kipengele hiki cha iOS, tunachagua kiwango cha juu zaidi cha hifadhi kwa nguvu. Kuanzia thamani fulani, inapunguza nusu mfululizo hadi chaguo la kukokotoa mdb_env_open haitarudisha matokeo zaidi ya ENOMEM. Kwa nadharia, kuna njia tofauti - kwanza toa kiwango cha chini cha kumbukumbu kwa injini, na kisha, wakati makosa yanapokelewa. MDB_MAP_FULL, ongeza. Hata hivyo, ni mwiba zaidi. Sababu ni kwamba utaratibu wa kurejesha kumbukumbu kwa kutumia kazi mdb_env_set_map_size hubatilisha huluki zote (mshale, miamala, funguo na thamani) zilizopokelewa kutoka kwa injini mapema. Uhasibu kwa zamu kama hiyo ya matukio katika kanuni itasababisha matatizo yake makubwa. Ikiwa, hata hivyo, kumbukumbu ya kawaida ni mpenzi sana kwako, basi hii inaweza kuwa sababu ya kuangalia uma ambao umeenda mbele. MDBX, ambapo kati ya vipengele vilivyotangazwa kuna "marekebisho ya ukubwa wa database ya moja kwa moja ya kuruka".

Kigezo cha pili, thamani ya chaguo-msingi ambayo haikutufaa, inasimamia mitambo ya kuhakikisha usalama wa nyuzi. Kwa bahati mbaya, angalau katika iOS 10, kuna matatizo na usaidizi wa uhifadhi wa ndani wa thread. Kwa sababu hii, katika mfano hapo juu, hifadhi inafunguliwa na bendera MDB_NOTLS. Kwa kuongeza, pia ilihitaji uma C++ kanga lmdbxxkukata vigeu na katika sifa hii.

Takwimu

Hifadhidata ni mfano tofauti wa mti wa B ambao tuliongelea hapo juu. Ufunguzi wake hutokea ndani ya shughuli, ambayo kwa mara ya kwanza inaweza kuonekana kuwa ya ajabu kidogo.

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

Hakika, muamala katika LMDB ni huluki ya hifadhi, si hifadhidata maalum. Dhana hii inakuwezesha kufanya shughuli za atomiki kwenye vyombo vilivyo katika hifadhidata tofauti. Kwa nadharia, hii inafungua uwezekano wa meza za mfano kwa namna ya hifadhidata tofauti, lakini wakati mmoja nilikwenda kwa njia nyingine, iliyoelezwa kwa undani hapa chini.

Vifunguo na maadili

Muundo MDB_val mifano ya dhana ya ufunguo na thamani. Hifadhi haina wazo kuhusu semantiki zao. Kwake, kitu ambacho ni tofauti ni safu tu ya baiti za saizi fulani. Ukubwa wa juu wa ufunguo ni 512 byte.

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

Hifadhi hutumia kilinganishi kupanga funguo kwa mpangilio wa kupanda. Usipoibadilisha na yako mwenyewe, basi ile chaguo-msingi itatumika, ambayo inazipanga kwa baiti kwa mpangilio wa leksikografia.

Shughuli

Kifaa cha muamala kimeelezewa kwa kina katika sura iliyopita, kwa hivyo hapa nitarudia mali zao kuu katika mstari mfupi:

  1. Msaada kwa mali zote za msingi ACIDManeno muhimu: atomiki, uthabiti, kutengwa na kuegemea. Siwezi kusaidia lakini kumbuka kuwa kwa suala la uimara kwenye macOS na iOS kuna mdudu uliowekwa katika MDBX. Unaweza kusoma zaidi katika wao README.
  2. Mbinu ya usomaji mwingi inaelezewa na mpango wa "mwandishi mmoja / wasomaji wengi". Waandishi huzuia kila mmoja, lakini hawazuii wasomaji. Wasomaji hawazuii waandishi au kila mmoja.
  3. Usaidizi kwa shughuli zilizowekwa.
  4. Usaidizi wa aina nyingi.

Multiversioning katika LMDB ni nzuri sana kwamba ninataka kuionyesha kwa vitendo. Nambari iliyo hapa chini inaonyesha kuwa kila shughuli inafanya kazi na toleo la hifadhidata ambalo lilikuwa muhimu wakati wa ufunguzi wake, likiwa limetengwa kabisa na mabadiliko yote yanayofuata. Kuanzisha hazina na kuongeza rekodi ya jaribio kwake hakuna riba, kwa hivyo mila hizi huachwa chini ya mharibifu.

Inaongeza ingizo la jaribio

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

Kwa hiari, ninapendekeza kujaribu hila sawa na SQLite na uone kinachotokea.

Multiversioning huleta manufaa mazuri sana kwa maisha ya msanidi wa iOS. Kwa kutumia kipengele hiki, unaweza kurekebisha kwa urahisi na kwa kawaida kiwango cha masasisho ya chanzo cha data kwa fomu za skrini kulingana na masuala ya uzoefu wa mtumiaji. Kwa mfano, hebu tuchukue kipengele kama hicho cha programu ya Wingu la Mail.ru kama upakiaji wa maudhui kiotomatiki kutoka kwa ghala la mfumo wa midia. Kwa muunganisho mzuri, mteja anaweza kuongeza picha kadhaa kwa sekunde kwenye seva. Ukisasisha baada ya kila upakuaji UICollectionView ukiwa na maudhui ya midia kwenye wingu la mtumiaji, unaweza kusahau kuhusu ramprogrammen 60 na kusogeza laini wakati wa mchakato huu. Ili kuzuia sasisho za skrini mara kwa mara, unahitaji kwa namna fulani kupunguza kiwango cha mabadiliko ya data kwa msingi UICollectionViewDataSource.

Ikiwa hifadhidata haiungi mkono ujumuishaji mwingi na hukuruhusu kufanya kazi na hali ya sasa tu, kisha kuunda muhtasari wa data wa wakati, unahitaji kuinakili kwa muundo fulani wa data ya kumbukumbu au kwa jedwali la muda. Yoyote ya njia hizi ni ghali sana. Kwa upande wa hifadhi ya kumbukumbu, tunapata gharama zote mbili za kumbukumbu zinazosababishwa na kuhifadhi vitu vilivyoundwa na gharama za muda zinazohusiana na mabadiliko yasiyohitajika ya ORM. Kuhusu meza ya muda, hii ni raha ya gharama kubwa zaidi, ambayo ina maana tu katika kesi zisizo ndogo.

Multiversioning LMDB hutatua tatizo la kudumisha chanzo thabiti cha data kwa njia ya kifahari sana. Inatosha tu kufungua shughuli na voila - hadi tutakapokamilisha, seti ya data imehakikishiwa kurekebishwa. Mantiki ya kasi yake ya usasishaji sasa iko mikononi mwa safu ya uwasilishaji, bila rasilimali nyingi muhimu.

Mishale

Vishale hutoa utaratibu wa kurudia kwa mpangilio juu ya jozi za thamani-msingi kwa kuvuka mti B. Bila wao, haitawezekana kuiga vizuri meza kwenye hifadhidata, ambayo sasa tunageukia.

4.2. Uundaji wa Jedwali

Sifa kuu ya kuagiza hukuruhusu kuunda kifupisho cha kiwango cha juu kama vile jedwali juu ya vifupisho vya msingi. Hebu fikiria mchakato huu kwa mfano wa meza kuu ya mteja wa wingu, ambayo habari kuhusu faili zote na folda za mtumiaji zimehifadhiwa.

Jedwali Schema

Mojawapo ya matukio ya kawaida ambayo muundo wa jedwali iliyo na mti wa folda unapaswa kunolewa ni kuchagua vipengele vyote vilivyo ndani ya saraka fulani. Mfano mzuri wa shirika la data kwa maswali bora ya aina hii ni. Orodha ya urafiki. Ili kutekeleza juu ya hifadhi ya ufunguo wa thamani, ni muhimu kupanga funguo za faili na folda kwa namna ambayo zimewekwa kwa makundi kulingana na mali ya saraka ya wazazi. Kwa kuongeza, ili kuonyesha yaliyomo kwenye saraka katika fomu inayojulikana kwa mtumiaji wa Windows (folda kwanza, kisha faili, zote mbili zimepangwa kwa alfabeti), ni muhimu kuingiza mashamba ya ziada yanayofanana kwenye ufunguo.

Picha iliyo hapa chini inaonyesha jinsi, kulingana na kazi, uwakilishi wa funguo kama safu ya baiti inaweza kuonekana kama. Kwanza, baiti zilizo na kitambulisho cha saraka kuu (nyekundu) huwekwa, kisha na aina (kijani), na tayari kwenye mkia wenye jina (bluu). Huku zikipangwa kwa kilinganishi chaguomsingi cha LMDB kwa mpangilio wa leksikografia, zimeagizwa katika njia inayotakiwa. Vifunguo vya kupitisha mfuatano vilivyo na kiambishi awali chekundu hutupatia thamani zinazohusishwa nazo katika mpangilio ambao zinapaswa kuonyeshwa kwenye kiolesura cha mtumiaji (kulia), bila kuhitaji uchakataji wowote wa ziada.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Kusawazisha Funguo na Maadili

Kuna njia nyingi za kusawazisha vitu kote ulimwenguni. Kwa kuwa hatukuwa na mahitaji mengine isipokuwa kasi, tulijichagulia moja ya haraka iwezekanavyo - dampo la kumbukumbu lililochukuliwa na mfano wa muundo wa lugha ya C. Kwa hivyo, ufunguo wa kipengele cha saraka unaweza kuigwa na muundo ufuatao. NodeKey.

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

Kuokoa NodeKey katika haja ya kuhifadhi katika kitu MDB_val weka pointer kwa data kwenye anwani ya mwanzo wa muundo, na uhesabu ukubwa wao na kazi sizeof.

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

Katika sura ya kwanza kuhusu vigezo vya uteuzi wa hifadhidata, nilitaja kupunguza mgao unaobadilika kama sehemu ya shughuli za CRUD kama kipengele muhimu cha uteuzi. Kanuni ya Kazi serialize inaonyesha jinsi, katika kesi ya LMDB, zinaweza kuepukwa kabisa wakati rekodi mpya zinaingizwa kwenye hifadhidata. Safu zinazoingia za baiti kutoka kwa seva hubadilishwa kwanza kuwa miundo ya rafu, na kisha hutupwa kwa kiasi kidogo kwenye hifadhi. Kwa kuzingatia kwamba pia hakuna mgao wa nguvu ndani ya LMDB, unaweza kupata hali nzuri kwa viwango vya iOS - tumia kumbukumbu ya stack tu kufanya kazi na data njia yote kutoka kwa mtandao hadi kwenye diski!

Kuagiza funguo na kulinganisha binary

Uhusiano wa utaratibu muhimu hutolewa na kazi maalum inayoitwa comparator. Kwa kuwa injini haijui chochote kuhusu semantiki za ka zilizomo, kilinganishi chaguo-msingi hana chaguo ila kupanga funguo kwa mpangilio wa leksikografia, akitumia ulinganisho wao wa byte-byte. Kuitumia kupanga miundo ni sawa na kunyoa kwa shoka la kuchonga. Walakini, katika hali rahisi, ninaona njia hii inakubalika. Njia mbadala imeelezewa hapa chini, lakini hapa nitagundua reki kadhaa zilizotawanyika njiani.

Jambo la kwanza kukumbuka ni uwakilishi wa kumbukumbu wa aina za data za awali. Kwa hiyo, kwenye vifaa vyote vya Apple, vigezo vya integer vinahifadhiwa katika muundo Endian mdogo. Hii inamaanisha kuwa baiti ndogo kabisa itakuwa upande wa kushoto, na hutaweza kupanga nambari kamili ukitumia ulinganisho wao wa baiti kwa baiti. Kwa mfano, kujaribu kufanya hivyo na seti ya nambari kutoka 0 hadi 511 itasababisha matokeo yafuatayo.

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

Ili kutatua tatizo hili, nambari kamili lazima zihifadhiwe katika ufunguo katika umbizo linalofaa kwa kilinganishi cha baiti. Kazi kutoka kwa familia zitasaidia kufanya mabadiliko muhimu. hton* (hasa htons kwa nambari za baiti mbili kutoka kwa mfano).

Umbizo la kuwakilisha kamba katika upangaji ni, kama unavyojua, nzima historia. Ikiwa semantiki ya kamba, pamoja na usimbuaji unaotumiwa kuwawakilisha kwenye kumbukumbu, unaonyesha kuwa kunaweza kuwa na zaidi ya byte moja kwa kila herufi, basi ni bora kuachana mara moja na wazo la kutumia kilinganishi chaguo-msingi.

Jambo la pili kukumbuka ni kanuni za upatanishi mkusanyaji wa uga wa muundo. Kwa sababu yao, ka zilizo na maadili ya takataka zinaweza kuunda katika kumbukumbu kati ya uwanja, ambayo, kwa kweli, huvunja upangaji wa kawaida. Ili kuondoa takataka, lazima utangaze shamba kwa mpangilio uliowekwa wazi, ukizingatia sheria za upatanishi, au utumie sifa katika tamko la muundo. packed.

Kuagiza muhimu kwa kilinganishi cha nje

Mantiki muhimu ya kulinganisha inaweza kugeuka kuwa ngumu sana kwa kulinganisha binary. Moja ya sababu nyingi ni uwepo wa nyanja za kiufundi ndani ya miundo. Nitaonyesha kutokea kwao kwa mfano wa ufunguo ambao tayari unajulikana kwetu kwa kipengele cha saraka.

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

Kwa unyenyekevu wake wote, katika idadi kubwa ya matukio hutumia kumbukumbu nyingi. Bafa ya kichwa ni baiti 256, ingawa kwa wastani majina ya faili na folda hayazidi vibambo 20-30.

Mojawapo ya mbinu za kawaida za kuboresha saizi ya rekodi ni kuikata ili kupatana na saizi yake halisi. Kiini chake ni kwamba yaliyomo katika nyanja zote za urefu wa kutofautiana huhifadhiwa kwenye bafa mwishoni mwa muundo, na urefu wao huhifadhiwa katika vigezo tofauti. Kwa mujibu wa mbinu hii, ufunguo. NodeKey inabadilishwa kwa njia ifuatayo.

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

Zaidi ya hayo, wakati wa kuratibu, haijabainishwa kama saizi ya data sizeof muundo mzima, na saizi ya sehemu zote ni urefu usiobadilika pamoja na saizi ya sehemu inayotumika ya bafa.

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

Kama matokeo ya kurekebisha tena, tulipata akiba kubwa katika nafasi iliyochukuliwa na funguo. Walakini, kwa sababu ya uwanja wa kiufundi nameLength, kilinganishi chaguo-msingi cha binary hakifai tena kwa ulinganisho mkuu. Ikiwa hatutaibadilisha na yetu wenyewe, basi urefu wa jina utakuwa jambo la kipaumbele zaidi katika kupanga kuliko jina lenyewe.

LMDB inaruhusu kila hifadhidata kuwa na kazi yake kuu ya kulinganisha. Hii inafanywa kwa kutumia kazi mdb_set_compare madhubuti kabla ya kufungua. Kwa sababu za wazi, hifadhidata haiwezi kubadilishwa katika maisha yake yote. Katika pembejeo, kulinganisha hupokea funguo mbili katika muundo wa binary, na kwa pato inarudi matokeo ya kulinganisha: chini ya (-1), kubwa kuliko (1) au sawa (0). Pseudocode kwa NodeKey inaonekana hivyo.

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 // ...
}​

Alimradi funguo zote kwenye hifadhidata ni za aina moja, ni halali kutuma uwakilishi wao bila masharti kwa aina ya muundo wa utumizi wa ufunguo. Kuna nuance moja hapa, lakini itajadiliwa chini kidogo katika kifungu cha "Rekodi za Kusoma".

Uwekaji Thamani

Kwa funguo za rekodi zilizohifadhiwa, LMDB inafanya kazi kwa bidii sana. Wanalinganishwa na kila mmoja ndani ya mfumo wa uendeshaji wowote wa maombi, na utendaji wa suluhisho zima inategemea kasi ya kulinganisha. Katika ulimwengu bora, kilinganishi chaguo-msingi cha binary kinapaswa kutosha kulinganisha funguo, lakini ikiwa kweli ilibidi utumie yako mwenyewe, basi utaratibu wa kuondoa funguo ndani yake unapaswa kuwa haraka iwezekanavyo.

Hifadhidata haivutiwi haswa na Sehemu ya Thamani ya rekodi (thamani). Uongofu wake kutoka kwa uwakilishi wa byte hadi kitu hutokea tu wakati tayari inahitajika na msimbo wa maombi, kwa mfano, ili kuionyesha kwenye skrini. Kwa kuwa hii hutokea mara chache, mahitaji ya kasi ya utaratibu huu sio muhimu sana, na katika utekelezaji wake tuko huru zaidi kuzingatia urahisi.Kwa mfano, kusawazisha metadata kuhusu faili ambazo bado hazijapakuliwa, tunatumia. NSKeyedArchiver.

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

Walakini, kuna nyakati ambapo utendaji ni muhimu. Kwa mfano, wakati wa kuhifadhi meta-habari kuhusu muundo wa faili wa wingu la mtumiaji, tunatumia utupaji wa kumbukumbu ya kitu sawa. Kivutio cha kazi ya kutoa uwakilishi wao wa mfululizo ni ukweli kwamba vipengele vya saraka huigwa na daraja la darasa.​

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Kwa utekelezaji wake katika lugha ya C, nyanja maalum za warithi huchukuliwa kwa miundo tofauti, na uunganisho wao na msingi huelezwa kupitia uwanja wa aina ya umoja. Maudhui halisi ya muungano yamebainishwa kupitia aina ya sifa ya kiufundi.

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

Kuongeza na kusasisha rekodi

Kitufe cha serialized na thamani inaweza kuongezwa kwenye duka. Kwa hili, kazi hutumiwa mdb_put.

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

Katika hatua ya usanidi, hazina inaweza kuruhusiwa au kuzuiwa kuhifadhi rekodi nyingi kwa ufunguo sawa.​ Iwapo kurudia funguo kumepigwa marufuku, basi unapoingiza rekodi, unaweza kubainisha ikiwa kusasisha rekodi iliyopo tayari kunaruhusiwa au la. Ikiwa utapeli unaweza kutokea tu kama matokeo ya kosa katika nambari, basi unaweza kuhakikisha dhidi yake kwa kutaja bendera. NOOVERWRITE.

Kusoma Rekodi

Kazi ya kusoma rekodi katika LMDB ni mdb_get. Ikiwa jozi ya thamani ya ufunguo inawakilishwa na miundo iliyotupwa hapo awali, basi utaratibu huu unaonekana kama hii.

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

Uorodheshaji uliowasilishwa unaonyesha jinsi usanifu kupitia utupaji wa miundo hukuruhusu kuondoa ugawaji wa nguvu sio tu wakati wa kuandika, lakini wakati wa kusoma data. Imetokana na utendaji mdb_get pointer inaonekana haswa kwenye anwani ya kumbukumbu ya kawaida ambapo hifadhidata huhifadhi uwakilishi wa kitu. Kwa kweli, tunapata aina ya ORM, karibu bila malipo kutoa kasi ya juu sana ya kusoma data. Pamoja na uzuri wote wa mbinu, ni muhimu kukumbuka vipengele kadhaa vinavyohusishwa nayo.

  1. Kwa muamala wa kusoma pekee, kielekezi kwa muundo wa thamani kinahakikishiwa kubaki halali hadi muamala ufungwe. Kama ilivyobainishwa hapo awali, kurasa za mti B ambamo kitu kinakaa, kutokana na kanuni ya kunakili-kwa-kuandika, hubakia bila kubadilika mradi angalau shughuli moja inarejelea. Wakati huo huo, mara tu shughuli ya mwisho inayohusishwa nao imekamilika, kurasa zinaweza kutumika tena kwa data mpya. Ikiwa ni muhimu kwa vitu kuishi katika shughuli iliyowaumba, basi bado wanapaswa kunakiliwa.
  2. Kwa muamala wa kusoma, kielekezi cha thamani-muundo inayotokana itakuwa halali tu hadi utaratibu wa kwanza wa kurekebisha (kuandika au kufuta data).
  3. Ingawa muundo NodeValue sio kamili, lakini imepunguzwa (angalia kifungu kidogo "Vifunguo vya kuagiza na kilinganishi cha nje"), kupitia pointer, unaweza kufikia mashamba yake kwa urahisi. Jambo kuu sio kuidharau!
  4. Hakuna kesi unaweza kurekebisha muundo kupitia pointer iliyopokelewa. Mabadiliko yote lazima yafanywe tu kupitia njia mdb_put. Hata hivyo, kwa hamu yote ya kufanya hivyo, haitafanya kazi, kwa kuwa eneo la kumbukumbu ambalo muundo huu unapatikana limepangwa katika hali ya kusoma tu.
  5. Rudisha faili kwenye nafasi ya anwani ya mchakato ili, kwa mfano, kuongeza ukubwa wa juu wa hifadhi kwa kutumia chaguo la kukokotoa mdb_env_set_map_size inabatilisha kabisa shughuli zote na huluki zinazohusiana kwa ujumla na viashiria vya kusoma vitu haswa.

Hatimaye, kipengele kimoja zaidi ni cha hila hivi kwamba ufichuzi wa kiini chake hauingii katika nukta moja zaidi. Katika sura ya B-mti, nilitoa mchoro wa shirika la kurasa zake katika kumbukumbu. Inafuata kutoka kwake kwamba anwani ya mwanzo wa buffer na data ya serial inaweza kuwa ya kiholela kabisa. Kwa sababu ya hili, pointer kwao, iliyopatikana katika muundo MDB_val na kutupwa kwa pointer kwa muundo kwa ujumla haijasawazishwa. Wakati huo huo, usanifu wa baadhi ya chips (katika kesi ya iOS, hii ni armv7) inahitaji kwamba anwani ya data yoyote iwe nyingi ya ukubwa wa neno la mashine, au, kwa maneno mengine, udogo wa mfumo. (kwa armv7, hii ni bits 32). Kwa maneno mengine, operesheni kama *(int *foo)0x800002 juu yao ni sawa na kutoroka na kupelekea kutekelezwa kwa hukumu EXC_ARM_DA_ALIGN. Kuna njia mbili za kuzuia hatima kama hiyo ya kusikitisha.

Ya kwanza ni kunakili data katika muundo unaojulikana kabla. Kwa mfano, kwenye kilinganishi maalum, hii itaonyeshwa kama ifuatavyo.

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 // ...
}

Njia mbadala ni kumjulisha mkusanyaji mapema kwamba miundo iliyo na ufunguo na thamani haiwezi kuunganishwa kwa kutumia sifa. aligned(1). Kwenye ARM athari sawa inaweza kuwa ili kufikia na kutumia sifa iliyojaa. Kwa kuzingatia kwamba pia inachangia uboreshaji wa nafasi iliyochukuliwa na muundo, njia hii inaonekana kwangu kuwa bora, ingawa приводит kuongeza gharama ya shughuli za ufikiaji wa data.

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

Maswali mbalimbali

Ili kusisitiza juu ya kundi la rekodi, LMDB hutoa kichocheo cha mshale. Wacha tuangalie jinsi ya kufanya kazi nayo kwa kutumia mfano wa jedwali iliyo na metadata ya wingu ya mtumiaji ambayo tayari inajulikana kwetu.

Kama sehemu ya kuonyesha orodha ya faili kwenye saraka, unahitaji kupata funguo zote ambazo faili na folda zake za watoto zinahusishwa. Katika vifungu vilivyotangulia, tulipanga funguo NodeKey ili waagizwe kwanza na kitambulisho cha saraka ya mzazi. Kwa hivyo, kitaalam, kazi ya kupata yaliyomo kwenye folda imepunguzwa kwa kuweka mshale kwenye mpaka wa juu wa kikundi cha funguo na kiambishi awali, ikifuatiwa na kurudia kwa mpaka wa chini.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Unaweza kupata kifungo cha juu "kwenye paji la uso" kwa utafutaji wa mfululizo. Ili kufanya hivyo, mshale umewekwa mwanzoni mwa orodha nzima ya funguo kwenye hifadhidata na kisha kuongezwa hadi ufunguo na kitambulisho cha saraka ya mzazi inaonekana chini yake. Njia hii ina mapungufu 2 dhahiri:

  1. Utata wa mstari wa utafutaji, ingawa, kama unavyojua, katika miti kwa ujumla na katika mti wa B hasa, unaweza kufanywa kwa wakati wa logarithmic.
  2. Kwa bure, kurasa zote zinazotangulia ile inayotaka zinainuliwa kutoka kwa faili hadi kumbukumbu kuu, ambayo ni ghali sana.

Kwa bahati nzuri, API ya LMDB hutoa njia bora ya kuweka kielekezi mwanzoni. Ili kufanya hivyo, unahitaji kuunda kitufe ambacho thamani yake inajulikana kuwa chini ya au sawa na kitufe kilicho kwenye sehemu ya juu ya muda. Kwa mfano, kuhusiana na orodha katika takwimu hapo juu, tunaweza kufanya ufunguo ambao shamba parentId itakuwa sawa na 2, na wengine wote wamejaa sifuri. Kitufe kama hicho kilichojazwa kwa sehemu kinalishwa kwa ingizo la chaguo la kukokotoa mdb_cursor_get kuashiria operesheni 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);

Ikiwa sehemu ya juu ya kikundi cha funguo inapatikana, basi tunairudia hadi tukutane au ufunguo na mwingine. parentId, au funguo hazitaisha hata kidogo

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​​

Nini ni nzuri, kama sehemu ya iteration kutumia mdb_cursor_get, sisi kupata si tu muhimu, lakini pia thamani. Ikiwa, ili kutimiza masharti ya uteuzi, ni muhimu kuangalia, kati ya mambo mengine, mashamba kutoka kwa sehemu ya thamani ya rekodi, basi wanapatikana kabisa kwao wenyewe bila ishara za ziada.

4.3. Kuunda uhusiano kati ya meza

Hadi sasa, tumeweza kuzingatia vipengele vyote vya kubuni na kufanya kazi na hifadhidata ya meza moja. Tunaweza kusema kwamba jedwali ni seti ya rekodi zilizopangwa zinazojumuisha jozi za thamani-msingi za aina moja. Ukionyesha ufunguo kama mstatili na thamani yake inayohusishwa kama kisanduku, unapata mchoro unaoonekana wa hifadhidata.

â € <

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Walakini, katika maisha halisi, ni nadra sana kuweza kuishi na damu kidogo. Mara nyingi katika hifadhidata inahitajika, kwanza, kuwa na meza kadhaa, na pili, kutekeleza chaguzi ndani yao kwa mpangilio tofauti na ufunguo wa msingi. Sehemu hii ya mwisho imejitolea kwa maswala ya uundaji wao na muunganisho.

Majedwali ya index

Programu ya wingu ina sehemu ya "Matunzio". Inaonyesha maudhui ya midia kutoka kwa wingu zima, yaliyopangwa kulingana na tarehe. Kwa utekelezaji bora wa uteuzi kama huo, karibu na meza kuu, unahitaji kuunda nyingine na aina mpya ya funguo. Zitakuwa na sehemu iliyo na tarehe ambayo faili iliundwa, ambayo itafanya kama kigezo cha msingi cha kupanga. Kwa sababu funguo mpya hurejelea data sawa na funguo katika jedwali la msingi, zinaitwa funguo za index. Wao ni yalionyesha katika machungwa katika picha hapa chini.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Ili kutenganisha funguo za jedwali tofauti kutoka kwa kila mmoja ndani ya hifadhidata sawa, Jedwali la ziada la uwanja wa kiufundi limeongezwa kwa zote. Kwa kuifanya kuwa kipaumbele cha juu zaidi cha kupanga, tutaweka funguo kwanza kwa meza, na tayari ndani ya meza - kulingana na sheria zetu wenyewe.

Kitufe cha faharasa kinarejelea data sawa na ufunguo msingi. Utekelezaji wa moja kwa moja wa mali hii kwa kuhusisha nayo nakala ya sehemu ya thamani ya ufunguo msingi ni mdogo kutoka kwa maoni kadhaa mara moja:

  1. Kutoka kwa mtazamo wa nafasi iliyochukuliwa, metadata inaweza kuwa tajiri sana.
  2. Kutoka kwa mtazamo wa utendaji, kwani wakati wa kusasisha metadata ya nodi, itabidi ubadilishe funguo mbili.
  3. Kutoka kwa mtazamo wa usaidizi wa kificho, baada ya yote, ikiwa tunasahau kusasisha data kwa moja ya funguo, tutapata hitilafu ya hila ya kutofautiana kwa data katika hifadhi.

Ifuatayo, tutazingatia jinsi ya kuondoa mapungufu haya.

Shirika la mahusiano kati ya meza

Mchoro unafaa kwa kuunganisha meza ya index na moja kuu "ufunguo kama thamani". Kama jina lake linamaanisha, sehemu ya thamani ya rekodi ya faharisi ni nakala ya thamani kuu ya msingi. Mbinu hii huondoa hasara zote zilizoorodheshwa hapo juu zinazohusiana na kuhifadhi nakala ya sehemu ya thamani ya rekodi ya msingi. Ada pekee ni kwamba ili kupata thamani kwa ufunguo wa faharisi, unahitaji kuuliza maswali 2 kwenye hifadhidata badala ya moja. Kwa utaratibu, schema ya hifadhidata inayosababishwa ni kama ifuatavyo.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Mfano mwingine wa kuandaa uhusiano kati ya meza ni "ufunguo usiohitajika". Kiini chake ni kuongeza sifa za ziada kwa ufunguo, ambazo hazihitajiki kwa kupanga, lakini kwa kuunda tena ufunguo unaohusishwa.Kuna mifano halisi ya matumizi yake katika programu ya Wingu la Mail.ru, hata hivyo, ili kuepuka kupiga mbizi kwa kina kwenye muktadha wa mifumo maalum ya iOS, nitatoa uwongo, lakini mfano unaoeleweka zaidi.

Wateja wa rununu wa Wingu wana ukurasa unaoonyesha faili na folda zote ambazo mtumiaji ameshiriki na watu wengine. Kwa kuwa kuna faili chache kama hizo, na kuna habari nyingi maalum juu ya utangazaji unaohusishwa nazo (ambao ufikiaji unapewa, na haki gani, nk), haitakuwa busara kuzibeba na sehemu ya dhamana ya rekodi kwenye jedwali kuu. Hata hivyo, ikiwa unataka kuonyesha faili hizo nje ya mtandao, basi bado unahitaji kuzihifadhi mahali fulani. Suluhisho la asili ni kuunda meza tofauti kwa ajili yake. Katika mchoro ulio hapa chini, ufunguo wake umewekwa awali na "P", na kishikilia nafasi cha "propname" kinaweza kubadilishwa na thamani maalum zaidi "maelezo ya umma".

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Metadata zote za kipekee, kwa ajili yake ambazo jedwali jipya liliundwa, huhamishwa hadi sehemu ya thamani ya rekodi. Wakati huo huo, sitaki kurudia data kuhusu faili na folda ambazo tayari zimehifadhiwa kwenye jedwali kuu. Badala yake, data isiyohitajika huongezwa kwenye kitufe cha "P" kwa njia ya sehemu za "kitambulisho cha nodi" na "muhuri wa muda". Shukrani kwao, unaweza kuunda ufunguo wa index, ambayo unaweza kupata ufunguo wa msingi, ambao, hatimaye, unaweza kupata metadata ya node.

Hitimisho

Tunatathmini matokeo ya utekelezaji wa LMDB vyema. Baada yake, idadi ya kufungia maombi ilipungua kwa 30%.

Uzuri na umaskini wa hifadhidata ya thamani kuu ya LMDB katika programu za iOS

Matokeo ya kazi iliyofanywa yamepata jibu nje ya timu ya iOS. Hivi sasa, moja ya sehemu kuu za "Faili" kwenye programu ya Android pia imebadilisha kutumia LMDB, na sehemu zingine ziko njiani. Lugha ya C, ambamo hifadhi ya thamani-msingi inatekelezwa, ilikuwa usaidizi mzuri ili kufanya programu iunganishe kuzunguka jukwaa-msingi katika lugha ya C ++. Kwa muunganisho usio na mshono wa maktaba ya C ++ iliyosababishwa na nambari ya jukwaa katika Lengo-C na Kotlin, jenereta ya nambari ilitumiwa. Djinni kutoka kwa Dropbox, lakini hiyo ni hadithi nyingine.

Chanzo: mapenzi.com

Kuongeza maoni