Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Nan sezon otòn la nan 2019, yon evènman long dire ki te fèt nan ekip la Mail.ru Cloud iOS. Baz done prensipal la pou depo ki pèsistan nan eta aplikasyon an te vin trè ekzotik pou mond lan mobil Zeklè memwa-mape baz done (LMDB). Anba koupe a nou ofri ou yon revizyon detaye sou li an kat pati. Premyèman, ann pale sou rezon ki fè yo yon chwa ki pa trivial ak difisil. Lè sa a, nou pral kontinye konsidere twa poto yo nan kè a nan achitekti LMDB la: dosye memwa-map, B+-tree, apwòch kopi-sou-ekri pou mete ann aplikasyon tranzaksyon ak multivèsyon. Finalman, pou desè - pati nan pratik. Nan li nou pral gade nan ki jan yo konsepsyon ak aplike yon chema baz done ak plizyè tab, ki gen ladan yon endèks youn, sou tèt API a ki ba-nivo kle-valè.

Content

  1. Motivasyon pou aplikasyon
  2. Pozisyon LMDB
  3. Twa poto LMDB
    3.1. Balèn #1. Fichye ki gen kat memwa
    3.2. Balèn #2. B+-pyebwa
    3.3. Balèn #3. Kopi-sou-ekri
  4. Konsepsyon yon chema done sou tèt API kle-valè
    4.1. Abstraksyon debaz yo
    4.2. Modèl tab
    4.3. Modèl relasyon ant tab yo

1. Motivasyon pou aplikasyon

Yon ane nan 2015, nou te pran pwoblèm nan mezire konbyen fwa koòdone nan aplikasyon nou an reta. Nou te fè sa pou yon rezon. Nou te resevwa plent pi souvan ke pafwa aplikasyon an sispann reponn a aksyon itilizatè yo: bouton yo pa ka peze, lis pa woule, elatriye. Konsènan mekanik mezi yo te di sou AvitoTech, kidonk isit la mwen bay sèlman lòd nimewo yo.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Rezilta mezi yo te vin tounen yon douch frèt pou nou. Li te tounen soti ke gen anpil plis pwoblèm ki te koze pa jele pase nenpòt lòt. Si anvan reyalize reyalite sa a prensipal endikatè teknik bon jan kalite a te aksidan gratis, Lè sa a, apre konsantre an deplase sou friz gratis.

Èske w gen bati tablodbò ak jele epi apre depans quantitative и bon jan kalite analiz de rezon yo, lènmi prensipal la te vin klè - lojik biznis lou egzekite nan fil prensipal la nan aplikasyon an. Reyaksyon natirèl la nan wont sa a se te yon dezi boule pouse li nan kouran travay. Pou rezoud pwoblèm sa a sistematikman, nou te itilize yon achitekti milti-threaded ki baze sou aktè ki lejè. Mwen dedye li nan adaptasyon li yo pou mond lan iOS de fil sou Twitter kolektif ak atik sou Habré. Kòm yon pati nan naratif aktyèl la, mwen vle mete aksan sou aspè sa yo nan desizyon an ki enfliyanse chwa baz done a.

​Modèl aktè nan òganizasyon sistèm sipoze ke multithreading vin dezyèm sans li yo. Modèl objè nan li renmen travèse fwontyè kouran dlo. Apre sa, yo pa fè sa pafwa ak isit la ak la, men prèske toujou ap ak toupatou

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Baz done a se youn nan eleman prensipal yo nan dyagram prezante a. Travay prensipal li se aplike macropattern la Baz done pataje. Si nan mond lan antrepriz li itilize yo òganize senkronizasyon done ant sèvis, Lè sa a, nan ka a nan achitekti aktè - done ant fil. Kidonk, nou te bezwen yon baz done ki pa ta lakòz menm difikilte minim lè w ap travay avèk li nan yon anviwònman milti-threaded. An patikilye, sa vle di ke objè yo jwenn nan li yo dwe omwen fil ki an sekirite, epi depreferans konplètman ki pa ka chanje. Kòm ou konnen, lèt la ka itilize ansanm nan plizyè fil san yo pa recourir nan nenpòt ki bloke, ki gen yon efè benefik sou pèfòmans.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yoDezyèm faktè enpòtan ki te enfliyanse chwa baz done a se te API nwaj nou an. Li te enspire pa apwòch la senkronizasyon adopte pa git. Menm jan ak li, nou vize a offline-premye API, ki sanble pi plis pase apwopriye pou kliyan nwaj yo. Yo te sipoze ke yo ta sèlman ponpe eta a plen nan nwaj la yon fwa, ak Lè sa a, senkronizasyon nan akablan majorite nan ka yo ta rive nan woule soti chanjman. Ay, opòtinite sa a se toujou sèlman nan zòn nan teyorik, ak kliyan pa te aprann ki jan yo travay ak plak nan pratik. Gen yon kantite rezon objektif pou sa, ki, nan lòd pa retade entwodiksyon an, nou pral kite dèyè parantèz. Koulye a, sa ki pi plis enterè se konklizyon edikatif leson an sou sa k ap pase lè yon API di "A" epi konsomatè li pa di "B".

Se konsa, si ou imajine git, ki, lè w ap egzekite yon lòd rale, olye pou yo aplike plak nan yon snapshot lokal, konpare eta konplè li yo ak eta sèvè konplè a, Lè sa a, ou pral gen yon lide jistis egzat sou ki jan senkronizasyon rive nan nwaj. kliyan. Li fasil devine ke pou aplike li, ou bezwen asiyen de pyebwa DOM nan memwa ak meta-enfòmasyon sou tout sèvè ak dosye lokal yo. Li sanble ke si yon itilizatè estoke 500 mil dosye nan nwaj la, Lè sa a, senkronize li li nesesè rkree ak detwi de pye bwa ak 1 milyon dola nœuds. Men, chak ne se yon total ki gen yon graf subobjects. Nan limyè sa a, rezilta profilage yo te espere. Li te tounen soti ke menm san yo pa pran an kont algorithm nan fizyone, pwosedi a anpil nan kreye ak imedyatman detwi yon gwo kantite ti objè koute yon pyès lajan bèl. Se sitiyasyon an agrave pa lefèt ke se operasyon an senkronizasyon debaz enkli nan yon gwo kantite. nan scripts itilizatè yo. Kòm yon rezilta, nou ranje dezyèm kritè enpòtan nan chwazi yon baz done - kapasite nan aplike operasyon CRUD san alokasyon dinamik nan objè yo.

Lòt kondisyon yo pi tradisyonèl ak tout lis yo se jan sa a.

  1. Sekirite fil.
  2. Multiprocessing. Dikte pa dezi a sèvi ak menm egzanp baz done a senkronize eta pa sèlman ant fil, men tou, ant aplikasyon prensipal la ak ekstansyon iOS.
  3. Kapasite pou reprezante antite ki estoke kòm objè ki pa ka chanje.​
  4. Pa gen alokasyon dinamik nan operasyon CRUD yo.
  5. Sipò tranzaksyon pou pwopriyete debaz yo ASID: atomite, konsistans, izolasyon ak fyab.
  6. Vitès sou ka ki pi popilè yo.

Avèk sa a seri kondisyon, SQLite te e li rete yon bon chwa. Sepandan, kòm yon pati nan etid la nan altènatif, mwen te vin atravè yon liv "Kòmanse ak LevelDB". Anba lidèchip li, yo te ekri yon referans ki konpare vitès travay la ak baz done diferan nan senaryo nwaj reyèl. Rezilta a depase atant pi sovaj nou yo. Nan ka ki pi popilè yo - jwenn yon kurseur sou yon lis Ranje nan tout dosye ak yon lis Ranje nan tout dosye pou yon anyè bay yo - LMDB te tounen soti yo dwe 10 fwa pi vit pase SQLite. Chwa a te vin evidan.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

2. LMDB Pozisyon

LMDB se yon ti bibliyotèk (sèlman 10K ranje) ki aplike kouch fondamantal ki pi ba nan baz done - depo.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Dyagram ki pi wo a montre ke konpare LMDB ak SQLite, ki tou aplike pi wo nivo, jeneralman pa pi kòrèk pase SQLite ak Done Nwayo. Li ta pi jis pou site menm motè depo yo kòm konpetitè egal - BerkeleyDB, LevelDB, Sophia, RocksDB, elatriye Gen menm devlopman kote LMDB aji kòm yon eleman motè depo pou SQLite. Premye eksperyans sa yo te nan 2012 depanse pa LMDB Howard Chu. Jwenn te vin tèlman entrigan ke inisyativ li te ranmase pa amater OSS, e li te jwenn kontinyasyon li nan moun nan. LumoSQL. Nan mwa janvye 2020, otè pwojè sa a se te Den Shearer prezante li nan LinuxConfAu.

LMDB se sitou itilize kòm yon motè pou baz done aplikasyon yo. Bibliyotèk la dwe aparans li bay devlopè yo openldap, ki te trè satisfè ak BerkeleyDB kòm baz pou pwojè yo. Kòmanse nan yon bibliyotèk modès btree, Howard Chu te kapab kreye youn nan altènativ ki pi popilè nan tan nou an. Li dedye rapò trè fre li a nan istwa sa a, osi byen ke nan estrikti entèn LMDB. "Baz done ki gen kat memwa Zeklè a". Yon bon egzanp konkeri yon etablisman depo te pataje pa Leonid Yuryev (aka yleo) soti nan teknoloji pozitif nan rapò li nan Highload 2015 "Motè LMDB a se yon chanpyon espesyal". Nan li, li pale sou LMDB nan yon kontèks travay menm jan an nan aplikasyon ReOpenLDAP, ak LevelDB te deja sijè a kritik konparatif. Kòm yon rezilta nan aplikasyon an, teknoloji pozitif menm te gen yon fouchèt aktivman devlope MDBX ak karakteristik trè bon gou, optimize ak bugfixes.

LMDB yo souvan itilize kòm yon depo tankou-se. Pou egzanp, navigatè Mozilla Firefox te chwazi li pou yon kantite bezwen, epi, kòmanse nan vèsyon 9, Xcode prefere SQLite li yo pou estoke endèks.

Te motè a tou fè mak li nan mond lan nan devlopman mobil. Tras nan itilizasyon li yo ka jwenn nan kliyan iOS pou Telegram. LinkedIn te ale menm pi lwen e li te chwazi LMDB kòm depo default pou kach kachèt done lakay li yo Rocket Data, sou ki te di nan atik li an 2016.

LMDB ap goumen avèk siksè pou yon plas nan solèy la nan Tanporèman nich la kite pa BerkeleyDB apre li te vin anba kontwòl la nan Oracle. Bibliyotèk la renmen pou vitès li ak fyab, menm konpare ak kamarad li yo. Kòm ou konnen, pa gen okenn manje midi gratis, e mwen ta renmen mete aksan sou komès la ke w ap gen pou fè fas a lè w ap chwazi ant LMDB ak SQLite. Dyagram ki anwo a montre klèman ki jan vitès ogmante. Premyèman, nou pa peye pou kouch adisyonèl nan distraksyon sou tèt depo disk. Li klè ke yon bon achitekti toujou pa ka fè san yo, epi yo pral inevitableman parèt nan kòd aplikasyon an, men yo pral pi sibtil. Yo p ap genyen karakteristik ki pa obligatwa pa yon aplikasyon espesifik, pou egzanp, sipò pou demann nan lang SQL. Dezyèmman, li vin posib pou pi byen aplike kat operasyon aplikasyon sou demann nan depo ki gen kapasite. Si SQLite nan travay mwen se baze sou bezwen an mwayèn estatistik nan yon aplikasyon mwayèn, Lè sa a, ou, kòm yon devlopè aplikasyon, yo byen okouran de senaryo chaj travay prensipal yo. Pou yon solisyon ki pi pwodiktif, ou pral oblije peye yon pri ogmante tou de pou devlopman nan solisyon inisyal la ak pou sipò ki vin apre li yo.

3. Twa poto LMDB

Lè w fin gade LMDB a nan yon je zwazo, li te tan pou w ale pi fon. Twa pwochen seksyon yo pral konsakre nan yon analiz de poto prensipal yo sou ki achitekti depo a chita:

  1. Fichye memwa-map kòm yon mekanis pou travay ak disk ak senkronize estrikti done entèn yo.
  2. B+-tree kòm yon òganizasyon nan estrikti a nan done ki estoke.
  3. Kopi-sou-ekri kòm yon apwòch bay pwopriyete tranzaksyon ACID ak multiversion.

3.1. Balèn #1. Fichye ki gen kat memwa

Fichye memwa-map yo se tankou yon eleman enpòtan achitekti ke yo menm parèt nan non an nan depo a. Pwoblèm nan kachèt ak senkronizasyon nan aksè nan enfòmasyon ki estoke yo antyèman kite nan sistèm nan fonksyone. LMDB pa genyen okenn kachèt nan tèt li. Sa a se yon desizyon konsyan pa otè a, depi lekti done ki sòti dirèkteman nan dosye kat pèmèt ou koupe yon anpil nan kwen nan aplikasyon an motè. Anba la a se yon lis lwen soti nan konplè nan kèk nan yo.

  1. Kenbe konsistans nan done nan depo a lè w ap travay ak li nan plizyè pwosesis vin responsablite nan sistèm nan fonksyone. Nan pwochen seksyon an, mekanik sa a diskite an detay ak foto.
  2. Absans la nan kachèt konplètman elimine LMDB soti nan tèt yo ki asosye ak alokasyon dinamik. Lekti done nan pratik vle di mete yon konsèy sou adrès ki kòrèk la nan memwa vityèl e pa gen anyen plis. Li son tankou syans fiksyon, men nan kòd la sous depo tout apèl nan calloc yo konsantre nan fonksyon an konfigirasyon depo.
  3. Absans kachèt vle di tou absans kadna ki asosye ak senkronizasyon aksè yo. Lektè yo, ki ka gen yon kantite abitrè nan lektè an menm tan an, pa rankontre yon sèl mutex sou wout yo nan done yo. Akòz sa a, vitès lekti a gen évolutivité lineyè ideyal ki baze sou kantite CPU. Nan LMDB, sèlman modifye operasyon yo senkronize. Ka sèlman yon ekriven nan yon moman.
  4. Yon minimòm de lojik kachèt ak senkronizasyon elimine kalite erè ki trè konplèks ki asosye ak travay nan yon anviwònman milti-threaded. Te gen de etid baz done enteresan nan konferans Usenix OSDI 2014 la: "Tout sistèm dosye yo pa kreye egal: sou konpleksite nan fabrike aplikasyon aksidan ki konsistan" и "Tortire baz done pou plezi ak pwofi". Nan men yo ou ka ranmase enfòmasyon sou tou de fyab san parèy nan LMDB ak aplikasyon an prèske san defo nan pwopriyete tranzaksyon ACID, ki se siperyè ak sa yo ki nan SQLite.
  5. Minimalism nan LMDB pèmèt reprezantasyon machin nan kòd li yo dwe konplètman sitiye nan kachèt L1 nan processeur a ak karakteristik sa yo vitès.

Malerezman, nan iOS, ak dosye memwa-map, tout bagay se pa tankou nwaj jan nou ta renmen. Pou pale sou enpèfeksyon ki asosye ak yo plis konsyans, li nesesè sonje prensip jeneral yo nan aplikasyon mekanis sa a nan sistèm opere.

Enfòmasyon jeneral sou dosye memwa-map

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yoAvèk chak aplikasyon ki kouri, sistèm operasyon an asosye yon antite ki rele yon pwosesis. Chak pwosesis resevwa yon seri de adrès kote li mete tout bagay li bezwen pou opere. Nan adrès ki pi ba yo gen seksyon ki gen kòd ak done ak resous ki kode difisil. Apre vini yon blòk k ap grandi nan espas adrès dinamik, byen li te ye pou nou anba pil non an. Li gen adrès antite ki parèt pandan operasyon pwogram nan. Nan tèt la se zòn nan memwa itilize pa chemine aplikasyon an. Li swa grandi oswa kontra; nan lòt mo, gwosè li tou gen yon nati dinamik. Pou anpeche pil la ak pil pouse ak entèfere youn ak lòt, yo sitiye nan diferan bout nan espas adrès la. Gen yon twou ant de seksyon dinamik nan tèt la ak anba. Sistèm operasyon an itilize adrès nan mitan seksyon sa a pou asosye yon varyete antite ak pwosesis la. An patikilye, li ka asosye yon sèten seri adrès kontinyèl ak yon dosye sou disk la. Yo rele yon dosye konsa memory-mapped.​

Espas adrès ki afekte pwosesis la se gwo. Teyorikman, kantite adrès limite sèlman pa gwosè a nan konsèy la, ki se detèmine pa kapasite nan ti nan sistèm nan. Si memwa fizik yo te trase sou li 1-a-1, Lè sa a, premye pwosesis la ta gobble tout RAM la, epi pa ta gen okenn pale sou nenpòt ki multitech.

Sepandan, apati eksperyans nou nou konnen ke sistèm opere modèn yo ka an menm tan egzekite anpil pwosesis jan yo vle. Sa a se posib akòz lefèt ke yo sèlman asiyen yon anpil nan memwa nan pwosesis sou papye, men an reyalite yo chaje nan memwa fizik prensipal la sèlman pati sa a ki se nan demann isit la e kounye a. Se poutèt sa, yo rele memwa ki asosye ak yon pwosesis vityèl.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Sistèm operasyon an òganize memwa vityèl ak fizik nan paj yon gwosè sèten. Le pli vit ke yon sèten paj memwa vityèl se nan demann, sistèm nan fonksyone chaje li nan memwa fizik ak matche ak yo nan yon tablo espesyal. Si pa gen okenn plas gratis, Lè sa a, youn nan paj ki te deja chaje yo kopye sou disk la, ak youn nan demann lan pran plas li. Pwosedi sa a, ke nou pral retounen nan yon ti tan, yo rele swapping. Figi ki anba a montre pwosesis ki dekri a. Sou li, paj A ak adrès 0 yo te chaje epi yo mete l sou paj memwa prensipal la ak adrès 4. Reyalite sa a te reflete nan tablo korespondans nan nimewo selil 0 la.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Istwa a se egzakteman menm bagay la ak dosye trase nan memwa. Lojikman, yo swadizan kontinyèlman ak antyèman sitiye nan espas adrès la vityèl. Sepandan, yo antre nan memwa fizik paj pa paj epi sèlman sou demann. Modifikasyon nan paj sa yo senkronize ak dosye a sou disk. Nan fason sa a, ou ka fè I/O dosye lè w tou senpleman travay ak bytes nan memwa - tout chanjman yo pral otomatikman transfere pa nwayo a sistèm opere nan dosye sous la.

Imaj ki anba a montre kouman LMDB senkronize eta li lè w ap travay ak baz done ki soti nan diferan pwosesis. Lè nou mete memwa vityèl diferan pwosesis yo nan menm fichye a, nou defakto oblije sistèm operasyon an pou yo senkronize sèten blòk espas adrès yo youn ak lòt, kote LMDB sanble.​

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Yon nuans enpòtan se ke LMDB, pa default, modifye fichye done a atravè mekanis apèl sistèm ekri, epi li montre dosye a li menm nan mòd lekti sèlman. Apwòch sa a gen de konsekans enpòtan.

Premye konsekans komen pou tout sistèm operasyon yo. Sans li se ajoute pwoteksyon kont domaj envolontè nan baz done a pa kòd kòrèk. Kòm ou konnen, enstriksyon yo ègzèkutabl nan yon pwosesis yo gratis jwenn aksè nan done ki soti nan nenpòt kote nan espas adrès li yo. An menm tan an, jan nou jis sonje, montre yon fichye nan mòd lekti-ekri vle di ke nenpòt enstriksyon kapab tou modifye li. Si li fè sa pa erè, eseye, pou egzanp, aktyèlman ranplase yon eleman etalaj nan yon endèks ki pa egziste, Lè sa a, li ka aksidantèlman chanje dosye a trase nan adrès sa a, ki pral mennen nan koripsyon nan baz done a. Si fichye a parèt nan mòd lekti sèlman, lè sa a yon tantativ chanje espas adrès ki koresponn lan ap mennen nan yon revokasyon ijans nan pwogram nan ak yon siyal. SIGSEGV, ak dosye a ap rete entak.

Dezyèm konsekans lan deja espesifik pou iOS. Ni otè a ni okenn lòt sous mansyone klèman, men san li LMDB pa ta apwopriye pou kouri sou sistèm opere mobil sa a. Seksyon kap vini an konsakre nan konsiderasyon li yo.

Espesifik dosye memwa-map nan iOS

Te gen yon bèl rapò nan WWDC nan 2018 "iOS memwa gwo twou san fon plonje". Li di nou ke nan iOS, tout paj ki sitiye nan memwa fizik yo se youn nan 3 kalite: sal, konprese ak pwòp.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Netwaye memwa se yon koleksyon paj ki ka dechaje san doulè nan memwa fizik. Done yo genyen yo ka rechaje jan sa nesesè nan sous orijinal li yo. Lekti-sèlman dosye memwa-map tonbe nan kategori sa a. iOS pa pè dechaje paj yo trase nan yon dosye nan memwa a nenpòt ki lè, depi yo garanti yo dwe senkronize ak dosye a sou disk.

Tout paj modifye fini nan memwa sal, kèlkeswa kote yo te orijinèlman. An patikilye, dosye memwa-map modifye pa ekri nan memwa vityèl ki asosye ak yo pral klase nan fason sa a. Ouvèti LMDB ak drapo MDB_WRITEMAP, apre w fin fè chanjman nan li, ou ka verifye sa pèsonèlman.​

Le pli vit ke yon aplikasyon kòmanse pran twòp memwa fizik, iOS sijè li nan konpresyon paj sal. Memwa total ki okipe pa paj sal ak konprese yo konstitye sa yo rele anprint memwa aplikasyon an. Yon fwa li rive nan yon sèten valè papòt, daemon nan sistèm asasen OOM vini apre pwosesis la ak fòse mete fen nan li. Sa a se spesifik nan iOS konpare ak sistèm opere Desktop. Kontrèman, diminye anprint memwa a pa echanje paj soti nan memwa fizik nan disk yo pa bay nan iOS. Rezon yo ka sèlman devine nan. Petèt pwosedi a nan entansif deplase paj nan disk ak tounen lakay ou twò konsome enèji pou aparèy mobil, oswa iOS sove resous la nan reekri selil sou kondui SSD, oswa petèt konsèpteur yo pa t 'satisfè ak pèfòmans an jeneral nan sistèm nan, kote tout bagay se. toujou chanje. Se pou sa, reyalite a rete yon reyalite.

Bon nouvèl la, ki deja mansyone pi bonè, se ke LMDB pa default pa sèvi ak mekanis mmap pou mete ajou fichye yo. Sa vle di ke done ki parèt yo klase pa iOS kòm memwa pwòp epi yo pa kontribye nan anprint memwa a. Ou ka verifye sa lè l sèvi avèk yon zouti Xcode ki rele VM Tracker. Ekran ki anba a montre eta memwa vityèl iOS aplikasyon Cloud la pandan operasyon an. Nan kòmansman an, 2 ka LMDB yo te inisyalize ladan l. Premye a te pèmèt yo montre dosye l 'sou 1GiB nan memwa vityèl, dezyèm lan - 512MiB. Malgre lefèt ke tou de depo okipe yon sèten kantite memwa rezidan, okenn nan yo pa kontribye gwosè sal.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Epi kounye a li lè pou move nouvèl. Gras a mekanis swap nan sistèm operasyon Desktop 64-bit, chak pwosesis ka okipe otan espas adrès vityèl jan espas gratis ki gen kapasite pou swap posib li a pèmèt. Ranplase swap ak konpresyon nan iOS radikalman diminye maksimòm teyorik la. Koulye a, tout pwosesis k ap viv yo dwe anfòm nan memwa prensipal la (li RAM), ak tout moun ki pa anfòm yo dwe fòse yo mete fen. Sa a se endike tankou nan mansyone anwo a rapò, ak nan dokiman ofisyèl yo. Kòm yon konsekans, iOS sevè limite kantite memwa ki disponib pou alokasyon atravè mmap. Isit la isit la Ou ka gade nan limit anpirik kantite memwa ki ta ka resevwa lajan sou diferan aparèy lè l sèvi avèk apèl sistèm sa a. Sou modèl smartphone ki pi modèn, iOS te vin jenere pa 2 jigokte, ak sou vèsyon tèt iPad a - pa 4. Nan pratik, nan kou, ou dwe konsantre sou modèl yo aparèy ki pi ba sipòte, kote tout bagay trè tris. Menm pi mal, lè w gade eta memwa aplikasyon an nan VM Tracker, w ap jwenn ke LMDB se byen lwen youn nan sèlman ki reklame yo dwe memwa-map. Bon moso yo manje ale pa alokasyon sistèm, dosye resous, kad imaj, ak lòt predatè ki pi piti.

Dapre rezilta eksperyans yo nan nwaj la, nou rive nan valè konpwomi sa yo pou memwa LMDB atribye ba yo: 384 megabyte pou aparèy 32-bit ak 768 pou aparèy 64-bit. Apre volim sa a fin itilize, nenpòt operasyon modifye kòmanse fini ak kòd la MDB_MAP_FULL. Nou obsève erè sa yo nan siveyans nou an, men yo ase piti ke nan etap sa a yo ka neglije.

Yon rezon ki pa evidan pou konsomasyon memwa twòp nan depo a ka tranzaksyon ki dire lontan. Pou w konprann ki jan de fenomèn sa yo konekte, n ap ede nou konsidere de poto ki rete nan LMDB.

3.2. Balèn #2. B+-pyebwa

Pou imite tab yo anlè yon depo kle-valè, operasyon sa yo dwe prezan nan API li yo:

  1. Mete yon nouvo eleman.
  2. Chèche yon eleman ak yon kle bay.
  3. Retire yon eleman.
  4. Iterasyon sou entèval kle yo nan lòd yo klase yo.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yoEstrikti done ki pi senp ki ka fasilman aplike tout kat operasyon yo se yon pye bwa rechèch binè. Chak nan nœuds li yo reprezante yon kle ki divize tout sous-ansanm kle timoun yo an de sous-arbre. Yon sèl gòch la gen sa ki pi piti pase paran an, ak youn nan dwa gen sa yo ki pi gwo. Jwenn yon seri òdone nan kle reyalize atravè youn nan parvèse pyebwa klasik yo.​

Pye bwa binè gen de defo fondamantal ki anpeche yo efikas kòm yon estrikti done ki baze sou disk. Premyèman, degre nan balans yo se enprevizib. Gen yon risk konsiderab pou jwenn pye bwa nan ki wotè diferan branch yo ka diferan anpil, sa ki vin pi grav konpleksite algorithmik rechèch la konpare ak sa ki espere. Dezyèmman, abondans nan kwa-lyen ant nœuds anpeche pye bwa binè nan lokalite nan memwa.Nœuds fèmen (an tèm de koneksyon ant yo) ka sitiye sou paj konplètman diferan nan memwa vityèl. Kòm yon konsekans, menm yon travèse senp nan plizyè nœuds vwazen nan yon pye bwa ka mande pou vizite yon kantite konparab nan paj. Sa a se yon pwoblèm menm lè nou pale sou efikasite nan pye bwa binè kòm yon estrikti done nan memwa, depi toujou ap wotasyon paj nan kachèt processeur a se pa yon plezi bon mache. Lè li rive souvan rekipere paj ki asosye ak nœuds soti nan disk, sitiyasyon an vin konplètman deplorab.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yoB-pye bwa, yo te yon evolisyon nan pye bwa binè, rezoud pwoblèm yo idantifye nan paragraf anvan an. Premyèman, yo balanse tèt yo. Dezyèmman, chak nan nœuds yo divize seri kle timoun yo pa an 2, men an M òdone sou-ansanm, ak nimewo M a ka byen gwo, sou lòd plizyè santèn, oswa menm dè milye.

Kidonk:

  1. Chak ne gen yon gwo kantite kle deja bay lòd ak pye bwa yo trè kout.
  2. Pye bwa a jwenn pwopriyete a nan lokalite kote yo ye nan memwa, depi kle ki fèmen nan valè yo natirèlman sitiye akote youn ak lòt sou nœuds yo menm oswa vwazen.
  3. Kantite nœuds transpò lè w ap desann yon pye bwa pandan yon operasyon rechèch diminye.
  4. Nimewo a nan nœuds sib li pandan demann ranje redwi, paske chak nan yo deja gen yon gwo kantite kle kòmande.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

LMDB sèvi ak yon varyasyon nan B-pyebwa a ki rele yon pye bwa B + pou estoke done. Dyagram ki anwo a montre twa kalite nœuds ki egziste ladan l:

  1. Nan tèt la se rasin lan. Li konkretize pa gen anyen plis pase konsèp nan yon baz done andedan yon depo. Nan yon sèl egzanp LMDB, ou ka kreye plizyè baz done ki pataje yon espas adrès vityèl kat. Chak nan yo kòmanse nan rasin pwòp li yo.
  2. Nan nivo ki pi ba yo se fèy yo. Yo ak sèlman yo genyen pè kle-valè ki estoke nan baz done a. By wout la, sa a se patikilye nan B +-pye bwa. Si yon B-pyebwa regilye magazen pati valè nan nœuds nan tout nivo, Lè sa a, varyasyon B + se sèlman nan youn ki pi ba a. Lè w fin fikse reyalite sa a, nou pral rele plis soutip pyebwa yo itilize nan LMDB tou senpleman yon B-pyebwa.
  3. Ant rasin lan ak fèy gen 0 oswa plis nivo teknik ak nœuds navigasyon (branch). Travay yo se divize seri a klase nan kle ant fèy yo.

Fizikman, nœuds yo se blòk memwa ki gen yon longè predetèmine. Gwosè yo se yon miltip nan gwosè paj memwa nan sistèm operasyon an, ke nou te diskite pi wo a. Estrikti ne yo montre anba a. Header a gen meta enfòmasyon, ki pi evidan nan ki pou egzanp se checksum la. Apre sa, vini enfòmasyon sou konpanse kote selil yo ak done yo ye. Done yo ka swa kle, si nou ap pale de nœuds navigasyon, oswa tout pè kle-valè nan ka fèy yo.​ Ou ka li plis sou estrikti paj nan travay la. "Evalyasyon gwo pèfòmans magazen kle-valè".

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Lè nou te fè fas ak kontni entèn nan nœuds paj la, nou pral pi lwen reprezante LMDB B-pyebwa a nan yon fason senplifye nan fòm sa a.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Paj ak nœuds yo sitiye sekans sou disk. Paj ki pi wo nimewote yo sitiye nan fen dosye a. Sa yo rele meta paj la gen enfòmasyon sou konpanse yo ka jwenn rasin tout pyebwa yo. Lè ouvri yon fichye, LMDB analize paj dosye a pa paj depi fen rive nan kòmansman pou chèche yon paj meta ki valab epi atravè li jwenn baz done ki egziste deja.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Koulye a, gen yon lide sou estrikti lojik ak fizik òganizasyon done, nou ka kontinye pou konsidere twazyèm poto LMDB. Se avèk èd li yo ke tout modifikasyon depo fèt tranzaksyon ak nan izolasyon youn ak lòt, bay baz done a kòm yon antye pwopriyete a nan multiversion.

3.3. Balèn #3. Kopi-sou-ekri

Kèk operasyon B-tree enplike fè yon seri de chanjman nan nœuds li yo. Yon egzanp se ajoute yon nouvo kle nan yon ne ki te deja rive nan kapasite maksimòm li yo. Nan ka sa a, li nesesè, premyèman, divize ne an de, ak dezyèmman, ajoute yon lyen nan nouvo ne timoun nan boujònman nan paran li yo. Pwosedi sa a se potansyèlman trè danjere. Si pou kèk rezon (aksidan, pann kouran, elatriye) sèlman yon pati nan chanjman ki soti nan seri a rive, Lè sa a, pye bwa a ap rete nan yon eta konsistan.

Yon solisyon tradisyonèl pou fè yon baz done tolerans fay se ajoute yon estrikti done adisyonèl sou-disk akote B-pyebwa a - yon boutèy demi lit tranzaksyon, ke yo rele tou yon mòso ekri an avans (WAL). Li se yon dosye nan fen operasyon an gen entansyon ekri entèdi anvan modifye B-pyebwa a tèt li. Kidonk, si yo detekte koripsyon done pandan dyagnostik pwòp tèt ou, baz done a konsilte boutèy la pou mete tèt li nan lòd.

LMDB te chwazi yon metòd diferan kòm yon mekanis tolerans fay, ki rele kopi-sou-ekri. Sans li se ke olye pou yo mete ajou done sou yon paj ki deja egziste, li premye kopye li antyèman epi fè tout modifikasyon nan kopi a.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Apre sa, nan lòd pou done yo mete ajou yo disponib, li nesesè chanje lyen ki mennen nan ne ki te vin aktyèl nan ne paran li yo. Depi li tou bezwen modifye pou sa a, li tou kopye davans. Pwosesis la kontinye rekursif tout wout la nan rasin lan. Dènye bagay pou chanje se done ki sou paj meta a.​​

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Si toudenkou pwosesis la aksidan pandan pwosedi aktyalizasyon a, Lè sa a, swa yon nouvo paj meta pa pral kreye, oswa li pa pral ekri sou disk nèt, ak checksum li yo pral kòrèk. Nan nenpòt nan de ka sa yo, nouvo paj yo pral inaccessible, men ansyen yo pa pral afekte. Sa a elimine nesesite pou LMDB ekri mòso devan pou kenbe konsistans done yo. Defakto, estrikti nan depo done sou disk ki dekri anwo a ansanm pran fonksyon li yo. Absans yon jounal tranzaksyon eksplisit se youn nan karakteristik LMDB ki bay gwo vitès lekti done.​

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Konsepsyon an ki kapab lakòz, ki rele ajoute-sèlman B-tree, natirèlman bay izolasyon tranzaksyon ak milti-vèsyon. Nan LMDB, chak tranzaksyon louvri asosye ak rasin pye bwa ki enpòtan kounye a. Jiskaske tranzaksyon an fini, paj pye bwa ki asosye ak li yo p ap janm chanje oswa itilize ankò pou nouvo vèsyon done yo. Kidonk, ou ka travay pou toutotan ou renmen ak egzakteman seri done ki te enpòtan nan moman an. tranzaksyon an te louvri, menm si depo a kontinye ap aktivman mete ajou nan moman sa a. Sa a se sans nan multiversion, ki fè LMDB yon sous done ideyal pou nou renmen anpil UICollectionView. Lè w te louvri yon tranzaksyon, pa gen okenn nesesite pou ogmante anprint memwa aplikasyon an pa prese ponpe done aktyèl yo nan kèk estrikti nan memwa, paske yo te pè yo te kite san anyen. Karakteristik sa a distenge LMDB soti nan SQLite a menm, ki pa ka fè grandizè de izolasyon total sa yo. Lè w te louvri de tranzaksyon nan lèt la epi efase yon sèten dosye nan youn nan yo, li p ap posib ankò pou jwenn menm dosye a nan dezyèm youn ki rete a.

Bò kote pyès monnen an se konsomasyon memwa vityèl ki kapab siyifikativman pi wo. Slide a montre ki jan estrikti baz done a pral sanble si li modifye ansanm ak 3 tranzaksyon lekti louvri gade diferan vèsyon baz done a. Piske LMDB pa ka reitilize nœuds ki ka jwenn soti nan rasin ki asosye ak tranzaksyon aktyèl yo, magazen an pa gen okenn chwa ke asiyen yon lòt rasin katriyèm nan memwa epi yon lòt fwa ankò klonaj paj modifye anba li.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Isit la li ta itil yo sonje seksyon an sou dosye memwa-map. Li sanble ke konsomasyon adisyonèl nan memwa vityèl pa ta dwe enkyete nou anpil, paske li pa kontribye nan anprint memwa aplikasyon an. Sepandan, an menm tan an, li te note ke iOS trè chich nan allocation li, epi nou pa ka, tankou sou yon sèvè oswa Desktop, bay yon rejyon LMDB nan 1 teraocte epi yo pa panse sou karakteristik sa a ditou. Si sa posib, ou ta dwe eseye fè tout lavi tranzaksyon yo kout ke posib.

4. Konsepsyon yon chema done sou tèt API kle-valè

Ann kòmanse analiz API nou an lè nou gade abstraksyon debaz yo bay pa LMDB: anviwònman ak baz done, kle ak valè, tranzaksyon ak kurseur.

Yon nòt sou lis kòd

Tout fonksyon nan API LMDB piblik la retounen rezilta travay yo sou fòm yon kòd erè, men nan tout lis ki vin apre yo omisyon verifikasyon li yo pou yon fason ki kout.​ An pratik, nou menm itilize pwòp pa nou pou kominike avèk depo a. fouchèt Anbalaj C++ lmdbxx, nan ki erè yo konkretize kòm eksepsyon C++.

Kòm fason ki pi rapid pou konekte LMDB nan yon pwojè pou iOS oswa macOS, mwen sijere CocoaPod mwen an. POSLMDB.

4.1. Abstraksyon debaz yo

Anviwònman

Estrikti MDB_env se repozitwa eta entèn LMDB la. Fanmi fonksyon prefiks mdb_env pèmèt ou konfigirasyon kèk nan pwopriyete li yo. Nan ka ki pi senp, inisyalizasyon motè sanble sa a.

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

Nan aplikasyon an Mail.ru Cloud, nou chanje valè yo default nan sèlman de paramèt.

Premye a se gwosè espas adrès vityèl ke dosye depo a trase sou li. Malerezman, menm sou menm aparèy la, valè espesifik la ka varye anpil soti nan kouri ale nan kouri. Pou pran an kont karakteristik sa a nan iOS, volim nan depo maksimòm chwazi dinamik. Kòmanse soti nan yon sèten valè, li se sekans mwatye jiska fonksyon an mdb_env_open pa pral retounen yon rezilta diferan de ENOMEM. Nan teyori, gen tou yon fason opoze a - premye asiyen yon minimòm memwa nan motè a, ak Lè sa a, lè erè yo resevwa, MDB_MAP_FULL, ogmante li. Sepandan, li se pi plis litijyeuz. Rezon ki fè la se ke pwosedi a pou re-allocation memwa (remap) lè l sèvi avèk fonksyon an mdb_env_set_map_size invalid tout antite (kurseur, tranzaksyon, kle ak valè) te deja resevwa nan men motè a. Lè w pran sa a vire nan evènman an kont nan kòd la ap mennen nan konplikasyon enpòtan li yo. Si, sepandan, memwa vityèl trè enpòtan pou ou, Lè sa a, sa a ka yon rezon ki fè yo pran yon gade pi pre nan fouchèt la ki te ale pi devan. MDBX, kote nan mitan karakteristik yo te anonse gen "otomatik sou-a-vole ajisteman gwosè baz done".

Dezyèm paramèt la, valè default ki pa t 'kostim nou, kontwole mekanik pou asire sekirite fil. Malerezman, omwen iOS 10 gen pwoblèm ak sipò pou fil lokal depo. Pou rezon sa a, nan egzanp ki anwo a, repozitwa a louvri ak drapo a MDB_NOTLS. Anplis de sa, li te nesesè tou fouchèt Anbalaj C++ lmdbxxkoupe varyab ak atribi sa a ak nan li.

Baz done

Baz done a se yon egzanp separe B-tree, ke nou te diskite pi wo a. Ouvèti li fèt andedan yon tranzaksyon, ki ka sanble yon ti kras etranj nan premye.

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

Vreman vre, yon tranzaksyon nan LMDB se yon antite depo, pa yon antite espesifik baz done. Konsèp sa a pèmèt ou fè operasyon atomik sou antite ki sitiye nan baz done diferan. Nan teyori, sa a ouvè posiblite pou modèl tab nan fòm diferan baz done, men nan yon sèl fwa mwen te pran yon chemen diferan, ki dekri an detay anba a.

Kle ak valè

Estrikti MDB_val modèl konsèp tou de kle ak valè. Repozitwa a pa gen okenn lide sou semantik yo. Pou li, yon lòt bagay se jis yon etalaj de bytes nan yon gwosè bay yo. Gwosè maksimòm kle a se 512 octets.

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

Sèvi ak yon konparezon, magazen an klase kle yo nan lòd monte. Si ou pa ranplase li ak pwòp ou a, Lè sa a, youn nan default yo pral itilize, ki klase yo byte pa byte nan lòd leksikografik.

Tranzaksyon yo

Estrikti tranzaksyon an dekri an detay nan chapit anvan an, Se konsa, isit la mwen pral yon ti tan repete pwopriyete prensipal yo:

  1. Sipòte tout pwopriyete debaz yo ASID: atomite, konsistans, izolasyon ak fyab. Mwen pa ka ede men sonje ke gen yon ensèk an tèm de rezistans sou macOS ak iOS ki te fiks nan MDBX. Ou ka li plis nan yo README.
  2. Se konplo "yon sèl ekriven / plizyè lektè" ki dekri apwòch multithreading la. Ekriven yo bloke youn lòt, men yo pa bloke lektè yo. Lektè yo pa bloke ekriven oswa youn ak lòt.
  3. Sipò pou tranzaksyon enbrike.
  4. Multiversion sipò.

Multiversion nan LMDB tèlman bon ke mwen vle demontre li nan aksyon. Soti nan kòd ki anba a ou ka wè ke chak tranzaksyon travay ak egzakteman vèsyon an nan baz done a ki te aktyèl nan moman an li te louvri, yo te konplètman izole nan tout chanjman ki vin apre yo. Inisyalize depo a epi ajoute yon dosye tès nan li pa reprezante anyen ki enteresan, kidonk rituèl sa yo rete anba spoiler la.

Ajoute yon antre tès

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

Mwen rekòmande ke ou eseye jwe fent la menm ak SQLite ak wè sa k ap pase.

Multiversion pote avantaj trè bèl nan lavi yon pwomotè iOS. Sèvi ak pwopriyete sa a, ou ka fasilman ak natirèlman ajiste pousantaj aktyalizasyon sous done a pou fòm ekran, ki baze sou konsiderasyon eksperyans itilizatè. Pou egzanp, ann pran yon karakteristik nan aplikasyon an Mail.ru Cloud tankou otoloading kontni nan galri medya sistèm lan. Avèk yon koneksyon bon, kliyan an kapab ajoute plizyè foto pa segonn nan sèvè a. Si ou mete ajou apre chak download UICollectionView ak kontni medya nan nwaj itilizatè a, ou ka bliye sou 60 fps ak defile lis pandan pwosesis sa a. Pou anpeche mizajou ekran souvan, ou bezwen yon jan kanmenm limite pousantaj done yo chanje nan kache a UICollectionViewDataSource.

Si baz done a pa sipòte multiversion ak pèmèt ou travay sèlman ak aktyèl eta aktyèl la, Lè sa a, yo kreye yon snapshot tan ki estab nan done yo ou bezwen kopye li swa nan kèk estrikti done nan memwa oswa nan yon tab tanporè. Nenpòt nan apwòch sa yo trè chè. Nan ka depo nan memwa, nou jwenn depans tou de nan memwa, ki te koze pa estoke objè konstwi, ak nan tan, ki asosye ak transfòmasyon ORM redondants. Kòm pou tab la tanporè, sa a se yon plezi menm pi chè, fè sans sèlman nan ka ki pa trivial.

Solisyon multiversion LMDB a rezoud pwoblèm nan kenbe yon sous done ki estab nan yon fason trè elegant. Li ase jis yo louvri yon tranzaksyon ak vwala - jiskaske nou fini li, seri done a garanti yo dwe fiks. Lojik pou vitès aktyalizasyon li yo kounye a se antyèman nan men yo nan kouch prezantasyon an, ki pa gen okenn anlè resous enpòtan.

Kursè

Kursè yo bay yon mekanis pou iterasyon lòd sou pè kle-valè atravè travès B-tree. San yo pa yo, li ta enposib efektivman modèl tab yo nan baz done a, ki nou kounye a ale nan.

4.2. Modèl tab

Pwopriyete lòd kle pèmèt ou konstwi yon abstraksyon wo nivo tankou yon tab sou tèt abstraksyon debaz yo. Ann konsidere pwosesis sa a lè l sèvi avèk egzanp tablo prensipal la nan yon kliyan nwaj, ki kachèt enfòmasyon sou tout fichye itilizatè a ak dosye.

Chema tab la

Youn nan senaryo komen pou yo ta dwe adapte yon estrikti tab ak yon pye bwa katab se seleksyon tout eleman ki sitiye nan yon anyè bay. Yon bon modèl òganizasyon done pou demann efikas nan kalite sa a se Lis Adjacency. Pou aplike li anlè depo kle-valè a, li nesesè pou klase kle fichye yo ak dosye yo nan yon fason ke yo gwoupe dapre manm yo nan anyè paran an. Anplis de sa, yo nan lòd yo montre sa ki nan anyè a nan fòm ki abitye nan yon itilizatè Windows (premye dosye, Lè sa a, fichye, tou de klase alfabetik), li nesesè yo enkli jaden ki koresponn yo adisyonèl nan kle a.

​Foto ki anba la a montre kouman, dapre travay la nan men an, yon reprezantasyon kle nan fòm yon etalaj byte ta ka sanble. Byte yo ak idantifyan an nan anyè paran an (wouj) yo mete an premye, Lè sa a, ak kalite a (vèt) ak nan ke a ak non an (ble). fason obligatwa. Sekans travèse kle ak menm prefiks wouj la ba nou valè ki asosye yo nan lòd yo ta dwe parèt nan koòdone itilizatè a (sou bò dwat la), san yo pa bezwen okenn lòt pwosesis apre.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Serialize kle ak valè

Anpil metòd pou seri objè yo te envante nan mond lan. Piske nou pa t gen okenn lòt kondisyon pase vitès, nou te chwazi pi rapid posib pou tèt nou - yon pil fatra nan memwa okipe pa yon egzanp nan estrikti nan lang C. Kidonk, kle a nan yon eleman anyè ka modle ak estrikti sa a. NodeKey.

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

Pou sove NodeKey nan depo ki nesesè nan objè MDB_val pozisyon pwent done a nan adrès la nan kòmansman an nan estrikti a, epi kalkile gwosè yo ak fonksyon an sizeof.

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

Nan premye chapit la sou kritè seleksyon baz done a, mwen mansyone minimize alokasyon dinamik nan operasyon CRUD kòm yon faktè seleksyon enpòtan. Kòd fonksyon serialize montre kouman nan ka LMDB yo ka konplètman evite lè yo mete nouvo dosye nan baz done a. Se etalaj la byte fèk ap rantre soti nan sèvè a premye transfòme nan estrikti chemine, ak Lè sa a, yo trivially jete nan depo. Lè ou konsidere ke pa gen okenn alokasyon dinamik tou andedan LMDB, ou ka jwenn yon sitiyasyon kokenn dapre estanda iOS - itilize sèlman pile memwa pou travay ak done sou tout chemen an soti nan rezo a nan disk la!

Kòmande kle ak yon konparatè binè

Relasyon lòd kle a espesifye pa yon fonksyon espesyal ki rele yon konparezon. Piske motè a pa konnen anyen sou semantik byte yo genyen yo, konparezon defo a pa gen okenn chwa ke pou fè aranjman pou kle yo nan lòd leksikografik, fè yon konparezon byte-pa-byte. Sèvi ak li pou òganize estrikti se menm jan ak bab ak yon rach koupe. Sepandan, nan ka senp mwen jwenn metòd sa a akseptab. Altènatif la dekri anba a, men isit la mwen pral sonje yon koup nan rato gaye sou chemen sa a.

Premye bagay ou sonje se reprezantasyon memwa kalite done primitif yo. Kidonk, sou tout aparèy Apple, varyab nonb antye relatif yo estoke nan fòma a Ti Endian. Sa vle di ke byte ki pi piti a pral sou bò gòch la, epi li pa pral posib pou klase nonm antye yo lè l sèvi avèk yon konparezon byte-pa-byte. Pou egzanp, eseye fè sa ak yon seri nimewo ki soti nan 0 a 511 pral pwodui rezilta sa a.

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

Pou rezoud pwoblèm sa a, nonm antye yo dwe estoke nan kle a nan yon fòma apwopriye pou konparan byte-byte a. Fonksyon nan fanmi an pral ede w pote transfòmasyon ki nesesè yo hton* (an patikilye htons pou nimewo doub-byte nan egzanp lan).

Fòma pou reprezante strings nan pwogramasyon se, jan ou konnen, yon antye istwa. Si semantik fisèl yo, osi byen ke kodaj yo itilize pou reprezante yo nan memwa, sijere ke ka gen plis pase yon byte pou chak karaktè, Lè sa a, li pi bon imedyatman abandone lide a nan itilize yon konparezon default.

Dezyèm bagay ou dwe sonje se prensip aliyman yo èstrikti jaden du. Poutèt yo, bytes ak valè fatra ka fòme nan memwa ant jaden, ki, nan kou, kraze byte-byte klasman. Pou elimine fatra, ou bezwen swa deklare jaden yo nan yon lòd ki entèdi, kenbe règ aliyman nan tèt ou, oswa itilize atribi a nan deklarasyon estrikti a. packed.

Kòmande kle ak yon konparatè ekstèn

Lojik konparezon kle a ka twò konplèks pou yon konparatè binè. Youn nan anpil rezon se prezans nan domèn teknik nan estrikti yo. Mwen pral ilistre ensidan yo lè l sèvi avèk egzanp yon kle pou yon eleman anyè ki deja abitye pou nou.

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

Malgre senplisite li yo, nan vas majorite de ka li konsome twòp memwa. Tanpon pou non an pran 256 octets, byenke an mwayèn non dosye ak katab raman depase 20-30 karaktè.

Youn nan teknik estanda pou optimize gwosè yon dosye se "taye" li nan gwosè aktyèl la. Sans li se ke sa ki nan tout jaden longè varyab yo estoke nan yon tanpon nan fen estrikti a, ak longè yo yo estoke nan varyab separe. Dapre apwòch sa a, kle a NodeKey transfòme jan sa a.

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

Pli lwen, lè seri, gwosè done yo pa espesifye sizeof estrikti a tout antye, ak gwosè a nan tout jaden se yon longè fiks plis gwosè a nan pati a aktyèlman itilize nan tanpon an.

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

Kòm yon rezilta nan refactoring la, nou te resevwa ekonomi enpòtan nan espas ki te okipe pa kle yo. Sepandan, akòz jaden teknik la nameLength, konparezon binè default la pa apwopriye ankò pou konparezon kle. Si nou pa ranplase li ak pwòp pa nou, Lè sa a, longè non an pral yon faktè priyorite ki pi wo nan klasman pase non an tèt li.

LMDB pèmèt chak baz done gen pwòp fonksyon konparezon kle li yo. Sa a se fè lè l sèvi avèk fonksyon an mdb_set_compare estrikteman anvan ouvèti. Pou rezon evidan, li pa ka chanje pandan tout lavi baz done a. Konparatè a resevwa de kle nan fòma binè kòm opinyon, epi nan pwodiksyon an li retounen rezilta konparezon an: mwens pase (-1), pi gran pase (1) oswa egal a (0). Pseudocode pou NodeKey sanble sa.

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

Osi lontan ke tout kle yo nan baz done a se nan menm kalite a, san kondisyon jete reprezantasyon byte yo nan kalite a nan estrikti kle aplikasyon an legal. Gen yon sèl nuans isit la, men li pral diskite pi ba a nan seksyon "Dosye Lekti".

Serialize valè

LMDB travay trè entansif ak kle yo nan dosye ki estoke. Konparezon yo youn ak lòt rive nan kad nenpòt operasyon aplike, ak pèfòmans nan solisyon an antye depann sou vitès la nan konparatè a. Nan yon mond ideyal, konparezon binè default la ta dwe ase pou konpare kle, men si ou te oblije sèvi ak pwòp ou a, Lè sa a, pwosedi a pou deserialize kle nan li ta dwe pi vit ke posib.

Baz done a pa patikilyèman enterese nan pati nan valè nan dosye a (valè). Konvèsyon li soti nan yon reprezantasyon byte nan yon objè fèt sèlman lè kòd aplikasyon an deja egzije l, pou egzanp, montre li sou ekran an. Piske sa rive relativman raman, kondisyon vitès pou pwosedi sa a pa tèlman kritik, epi nan aplikasyon li nou gen plis lib pou konsantre sou konvenyans.Pou egzanp, pou seri metadata sou dosye ki poko telechaje, nou itilize. NSKeyedArchiver.

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

Sepandan, gen kèk fwa lè pèfòmans toujou enpòtan. Pa egzanp, lè n ap sove metaenfòmasyon sou estrikti dosye yon nwaj itilizatè, nou itilize menm pil fatra objè yo. Rekò nan travay la nan jenere yon reprezantasyon seri yo se lefèt ke eleman yo nan yon anyè yo modle pa yon yerachi nan klas yo.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Pou aplike li nan lang C a, jaden espesifik nan eritye yo mete yo nan estrikti separe, epi koneksyon yo ak youn nan baz espesifye atravè yon jaden nan kalite sendika. Sa ki reyèl nan sendika a espesifye atravè kalite atribi teknik.

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

Ajoute ak mete ajou dosye yo

Serialize kle a ak valè ka ajoute nan magazen an. Pou fè sa, sèvi ak fonksyon an mdb_put.

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

Nan etap konfigirasyon an, yo ka pèmèt depo a oswa entèdi pou estoke plizyè dosye ak menm kle a. Si kopi kle yo entèdi, Lè sa a, lè w ap mete yon dosye, ou ka detèmine si mete ajou yon dosye ki egziste deja pèmèt oswa ou pa. Si frayaj ka fèt sèlman kòm yon rezilta nan yon erè nan kòd la, Lè sa a, ou ka pwoteje tèt ou kont li lè w espesifye drapo a. NOOVERWRITE.

Lekti antre yo

Pou li dosye nan LMDB, sèvi ak fonksyon an mdb_get. Si pè kle-valè reprezante pa estrikti deja jete, lè sa a pwosedi sa a sanble sa a.

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

Lis ki prezante a montre kouman serializasyon atravè pil fatra estrikti pèmèt ou debarase m de alokasyon dinamik pa sèlman lè w ap ekri, men lè w ap li done yo. Ki sòti nan fonksyon mdb_get konsèy la gade egzakteman nan adrès la memwa vityèl kote baz done a estoke reprezantasyon an byte nan objè a. An reyalite, nou jwenn yon kalite ORM ki bay vitès lekti done trè wo prèske gratis. Malgre tout bote nan apwòch la, li nesesè sonje plizyè karakteristik ki asosye ak li.

  1. Pou yon tranzaksyon lekti sèlman, konsèy la sou estrikti valè a garanti yo rete valab sèlman jiskaske tranzaksyon an fèmen. Jan nou te note pi bonè, paj B-tree kote yon objè sitiye, gras a prensip kopi-sou-ekri, rete san chanjman toutotan yo fè referans a pa omwen yon tranzaksyon. An menm tan an, le pli vit ke dènye tranzaksyon ki asosye ak yo fini, paj yo ka reyitilize pou nouvo done. Si li nesesè pou objè yo siviv tranzaksyon ki te pwodwi yo, Lè sa a, yo toujou gen yo dwe kopye.
  2. Pou yon tranzaksyon reekri, konsèy la nan estrikti valè ki kapab lakòz yo pral valab sèlman jiskaske premye pwosedi modifye (ekri oswa efase done).
  3. Malgre ke estrikti a NodeValue pa totalman, men taye (gade sou-seksyon "Komande kle lè l sèvi avèk yon konparatè ekstèn"), ou ka jwenn aksè san danje nan jaden li yo atravè konsèy la. Bagay pwensipal lan se pa dereference li!
  4. Nan okenn sikonstans, estrikti a pa ta dwe modifye atravè pointeur resevwa a. Tout chanjman yo dwe fèt sèlman atravè metòd la mdb_put. Sepandan, kèlkeswa jan ou vle fè sa a, li pa pral posib, paske zòn memwa kote estrikti sa a sitiye se trase nan mòd lekti sèlman.
  5. Remap yon fichye nan espas adrès pwosesis la nan bi pou, pou egzanp, ogmante gwosè depo maksimòm nan lè l sèvi avèk fonksyon an mdb_env_set_map_size konplètman anile tout tranzaksyon ak antite ki gen rapò an jeneral ak endikasyon sou sèten objè an patikilye.

Finalman, yon lòt karakteristik se konsa trètr ke revele sans li yo pa anfòm nan jis yon lòt paragraf. Nan chapit sou B-pyebwa a, mwen te bay yon dyagram sou fason paj li yo ranje nan memwa. Li swiv nan sa a ke adrès la nan kòmansman an nan tanpon an ak done seri ka absoliman abitrè. Poutèt sa, konsèy la yo te resevwa nan estrikti a MDB_val ak redwi a yon konsèy nan yon estrikti, li vire soti yo dwe unaligned nan ka jeneral la. An menm tan an, achitekti yo nan kèk chips (nan ka a nan iOS sa a se armv7) mande pou adrès la nan nenpòt done dwe yon miltip nan gwosè a nan mo machin lan oswa, nan lòt mo, gwosè a ti jan nan sistèm lan ( pou armv7 li se 32 bit). Nan lòt mo, yon operasyon tankou *(int *foo)0x800002 sou yo se ekivalan a chape ak mennen nan ekzekisyon ak yon vèdik EXC_ARM_DA_ALIGN. Gen de fason pou evite yon sò tris konsa.

Premye a desann nan kopi preliminè nan done nan yon estrikti evidamman aliyen. Pou egzanp, sou yon konparezon koutim sa a pral reflete jan sa a.

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

Yon fason altènatif se avèti konpilatè a davans ke estrikti kle-valè yo pa ka aliye ak atribi. aligned(1). Sou ARM ou ka gen menm efè reyalize epi itilize atribi chaje a. Lè ou konsidere ke li ede tou optimize espas ki okipe pa estrikti a, metòd sa a sanble pi bon pou mwen, byenke приводит nan yon ogmantasyon nan pri a nan operasyon aksè done yo.

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

Rekèt ranje

Pou itere sou yon gwoup dosye, LMDB bay yon abstraksyon kurseur. Ann gade ki jan yo travay avèk li lè l sèvi avèk egzanp yon tab ak metadata nwaj itilizatè yo deja abitye pou nou.

Kòm yon pati nan montre yon lis fichye nan yon anyè, li nesesè jwenn tout kle yo ak ki dosye pitit li yo ak dosye yo asosye. Nan sou-seksyon anvan yo nou klase kle yo NodeKey konsa ke yo prensipalman kòmande pa ID la nan anyè paran an. Kidonk, teknikman, travay la nan rekipere sa ki nan yon katab vini desann nan mete kurseur a sou fwontyè a anwo nan gwoup la nan kle ak yon prefiks bay ak Lè sa a, iterasyon nan fwontyè ki pi ba a.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Ou ka jwenn limit siperyè a dirèkteman pa rechèch sekans. Pou fè sa, yo mete kurseur a nan kòmansman an nan tout lis la nan kle nan baz done a ak plis enkreman jiskaske yon kle ak idantifyan an nan anyè paran an parèt anba li. Apwòch sa a gen 2 dezavantaj evidan:

  1. Konpleksite rechèch lineyè, byenke, jan yo konnen, nan pye bwa an jeneral ak nan yon B-pyebwa an patikilye li ka fèt nan tan logaritmik.
  2. Pou gremesi, tout paj ki vin anvan sa a ke yo te chache a yo leve soti nan dosye a nan memwa prensipal la, ki se trè chè.

Erezman, LMDB API a bay yon fason efikas pou okòmansman pozisyon kurseur a. Pou fè sa, ou bezwen jenere yon kle ki gen valè evidamman mwens pase oswa egal ak kle ki sitiye nan fwontyè a anwo nan entèval la. Pou egzanp, an relasyon ak lis ki nan figi ki anwo a, nou ka fè yon kle nan ki jaden an parentId pral egal a 2, ak tout rès yo plen ak zewo. Se tankou yon kle pasyèlman ranpli apwovizyone nan opinyon an fonksyon mdb_cursor_get ki endike operasyon an 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);

Si yo jwenn fwontyè anwo a nan yon gwoup kle, Lè sa a, nou repete sou li jiskaske swa nou rankontre oswa kle a rankontre yon lòt. parentId, oswa kle yo pa pral fini ditou.​

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

Ki sa ki bèl se ke kòm yon pati nan iterasyon an lè l sèvi avèk mdb_cursor_get, nou jwenn non sèlman kle a, men tou, valè a. Si, yo nan lòd yo satisfè kondisyon echantiyon yo, ou bezwen tcheke, pami lòt bagay, jaden ki soti nan pati nan valè nan dosye a, Lè sa a, yo byen aksesib san jès adisyonèl.

4.3. Modèl relasyon ant tab yo

Depi kounye a, nou te jere yo konsidere tout aspè nan konsepsyon ak travay ak yon baz done yon sèl tab. Nou ka di ke yon tab se yon seri dosye klase ki gen menm kalite pè kle-valè. Si ou montre yon kle kòm yon rektang ak valè ki asosye a kòm yon paralèlepipèd, ou jwenn yon dyagram vizyèl nan baz done a.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Sepandan, nan lavi reyèl li se raman posib jwenn pa ak san koule konsa ti kras. Souvan nan yon baz done li oblije, premyèman, gen plizyè tab, ak dezyèmman, fè seleksyon nan yo nan yon lòd diferan de kle prensipal la. Dènye seksyon sa a konsakre nan pwoblèm yo nan kreyasyon yo ak entèkoneksyon.

Tablo endèks yo

Aplikasyon nwaj la gen yon seksyon "Galeri". Li montre kontni medya ki soti nan tout nwaj la, klase pa dat. Pou pi byen aplike seleksyon sa a, akote tab prensipal la ou bezwen kreye yon lòt ak yon nouvo kalite kle. Yo pral genyen yon jaden ki gen dat fichye a te kreye, ki pral aji kòm kritè klasman prensipal la. Paske nouvo kle yo fè referans a menm done ak kle yo nan tablo prensipal la, yo rele yo kle endèks. Nan foto ki anba a yo make an zoranj.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Yo nan lòd yo separe kle yo nan tab diferan youn ak lòt nan menm baz done a, yo te ajoute yon lòt tableId jaden teknik nan tout nan yo. Lè nou fè li pi gwo priyorite pou klasman, nou pral reyalize gwoupman kle yo an premye pa tab, ak nan tab - dapre pwòp règ nou yo.

Kle endèks la fè referans a menm done ak kle prensipal la. Yon aplikasyon senp nan pwopriyete sa a atravè asosye ak li yon kopi pati nan valè nan kle prensipal la pa pi bon nan plizyè pwen de vi:

  1. An tèm de espas pran, metadata yo ka byen rich.
  2. Soti nan yon pwen de vi pèfòmans, depi lè mete ajou metadata yo nan yon ne, ou pral oblije reekri li lè l sèvi avèk de kle.
  3. Soti nan pwen de vi sipò kòd, si nou bliye mete ajou done yo pou youn nan kle yo, nou pral jwenn yon pinèz flotant nan enkonsistans done nan depo a.

Apre sa, nou pral konsidere ki jan yo elimine enpèfeksyon sa yo.

Òganize relasyon ant tab yo

Modèl la byen adapte pou konekte tab endèks la ak tab prensipal la "kle kòm valè". Kòm non li sijere, pati nan valè nan dosye endèks la se yon kopi valè prensipal la kle. Apwòch sa a elimine tout dezavantaj ki mansyone anwo yo ki asosye ak estoke yon kopi valè pati dosye prensipal la. Sèl pri a se ke pou jwenn yon valè pa kle endèks, ou bezwen fè 2 demann nan baz done a olye pou yo youn. Schématikman, chema baz done ki kapab lakòz la sanble sa a.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Yon lòt modèl pou òganize relasyon ant tab se "kle redondants". Sans li se ajoute atribi adisyonèl nan kle a, ki nesesè pa pou klasman, men pou rkree kle ki asosye a.Nan aplikasyon an Mail.ru Cloud gen egzanp reyèl sou itilizasyon li yo, sepandan, yo nan lòd pou fè pou evite yon plonje byen fon nan kontèks espesifik iOS kad, mwen pral bay yon fiktiv, men men yon egzanp pi klè.​

Kliyan mobil Cloud yo gen yon paj ki montre tout fichye ak dosye itilizatè a pataje ak lòt moun. Piske gen relativman kèk dosye sa yo, epi gen anpil diferan kalite enfòmasyon espesifik sou piblisite ki asosye ak yo (ki moun ki akòde aksè, ak ki dwa, elatriye), li pa pral rasyonèl chaje pati nan valè nan la. anrejistre nan tablo prensipal la avèk li. Sepandan, si ou vle montre dosye sa yo offline, ou toujou bezwen sere li yon kote. Yon solisyon natirèl se kreye yon tab separe pou li. Nan dyagram ki anba a, kle li a prefiks ak "P", epi yo ka ranplase "propname" anplasman ak valè ki pi espesifik "enfòmasyon piblik".

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Tout metadata inik, pou dedomajman pou yo estoke ki nouvo tab la te kreye, yo mete nan pati nan valè nan dosye a. An menm tan an, ou pa vle kopi done yo sou dosye ak dosye ki deja estoke nan tablo prensipal la. Olye de sa, done redondants yo ajoute nan kle "P" nan fòm lan nan "ID ID" ak "timestamp" jaden yo. Mèsi a yo, ou ka konstwi yon kle endèks, ki soti nan ki ou ka jwenn yon kle prensipal, ki soti nan ki, finalman, ou ka jwenn metadata ne.

Konklizyon

Nou evalye rezilta aplikasyon LMDB pozitivman. Apre li, kantite aplikasyon jele diminye pa 30%.

Klere ak povrete baz done kle-valè LMDB nan aplikasyon iOS yo

Rezilta yo nan travay la fè rezonans pi lwen pase ekip iOS la. Kounye a, youn nan seksyon prensipal "Fichiye" yo nan aplikasyon android a te chanje tou pou itilize LMDB, ak lòt pati yo sou wout la. Lang C a, kote magazen kle-valè a aplike, te yon bon èd pou okòmansman kreye yon fondasyon aplikasyon alantou li kwa-platfòm nan C++. Yo te itilize yon dèlko kòd pou konekte bibliyotèk C++ ki kapab lakòz ak kòd platfòm nan Objective-C ak Kotlin. Djinni soti nan Dropbox, men sa a se yon istwa konplètman diferan.

Sous: www.habr.com

Add nouvo kòmantè