Moja izvedba medpomnilnika obroča v bliskavici NOR

prazgodovina

Na voljo so avtomati lastne zasnove. Znotraj Raspberry Pi in nekaj ožičenja na ločeni plošči. Priključeni so sprejemnik kovancev, sprejemnik bankovcev, bančni terminal ... Vse vodi program, ki ga sami napišemo. Celotna delovna zgodovina se zapiše v dnevnik na bliskovnem disku (MicroSD), ki se nato prek interneta (z uporabo USB modema) prenese na strežnik, kjer se shrani v bazo podatkov. Informacije o prodaji se nalagajo v 1c, na voljo je tudi enostaven spletni vmesnik za spremljanje itd.

To pomeni, da je dnevnik bistvenega pomena - za računovodstvo (prihodki, prodaja itd.), Spremljanje (vse vrste okvar in druge okoliščine višje sile); Lahko bi rekli, da so to vse informacije, ki jih imamo o tem stroju.

problem

Flash diski se kažejo kot zelo nezanesljive naprave. Ne uspejo z zavidljivo rednostjo. To vodi do izpadov stroja in (če iz nekega razloga dnevnika ni bilo mogoče prenesti na splet) do izgube podatkov.

To ni prva izkušnja uporabe bliskovnih diskov, pred tem je bil še en projekt z več kot sto napravami, kjer je bila revija shranjena na USB ključkih, težave so bile tudi z zanesljivostjo, na trenutke število tistih, ki so odpovedali na mesec je bilo na desetine. Preizkusili smo različne bliskovne pogone, vključno z blagovnimi znamkami s pomnilnikom SLC, in nekateri modeli so zanesljivejši od drugih, vendar zamenjava bliskovnih pogonov ni radikalno rešila težave.

Opozorilo! Longread! Če vas ne zanima "zakaj", ampak samo "kako", lahko greste naravnost Na koncu člankov.

odločitev

Prva stvar, ki pride na misel, je: opustite MicroSD, namestite na primer SSD in se zaženite z njega. Teoretično mogoče, verjetno, vendar razmeroma drago in ne tako zanesljivo (dodan je adapter USB-SATA; tudi statistika napak pri proračunskih SSD-jih ni spodbudna).

USB HDD prav tako ne izgleda posebej privlačna rešitev.

Zato smo prišli do te možnosti: pustite zagon z MicroSD, vendar jih uporabite v načinu samo za branje in shranite dnevnik delovanja (in druge informacije, edinstvene za posamezen kos strojne opreme - serijska številka, kalibracije senzorjev itd.) nekam drugam .

Tema FS-ja samo za branje za maline je bila že preučena znotraj in zunaj, v tem članku se ne bom osredotočal na podrobnosti izvedbe (če pa bo zanimanje, bom morda napisal mini članek na to temo). Edina točka, ki bi jo rad omenil, je, da tako iz osebnih izkušenj kot iz pregledov tistih, ki so to že izvajali, obstaja povečanje zanesljivosti. Da, nemogoče se je popolnoma znebiti okvar, vendar je znatno zmanjšanje njihove pogostosti povsem mogoče. In kartice postajajo poenotene, kar močno olajša zamenjavo servisnemu osebju.

Strojna oprema

O izbiri vrste pomnilnika - NOR Flash - ni bilo posebnega dvoma.
Argumenti:

  • enostavna povezava (najpogosteje vodilo SPI, s katerim že imate izkušnje, zato ni predvidenih težav s strojno opremo);
  • smešna cena;
  • standardni delovni protokol (izvedba je že v jedru Linuxa, če želite, lahko vzamete drugega proizvajalca, ki je prav tako prisoten, ali celo napišete svojega, na srečo je vse preprosto);
  • zanesljivost in vir:
    iz tipičnega podatkovnega lista: podatki se hranijo 20 let, 100000 ciklov brisanja za vsak blok;
    iz virov tretjih oseb: izjemno nizek BER, domneva, da ni potrebe po kodah za odpravljanje napak (nekatera dela obravnavajo ECC kot NOR, vendar običajno še vedno pomenijo MLC NOR; tudi to se zgodi).

Ocenimo zahteve glede količine in virov.

Želim, da se podatki zajamčeno hranijo več dni. To je potrebno, da se v primeru težav s komunikacijo ne izgubi zgodovina prodaje. V tem obdobju se bomo osredotočili na 5 dni (tudi ob vikendih in praznikih) problem je mogoče rešiti.

Trenutno zberemo približno 100 kb dnevnikov na dan (3-4 tisoč vnosov), vendar postopoma ta številka raste - podrobnosti se povečujejo, dodajajo se novi dogodki. Poleg tega včasih pride do izbruhov (nekateri senzor začne na primer pošiljati neželeno pošto z lažno pozitivnimi rezultati). Izračunali bomo za 10 tisoč zapisov po 100 bajtov - megabajtov na dan.

Skupaj pride ven 5 MB čistih (dobro stisnjenih) podatkov. Več jim (groba ocena) 1MB servisnih podatkov.

To pomeni, da potrebujemo 8 MB čip, če ne uporabljamo stiskanja, ali 4 MB, če ga uporabljamo. Precej realne številke za to vrsto pomnilnika.

Kar zadeva vir: če načrtujemo, da bo celoten pomnilnik prepisan največ enkrat na 5 dni, potem v 10 letih delovanja dobimo manj kot tisoč ciklov prepisovanja.
Naj vas spomnim, da proizvajalec obljublja sto tisoč.

Malo o NOR proti NAND

Danes je seveda pomnilnik NAND veliko bolj priljubljen, vendar ga za ta projekt ne bi uporabil: NAND za razliko od NOR nujno zahteva uporabo kod za odpravljanje napak, tabelo slabih blokov itd., in tudi noge NAND čipi običajno veliko več.

Slabosti NOR vključujejo:

  • majhna količina (in s tem visoka cena na megabajt);
  • nizka hitrost komunikacije (predvsem zaradi dejstva, da se uporablja serijski vmesnik, običajno SPI ali I2C);
  • počasno brisanje (odvisno od velikosti bloka traja od delčkov sekunde do nekaj sekund).

Zdi se, da za nas ni nič kritičnega, zato nadaljujemo.

Če so podrobnosti zanimive, je mikrovezje izbrano pri25df321a (vendar je to nepomembno, na trgu je veliko analogov, ki so združljivi v pinoutu in ukaznem sistemu; tudi če želimo namestiti mikrovezje drugega proizvajalca in/ali druge velikosti, bo vse delovalo brez spreminjanja Koda).

Uporabljam gonilnik, vgrajen v jedro Linuxa; na Raspberryju je zahvaljujoč podpori za prekrivanje drevesa naprav vse zelo preprosto - prevedeno prekrivanje morate dati v /boot/overlays in rahlo spremeniti /boot/config.txt.

Primer datoteke dts

Če sem iskren, nisem prepričan, da je napisano brez napak, vendar deluje.

/*
 * Device tree overlay for at25 at spi0.1
 */

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; 

    /* disable spi-dev for spi0.1 */
    fragment@0 {
        target = <&spi0>;
        __overlay__ {
            status = "okay";
            spidev@1{
                status = "disabled";
            };
        };
    };

    /* the spi config of the at25 */
    fragment@1 {
        target = <&spi0>;
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;
            flash: m25p80@1 {
                    compatible = "atmel,at25df321a";
                    reg = <1>;
                    spi-max-frequency = <50000000>;

                    /* default to false:
                    m25p,fast-read ;
                    */
            };
        };
    };

    __overrides__ {
        spimaxfrequency = <&flash>,"spi-max-frequency:0";
        fastread = <&flash>,"m25p,fast-read?";
    };
};

In še ena vrstica v config.txt

dtoverlay=at25:spimaxfrequency=50000000

Opis priklopa čipa na Raspberry Pi bom izpustil. Po eni strani nisem strokovnjak za elektroniko, po drugi strani pa je vse tukaj banalno tudi zame: mikrovezje ima samo 8 nog, od katerih potrebujemo maso, moč, SPI (CS, SI, SO, SCK ); ravni so enake kot pri Raspberry Pi, dodatno ožičenje ni potrebno - samo povežite navedenih 6 pinov.

Izjava o težavah

Kot običajno gre izjava o problemu skozi več ponovitev in zdi se mi, da je čas za naslednjo. Ustavimo se torej, sestavimo že napisano in razjasnimo podrobnosti, ki ostajajo v senci.

Zato smo se odločili, da bo dnevnik shranjen v SPI NOR Flash.

Kaj je NOR Flash za tiste, ki ne vedo?

To je obstojni pomnilnik, s katerim lahko izvedete tri operacije:

  1. Branje:
    Najpogostejše branje: posredujemo naslov in preberemo toliko bajtov, kot jih potrebujemo;
  2. Posnetek:
    Pisanje v NOR flash je videti kot običajno, vendar ima eno posebnost: spremenite lahko samo 1 v 0, ne pa tudi obratno. Na primer, če imamo 0x55 v pomnilniški celici, potem ko vanjo zapišemo 0x0f, bo 0x05 tam že shranjen (glej tabelo spodaj);
  3. Izbriši:
    Seveda pa moramo znati narediti obratno operacijo - spremeniti 0 v 1, prav temu je namenjena operacija brisanja. Za razliko od prvih dveh ne deluje z bajti, ampak z bloki (najmanjši blok za brisanje v izbranem čipu je 4kb). Brisanje uniči celoten blok in je edini način za spremembo 0 v 1. Zato morate pri delu z bliskovnim pomnilnikom podatkovne strukture pogosto poravnati z mejo bloka za brisanje.
    Snemanje v NOR Flash:

Binarni podatki

Bil je
01010101

Posneto
00001111

Je postalo
00000101

Sam dnevnik predstavlja zaporedje zapisov spremenljive dolžine. Tipična dolžina zapisa je približno 30 bajtov (čeprav se včasih pojavijo zapisi, ki so dolgi več kilobajtov). V tem primeru z njimi delamo preprosto kot z nizom bajtov, če pa vas zanima, se znotraj zapisov uporablja CBOR

Poleg dnevnika moramo shraniti nekaj informacij o "nastavitvah", posodobljenih in ne: določen ID naprave, kalibracije senzorjev, zastavico "naprava je začasno onemogočena" itd.
Te informacije so nabor zapisov ključ-vrednost, prav tako shranjenih v CBOR. Teh informacij nimamo veliko (največ nekaj kilobajtov) in se redko posodabljajo.
V nadaljevanju ga bomo imenovali kontekst.

Če se spomnimo, kje se je ta članek začel, je zelo pomembno zagotoviti zanesljivo shranjevanje podatkov in po možnosti neprekinjeno delovanje tudi v primeru okvar strojne opreme/poškodbe podatkov.

Katere vire težav je mogoče upoštevati?

  • Izklop med pisanjem/brisanjem. To je iz kategorije "ni trika proti lomilu."
    Informacije iz razprave na stackexchange: ko se med delom z bliskavico izklopi napajanje, tako brisanje (nastavljeno na 1) kot pisanje (nastavljeno na 0) povzroči nedefinirano vedenje: podatke je mogoče zapisati, delno zapisati (recimo, prenesli smo 10 bajtov/80 bitov , vendar še ni mogoče zapisati samo 45 bitov), ​​je možno tudi, da bodo nekateri biti v "vmesnem" stanju (branje lahko proizvede tako 0 kot 1);
  • Napake v samem flash pomnilniku.
    BER, čeprav zelo nizek, ne more biti enak nič;
  • Napake avtobusa
    Podatki, ki se prenašajo prek SPI, niso zaščiteni na noben način, lahko pride do enobitnih napak in napak pri sinhronizaciji - izguba ali vstavljanje bitov (kar vodi do velikega popačenja podatkov);
  • Druge napake/napake
    Napake v kodi, napake pri Raspberryju, vmešavanje tujcev ...

Oblikoval sem zahteve, katerih izpolnjevanje je po mojem mnenju potrebno za zagotavljanje zanesljivosti:

  • zapisi morajo iti v bliskovni pomnilnik takoj, zakasnjeno pisanje se ne upošteva; - če pride do napake, jo je treba odkriti in obdelati čim prej; - sistem mora, če je le mogoče, obnoviti napake.
    (primer iz življenja "kako ne bi smelo biti", za katerega mislim, da so se vsi srečali: po ponovnem zagonu v sili je datotečni sistem "pokvarjen" in operacijski sistem se ne zažene)

Ideje, pristopi, razmišljanja

Ko sem začel razmišljati o tem problemu, se mi je v glavi porodilo veliko idej, na primer:

  • uporabite stiskanje podatkov;
  • uporabite pametne podatkovne strukture, na primer shranjevanje glav zapisov ločeno od samih zapisov, tako da lahko, če je v katerem koli zapisu napaka, brez težav preberete ostale;
  • uporabite bitna polja za nadzor zaključka snemanja, ko je napajanje izklopljeno;
  • shranite kontrolne vsote za vse;
  • uporabite neko vrsto kodiranja, odpornega na hrup.

Nekatere od teh idej so bile uporabljene, druge pa so se odločili opustiti. Gremo po vrsti.

Stiskanje podatkov

Sami dogodki, ki jih beležimo v dnevnik, so precej podobni in ponovljivi (»vrgel kovanec za 5 rubljev«, »pritisnil gumb za dajanje drobiža«, ...). Zato mora biti stiskanje precej učinkovito.

Stroški stiskanja so zanemarljivi (naš procesor je precej zmogljiv, tudi prvi Pi je imel eno jedro s frekvenco 700 MHz, sedanji modeli imajo več jeder s frekvenco nad gigahercem), menjalni tečaj s pomnilnikom je nizek (več megabajtov na sekundo), je velikost zapisov majhna. Če na splošno kompresija vpliva na zmogljivost, bo le pozitivna. (popolnoma nekritično, samo navajam). Poleg tega nimamo pravega vdelanega, ampak običajnega Linuxa - zato izvedba ne bi smela zahtevati veliko truda (dovolj je, da samo povežete knjižnico in uporabite več funkcij iz nje).

Del dnevnika je bil vzet iz delujoče naprave (1.7 MB, 70 tisoč vnosov) in najprej preverjen za stisljivost z gzip, lz4, lzop, bzip2, xz, zstd, ki so na voljo v računalniku.

  • gzip, xz, zstd so pokazali podobne rezultate (40Kb).
    Presenetilo me je, da se je modni xz tukaj pokazal na ravni gzip ali zstd;
  • lzip s privzetimi nastavitvami je dal nekoliko slabše rezultate;
  • lz4 in lzop sta pokazala ne preveč dobre rezultate (150Kb);
  • bzip2 je pokazal presenetljivo dober rezultat (18Kb).

Torej so podatki zelo dobro stisnjeni.
Torej (če ne najdemo usodnih napak) bo prišlo do stiskanja! Preprosto zato, ker lahko na isti bliskovni pogon spravite več podatkov.

Pomislimo na slabosti.

Prva težava: dogovorili smo se že, da mora vsak zapis takoj iti na flash. Običajno arhivar zbira podatke iz vhodnega toka, dokler se ne odloči, da je čas za pisanje ob koncu tedna. Takoj moramo prejeti stisnjen blok podatkov in ga shraniti v obstojni pomnilnik.

Vidim tri načine:

  1. Stisnite vsak zapis z uporabo stiskanja v slovarju namesto algoritmov, opisanih zgoraj.
    To je popolnoma delujoča možnost, vendar mi ni všeč. Da bi zagotovili bolj ali manj dostojno stopnjo stiskanja, mora biti slovar "prikrojen" določenim podatkom, vsaka sprememba bo povzročila katastrofalen padec stopnje stiskanja. Da, težavo je mogoče rešiti z ustvarjanjem nove različice slovarja, vendar je to glavobol - morali bomo shraniti vse različice slovarja; pri vsakem vnosu bomo morali navesti, s katero različico slovarja je bil stisnjen ...
  2. Stisnite vsak zapis s "klasičnimi" algoritmi, vendar neodvisno od drugih.
    Obravnavani algoritmi stiskanja niso zasnovani za delo z zapisi te velikosti (desetine bajtov), ​​razmerje stiskanja bo očitno manjše od 1 (to je povečanje količine podatkov namesto stiskanja);
  3. Po vsakem snemanju naredite FLUSH.
    Številne knjižnice za stiskanje podpirajo FLUSH. To je ukaz (ali parameter postopka stiskanja), po prejemu katerega arhivar oblikuje stisnjen tok, ki ga lahko uporabi za obnovitev Vsi nestisnjenih podatkov, ki so že bili prejeti. Takšen analog sync v datotečnih sistemih oz commit v sql.
    Pomembno je, da bodo naslednje operacije stiskanja lahko uporabile nakopičeni slovar in da stiskalno razmerje ne bo tako prizadeto kot v prejšnji različici.

Mislim, da je očitno, da sem izbral tretjo možnost, poglejmo jo podrobneje.

Najden odličen članek o FLUSH v zlib.

Opravil sem test kolena na podlagi članka, vzel 70 tisoč vnosov v dnevnik iz prave naprave z velikostjo strani 60 Kb (na velikost strani se bomo vrnili pozneje) prejel:

Surovi podatki
Stiskanje gzip -9 (brez FLUSH)
zlib z Z_PARTIAL_FLUSH
zlib z Z_SYNC_FLUSH

Obseg, KB
1692
40
352
604

Na prvi pogled je cena, ki jo prispeva FLUSH, pretirano visoka, a v resnici nimamo veliko izbire - ali da sploh ne stisnemo ali pa da stisnemo (in to zelo učinkovito) s FLUSH. Ne smemo pozabiti, da imamo 70 tisoč zapisov, redundanca, ki jo uvaja Z_PARTIAL_FLUSH, je le 4-5 bajtov na zapis. In kompresijsko razmerje se je izkazalo skoraj 5:1, kar je več kot odličen rezultat.

Morda bo presenetljivo, vendar je Z_SYNC_FLUSH dejansko bolj učinkovit način za FLUSH

Pri uporabi Z_SYNC_FLUSH bodo zadnji 4 bajti vsakega vnosa vedno 0x00, 0x00, 0xff, 0xff. In če jih poznamo, nam jih ni treba shranjevati, zato je končna velikost le 324Kb.

Članek, na katerega sem povezal, ima razlago:

Dodan je nov blok tipa 0 s prazno vsebino.

Blok tipa 0 s prazno vsebino sestavljajo:

  • tribitna glava bloka;
  • 0 do 7 bitov enakih nič, da se doseže poravnava bajtov;
  • štiribajtno zaporedje 00 00 FF FF.

Kot lahko zlahka vidite, je v zadnjem bloku pred temi 4 bajti od 3 do 10 nič bitov. Praksa pa je pokazala, da je dejansko najmanj 10 ničelnih bitov.

Izkazalo se je, da so tako kratki bloki podatkov običajno (vedno?) kodirani z uporabo bloka tipa 1 (fiksni blok), ki se nujno konča s 7 ničelnimi biti, kar daje skupno 10-17 zajamčenih ničelnih bitov (preostanek pa bo nič z verjetnostjo približno 50 %).

Torej, na testnih podatkih je v 100% primerov en ničelni bajt pred 0x00, 0x00, 0xff, 0xff, v več kot tretjini primerov pa sta dva ničelna bajta (morda je dejstvo, da uporabljam binarni CBOR in pri uporabi besedilnega JSON bi bili pogostejši bloki tipa 2 - dinamični blok, oziroma bi naleteli na bloke brez dodatnih ničelnih bajtov pred 0x00, 0x00, 0xff, 0xff).

Z uporabo razpoložljivih testnih podatkov je skupno mogoče prilegati manj kot 250 Kb stisnjenih podatkov.

Nekoliko več lahko prihranite z žongliranjem z bitmi: zaenkrat ignoriramo prisotnost nekaj ničelnih bitov na koncu bloka, nekaj bitov na začetku bloka se prav tako ne spremeni ...
Toda potem sem se močno odločil, da neham, sicer bi lahko s tem tempom razvijal lasten arhivar.

Skupaj sem iz svojih testnih podatkov prejel 3-4 bajte na zapis, kompresijsko razmerje pa je bilo več kot 6:1. Bom iskren: nisem pričakoval takšnega rezultata, po mojem mnenju je vse, kar je boljše od 2:1, že rezultat, ki opravičuje uporabo kompresije.

Vse je v redu, vendar je zlib (deflate) še vedno arhaičen, zaslužen in rahlo staromoden algoritem stiskanja. Že samo dejstvo, da se zadnjih 32 Kb nestisnjenega podatkovnega toka uporablja kot slovar, je danes videti čudno (to pomeni, da če je nek podatkovni blok zelo podoben tistemu, kar je bil v vhodnem toku pred 40 Kb, se bo začel znova arhivirati, in se ne nanaša na prejšnji dogodek). V modernih sodobnih arhivarjih se velikost slovarja pogosto meri v megabajtih in ne v kilobajtih.

Torej nadaljujemo z našo mini študijo arhivarjev.

Nato smo preizkusili bzip2 (ne pozabite, brez FLUSH je pokazal fantastično kompresijsko razmerje skoraj 100:1). Na žalost se je s FLUSH izkazal zelo slabo; izkazalo se je, da je velikost stisnjenih podatkov večja od nestisnjenih podatkov.

Moje domneve o razlogih za neuspeh

Libbz2 ponuja samo eno možnost izpiranja, ki se zdi, da počisti slovar (analogno Z_FULL_FLUSH v zlibu); po tem ni več govora o učinkovitem stiskanju.

In zadnji na testu je bil zstd. Odvisno od parametrov stisne na ravni gzipa, vendar veliko hitreje ali bolje kot gzip.

Žal, s programom FLUSH se ni najbolje obnesel: velikost stisnjenih podatkov je bila približno 700 Kb.

Я postavil vprašanje na github strani projekta sem dobil odgovor, da računate na do 10 bajtov servisnih podatkov za vsak blok stisnjenih podatkov, kar je blizu dobljenim rezultatom, z deflatom se nikakor ne da dohiteti.

Odločil sem se, da se na tej točki ustavi pri svojih poskusih z arhivatorji (naj vas spomnim, da se xz, lzip, lzo, lz4 niso izkazali niti v fazi testiranja brez FLUSH in nisem upošteval bolj eksotičnih algoritmov stiskanja).

Vrnimo se k težavam z arhiviranjem.

Druga (kot pravijo po vrstnem redu, ne po vrednosti) težava je, da so stisnjeni podatki en sam tok, v katerem so nenehno sklicevanja na prejšnje razdelke. Če je torej del stisnjenih podatkov poškodovan, izgubimo ne samo pripadajoči blok nekomprimiranih podatkov, ampak tudi vse naslednje.

Obstaja pristop k rešitvi te težave:

  1. Preprečite nastanek težave - stisnjenim podatkom dodajte redundanco, kar vam bo omogočilo prepoznavanje in odpravljanje napak; o tem bomo govorili kasneje;
  2. Zmanjšajte posledice, če pride do težave
    Prej smo že povedali, da lahko stisnete vsak podatkovni blok neodvisno in težava bo izginila sama (poškodba podatkov enega bloka bo povzročila izgubo podatkov samo za ta blok). Vendar je to skrajni primer, v katerem bo stiskanje podatkov neučinkovito. Nasprotna skrajnost: vseh 4MB našega čipa uporabimo kot en sam arhiv, kar nam bo dalo odlično stiskanje, a katastrofalne posledice v primeru poškodovanja podatkov.
    Da, glede zanesljivosti je potreben kompromis. Ne smemo pa pozabiti, da razvijamo format za shranjevanje podatkov za obstojni pomnilnik z izjemno nizkim BER-om in deklarirano dobo shranjevanja podatkov 20 let.

Med poskusi sem ugotovil, da se bolj ali manj opazne izgube v stopnji stiskanja začnejo pri blokih stisnjenih podatkov, manjših od 10 KB.
Prej je bilo omenjeno, da je uporabljeni pomnilnik ostranjen; ne vidim razloga, zakaj ne bi uporabili korespondence »ena stran – en blok stisnjenih podatkov«.

To pomeni, da je najmanjša razumna velikost strani 16 Kb (z rezervo za servisne informacije). Vendar tako majhna velikost strani nalaga precejšnje omejitve glede največje velikosti zapisa.

Čeprav še ne pričakujem zapisov, večjih od nekaj kilobajtov v stisnjeni obliki, sem se odločil za 32Kb strani (za skupno 128 strani na čip).

Povzetek:

  • Podatke hranimo stisnjene z zlib (deflate);
  • Za vsak vnos nastavimo Z_SYNC_FLUSH;
  • Za vsak stisnjen zapis obrežemo končne bajte (npr. 0x00, 0x00, 0xff, 0xff); v glavi navedemo, koliko bajtov smo odrezali;
  • Podatke hranimo na 32Kb straneh; znotraj strani je en sam tok stisnjenih podatkov; Na vsaki strani znova začnemo s stiskanjem.

In preden končam s stiskanjem, bi vas rad opozoril na dejstvo, da imamo le nekaj bajtov stisnjenih podatkov na zapis, zato je izjemno pomembno, da ne napihnete servisnih informacij, tukaj šteje vsak bajt.

Shranjevanje glav podatkov

Ker imamo zapise spremenljive dolžine, moramo nekako določiti postavitev/meje zapisov.

Poznam tri pristope:

  1. Vsi zapisi so shranjeni v neprekinjenem toku, najprej je glava zapisa, ki vsebuje dolžino, nato pa sam zapis.
    V tej izvedbi so lahko glave in podatki spremenljive dolžine.
    V bistvu dobimo enojno povezan seznam, ki se uporablja ves čas;
  2. Glave in sami zapisi so shranjeni v ločenih tokovih.
    Z uporabo glave konstantne dolžine zagotovimo, da poškodba ene glave ne vpliva na druge.
    Podoben pristop se uporablja na primer v številnih datotečnih sistemih;
  3. Zapisi so shranjeni v neprekinjenem toku, meja zapisa je določena z določenim markerjem (znak/zaporedje znakov, ki je prepovedano znotraj podatkovnih blokov). Če je znotraj zapisa marker, ga zamenjamo z nekim zaporedjem (escape it).
    Podoben pristop se uporablja na primer v protokolu PPP.

Bom ilustriral.

Možnost 1:
Moja izvedba medpomnilnika obroča v bliskavici NOR
Tukaj je vse zelo preprosto: če poznamo dolžino zapisa, lahko izračunamo naslov naslednje glave. Tako se premikamo po naslovih, dokler ne naletimo na območje, zapolnjeno z 0xff (prosto območje) ali na konec strani.

Možnost 2:
Moja izvedba medpomnilnika obroča v bliskavici NOR
Zaradi spremenljive dolžine zapisa ne moremo vnaprej povedati, koliko zapisov (in s tem glav) bomo potrebovali na stran. Glave in same podatke lahko razporedite po različnih straneh, vendar imam raje drugačen pristop: tako glave kot podatke postavimo na eno stran, vendar glave (konstantne velikosti) prihajajo z začetka strani in podatki (spremenljive dolžine) prihajajo s konca. Takoj ko se »srečata« (ni dovolj prostega prostora za nov vnos), menimo, da je ta stran dokončana.

Možnost 3:
Moja izvedba medpomnilnika obroča v bliskavici NOR
Dolžine ali drugih informacij o lokaciji podatkov v glavi ni treba shranjevati, dovolj so oznake, ki označujejo meje zapisov. Vendar je treba podatke obdelati med pisanjem/branjem.
0xff bi uporabil kot marker (ki zapolni stran po brisanju), tako da prosto območje zagotovo ne bo obravnavano kot podatek.

Primerjalna tabela:

Možnost 1
Možnost 2
Možnost 3

Toleranca napak
-
+
+

Kompaktnost
+
-
+

Kompleksnost izvedbe
*
**
**

Možnost 1 ima usodno napako: če je katera od glav poškodovana, je celotna naslednja veriga uničena. Preostale možnosti vam omogočajo obnovitev nekaterih podatkov tudi v primeru velike škode.
Tukaj pa velja spomniti, da smo se odločili podatke shranjevati v stisnjeni obliki in tako po “pokvarjenem” zapisu izgubimo vse podatke na strani, tako da kljub temu, da je v tabeli minus, ne upoštevajte.

Kompaktnost:

  • pri prvi možnosti moramo v glavo shraniti samo dolžino, če uporabljamo cela števila spremenljive dolžine, potem v večini primerov lahko preživimo z enim bajtom;
  • pri drugi možnosti moramo shraniti začetni naslov in dolžino; zapis mora biti konstantne velikosti, ocenjujem 4 bajte na zapis (dva bajta za odmik in dva bajta za dolžino);
  • tretja možnost potrebuje samo en znak za označevanje začetka snemanja, poleg tega se bo sam posnetek povečal za 1-2% zaradi zaščite. Na splošno približno enakovredna prvi možnosti.

Sprva sem drugo možnost obravnaval kot glavno (in celo napisal izvedbo). Opustil sem ga šele, ko sem se končno odločil za kompresijo.

Morda bom nekoč še vedno uporabil podobno možnost. Na primer, če se moram ukvarjati s shranjevanjem podatkov za ladjo, ki potuje med Zemljo in Marsom, bodo popolnoma drugačne zahteve glede zanesljivosti, kozmičnega sevanja, ...

Kar zadeva tretjo možnost: dal sem ji dve zvezdici za težavnost izvedbe preprosto zato, ker se ne maram zapletati z zaščito, spreminjati dolžino med postopkom itd. Da, morda sem pristranski, vendar bom moral napisati kodo - zakaj bi se silil, da narediš nekaj, kar ti ni všeč.

Povzetek: Izberemo možnost shranjevanja v obliki verig »glava z dolžino - podatki spremenljive dolžine« zaradi učinkovitosti in enostavnosti izvedbe.

Uporaba bitnih polj za spremljanje uspešnosti zapisovalnih operacij

Zdaj se ne spomnim, od kod sem dobil idejo, ampak izgleda nekako takole:
Za vsak vnos dodelimo več bitov za shranjevanje zastavic.
Kot smo že povedali, so po brisanju vsi biti zapolnjeni z 1 in 1 lahko spremenimo v 0, ne pa tudi obratno. Torej za "zastavica ni nastavljena" uporabimo 1, za "zastavica je nastavljena" pa 0.

Kako bi lahko izgledalo vstavljanje zapisa spremenljive dolžine v flash:

  1. Nastavite zastavico "snemanje dolžine se je začelo";
  2. Zapišite dolžino;
  3. Nastavite zastavico »snemanje podatkov se je začelo«;
  4. Beležimo podatke;
  5. Nastavite zastavico »snemanje je končano«.

Poleg tega bomo imeli zastavo »prišlo je do napake« za skupno 4 bitne zastavice.

V tem primeru imamo dve stabilni stanju "1111" - snemanje se ni začelo in "1000" - snemanje je bilo uspešno; v primeru nepričakovane prekinitve procesa snemanja bomo prejeli vmesna stanja, ki jih lahko nato zaznamo in obdelamo.

Pristop je zanimiv, a varuje le pred nenadnimi izpadi električne energije in podobnimi okvarami, kar je seveda pomembno, a to še zdaleč ni edini (ali celo glavni) razlog za morebitne okvare.

Povzetek: Gremo naprej v iskanju dobre rešitve.

Kontrolne vsote

Kontrolne vsote omogočajo tudi, da se (z razumno verjetnostjo) prepričamo, da beremo točno to, kar bi moralo biti napisano. In za razliko od zgoraj obravnavanih bitnih polj vedno delujejo.

Če upoštevamo seznam možnih virov težav, o katerem smo razpravljali zgoraj, lahko kontrolna vsota prepozna napako ne glede na njen izvor (razen morda zlonamernih vesoljcev - tudi ti lahko ponaredijo kontrolno vsoto).

Torej, če je naš cilj preveriti, ali so podatki nedotaknjeni, so kontrolne vsote odlična ideja.

Izbira algoritma za izračun kontrolne vsote ni sprožila nobenih vprašanj - CRC. Po eni strani matematične lastnosti omogočajo 100-odstotno ulov nekaterih vrst napak, po drugi strani pa ta algoritem na naključnih podatkih običajno pokaže verjetnost kolizij, ki ni veliko večja od teoretične meje. Moja izvedba medpomnilnika obroča v bliskavici NOR. Morda ni najhitrejši algoritem, niti ni vedno najmanjši v smislu števila trkov, vendar ima zelo pomembno kakovost: v testih, na katere sem naletel, ni bilo vzorcev, pri katerih bi očitno odpovedal. Stabilnost je v tem primeru glavna kakovost.

Primer volumetrične študije: Del 1, Del 2 (povezave do narod.ru, oprostite).

Vendar naloga izbire kontrolne vsote ni dokončana; CRC je cela družina kontrolnih vsot. Odločiti se morate za dolžino in nato izbrati polinom.

Izbira dolžine kontrolne vsote ni tako preprosto vprašanje, kot se zdi na prvi pogled.

Naj ponazorim:
Imejmo verjetnost napake v vsakem bajtu Moja izvedba medpomnilnika obroča v bliskavici NOR in idealno kontrolno vsoto, izračunajmo povprečno število napak na milijon zapisov:

Podatki, bajt
Kontrolna vsota, bajt
Neodkrite napake
Lažne zaznave napak
Skupaj lažno pozitivni

1
0
1000
0
1000

1
1
4
999
1003

1
2
≈0
1997
1997

1
4
≈0
3990
3990

10
0
9955
0
9955

10
1
39
990
1029

10
2
≈0
1979
1979

10
4
≈0
3954
3954

1000
0
632305
0
632305

1000
1
2470
368
2838

1000
2
10
735
745

1000
4
≈0
1469
1469

Zdi se, da je vse preprosto - odvisno od dolžine zaščitenih podatkov izberite dolžino kontrolne vsote z najmanj napačnimi pozitivnimi rezultati - in trik je v vrečki.

Težava pa nastane pri kratkih kontrolnih vsotah: čeprav so dobre pri odkrivanju enobitnih napak, lahko z dokaj veliko verjetnostjo sprejmejo povsem naključne podatke za pravilne. Na Habréju je že bil članek, ki je opisoval problem v resničnem življenju.

Da bi bilo skoraj nemogoče ujemanje naključne kontrolne vsote, morate uporabiti kontrolne vsote, ki so dolge 32 bitov ali več. (za dolžine, večje od 64 bitov, se običajno uporabljajo kriptografske zgoščevalne funkcije).

Kljub temu, da sem že prej napisal, da moramo na vsak način varčevati s prostorom, bomo še vedno uporabljali 32-bitno kontrolno vsoto (16 bitov ni dovolj, verjetnost kolizije je več kot 0.01 %; in 24-bitno, saj recimo, niso ne tu ne tam) .

Tu se lahko pojavi ugovor: ali smo pri izbiri kompresije shranili vsak bajt, da bi zdaj dali 4 bajte naenkrat? Ali ne bi bilo bolje, da ne bi stisnili ali dodali kontrolne vsote? Seveda ne, brez kompresije ne pomeni, da ne potrebujemo preverjanja integritete.

Pri izbiri polinoma ne bomo znova izumljali kolesa, ampak vzeli zdaj priljubljen CRC-32C.
Ta koda zazna 6 bitnih napak na paketih do 22 bajtov (pri nas morda najpogostejši primer), 4 bitne napake na paketih do 655 bajtov (tudi pri nas pogost primer), 2 ali poljubno liho število bitnih napak na paketih katere koli razumne dolžine.

Če koga zanimajo podrobnosti

Članek iz Wikipedije glede CRC.

Parametri kode crc-32c o Spletno mesto Koopman — morda vodilni strokovnjak za CRC na planetu.

В njegov članek obstaja še ena zanimiva koda, ki zagotavlja nekoliko boljše parametre za dolžine paketov, ki so za nas relevantni, vendar se mi razlika ni zdela bistvena in sem bil dovolj kompetenten, da sem izbral kodo po meri namesto standardne in dobro raziskane.

Ker so naši podatki stisnjeni, se postavlja vprašanje: ali naj izračunamo kontrolno vsoto stisnjenih ali nestisnjenih podatkov?

Argumenti v prid izračuna kontrolne vsote nestisnjenih podatkov:

  • Navsezadnje moramo preveriti varnost shranjevanja podatkov – torej preverimo neposredno (hkrati se preverijo morebitne napake pri izvajanju kompresije/dekompresije, poškodbe zaradi pokvarjenega pomnilnika ipd.);
  • Algoritem deflate v zlibu ima dokaj zrelo izvedbo in ne bi smel pade z "krivimi" vhodnimi podatki; poleg tega je pogosto sposoben neodvisno zaznati napake v vhodnem toku, kar zmanjša splošno verjetnost neodkritja napake (izvedel test z obračanjem enega bita v kratkem zapisu, zlib je odkril napako v približno tretjini primerov).

Argumenti proti izračunu kontrolne vsote nestisnjenih podatkov:

  • CRC je »prikrojen« posebej za nekaj bitnih napak, ki so značilne za bliskovni pomnilnik (bitna napaka v stisnjenem toku lahko povzroči ogromno spremembo v izhodnem toku, na katerem čisto teoretično lahko »ujemo« kolizijo);
  • Ni mi všeč zamisel o posredovanju potencialno poškodovanih podatkov dekompresorju, Kdo vekako bo reagiral.

Pri tem projektu sem se odločil odstopiti od splošno sprejete prakse shranjevanja kontrolne vsote nestisnjenih podatkov.

Povzetek: Uporabljamo CRC-32C, kontrolno vsoto izračunamo iz podatkov v obliki, v kateri so zapisani na flash (po stiskanju).

Redundanca

Uporaba redundantnega kodiranja seveda ne odpravi izgube podatkov, vendar pa lahko bistveno (pogosto za več velikosti) zmanjša verjetnost nepopravljive izgube podatkov.

Za popravljanje napak lahko uporabimo različne vrste redundance.
Hammingove kode lahko popravijo enobitne napake, kode znakov Reed-Solomon, več kopij podatkov v kombinaciji s kontrolnimi vsotami ali kodiranja, kot je RAID-6, lahko pomagajo obnoviti podatke tudi v primeru velike poškodbe.
Sprva sem se zavzemal za široko uporabo kodiranja, odpornega na napake, potem pa sem spoznal, da se moramo najprej zamisliti, pred katerimi napakami se želimo zaščititi, in šele nato izbrati kodiranje.

Prej smo rekli, da je treba napake čim hitreje odkriti. Na katerih točkah lahko naletimo na napake?

  1. Nedokončano snemanje (iz neznanega razloga v času snemanja je bilo napajanje izklopljeno, Raspberry je zmrznil, ...)
    Žal, v primeru takšne napake ostane le, da ignoriramo neveljavne zapise in štejemo podatke za izgubljene;
  2. Napake pri pisanju (iz nekega razloga tisto, kar je bilo zapisano v pomnilnik flash, ni bilo tisto, kar je bilo zapisano)
    Takšne napake lahko takoj zaznamo, če naredimo testno branje takoj po snemanju;
  3. Izkrivljanje podatkov v pomnilniku med shranjevanjem;
  4. Napake pri branju
    Če ga želite popraviti, če se kontrolna vsota ne ujema, je dovolj, da branje večkrat ponovite.

To pomeni, da samo napak tretje vrste (spontana poškodba podatkov med shranjevanjem) ni mogoče popraviti brez kodiranja, odpornega na napake. Zdi se, da so takšne napake še vedno zelo malo verjetne.

Povzetek: bilo je odločeno, da se odvečno kodiranje opusti, če pa operacija pokaže napako te odločitve, se vrnite k obravnavi vprašanja (z že zbranimi statističnimi podatki o napakah, ki bodo omogočili izbiro optimalne vrste kodiranja).

Drugo

Format članka seveda ne dopušča, da bi utemeljili vsak košček v formatu (in moje moči so že zmanjkale), zato bom na kratko pregledal nekaj točk, ki se jih prej nisem dotaknil.

  • Odločeno je bilo, da bodo vse strani "enake"
    To pomeni, da ne bo posebnih strani z metapodatki, ločenimi nitmi itd., ampak namesto tega ena sama nit, ki prepisuje vse strani po vrsti.
    To zagotavlja enakomerno obrabo strani, brez ene same točke okvare, in to mi je preprosto všeč;
  • Nujno je zagotoviti različico formata.
    Format brez številke različice v glavi je zlo!
    Dovolj je, da v glavo strani dodate polje z določeno magično številko (podpis), ki bo označevala različico uporabljenega formata (Mislim, da jih v praksi ne bo niti ducat);
  • Uporabite glavo spremenljive dolžine za zapise (ki jih je veliko), poskušajte v večini primerov narediti 1 bajt dolgo;
  • Za kodiranje dolžine glave in dolžine odrezanega dela stisnjenega zapisa uporabite binarne kode spremenljive dolžine.

Veliko pomagalo spletni generator Huffmanove kode. V samo nekaj minutah smo lahko izbrali zahtevane kode spremenljive dolžine.

Opis formata za shranjevanje podatkov

Vrstni red bajtov

Polja, večja od enega bajta, so shranjena v formatu big-endian (omrežni vrstni red bajtov), ​​kar pomeni, da je 0x1234 zapisano kot 0x12, 0x34.

Paginacija

Ves bliskovni pomnilnik je razdeljen na strani enake velikosti.

Privzeta velikost strani je 32 Kb, vendar ne več kot 1/4 skupne velikosti pomnilniškega čipa (za čip s 4 MB se pridobi 128 strani).

Vsaka stran shranjuje podatke neodvisno od drugih (to pomeni, da se podatki na eni strani ne sklicujejo na podatke na drugi strani).

Vse strani so oštevilčene v naravnem vrstnem redu (v naraščajočem vrstnem redu naslovov), začenši s številko 0 (stran nič se začne pri naslovu 0, prva stran se začne pri 32 Kb, druga stran se začne pri 64 Kb itd.)

Pomnilniški čip se uporablja kot ciklični vmesni pomnilnik (ring buffer), to pomeni, da gre najprej pisanje na stran številka 0, nato številka 1, ..., ko zapolnimo zadnjo stran, se začne nov cikel in snemanje se nadaljuje od strani XNUMX .

Znotraj strani

Moja izvedba medpomnilnika obroča v bliskavici NOR
Na začetku strani je shranjena 4-bajtna glava strani, nato kontrolna vsota glave (CRC-32C), nato pa se zapisi shranijo v formatu "glava, podatki, kontrolna vsota".

Naslov strani (umazano zelen v diagramu) je sestavljen iz:

  • dvobajtno polje Magic Number (tudi znak različice zapisa)
    za trenutno različico formata se izračuna kot 0xed00 ⊕ номер страницы;
  • dvobajtni števec “Različica strani” (številka cikla prepisovanja pomnilnika).

Vnosi na strani so shranjeni v stisnjeni obliki (uporabljen je algoritem deflate). Vsi zapisi na eni strani so stisnjeni v eni niti (uporablja se skupni slovar), na vsaki novi strani pa se stiskanje začne znova. To pomeni, da so za dekompresijo katerega koli zapisa potrebni vsi prejšnji zapisi s te strani (in samo ta).

Vsak zapis bo stisnjen z zastavico Z_SYNC_FLUSH, na koncu stisnjenega toka pa bodo 4 bajti 0x00, 0x00, 0xff, 0xff, pred katerimi bo morda še en ali dva ničelna bajta.
To zaporedje (4, 5 ali 6 bajtov dolgo) zavržemo pri pisanju v bliskovni pomnilnik.

Glava zapisa ima 1, 2 ali 3 bajte in shranjuje:

  • en bit (T), ki označuje vrsto zapisa: 0 - kontekst, 1 - dnevnik;
  • polje spremenljive dolžine (S) od 1 do 7 bitov, ki določa dolžino glave in "repa", ki ga je treba dodati zapisu za dekompresijo;
  • dolžina zapisa (L).

Tabela vrednosti S:

S
Dolžina glave, bajti
Zavrženo pri pisanju, bajt

0
1
5 (00 00 00 ff ff)

10
1
6 (00 00 00 00 ff ff)

110
2
4 (00 00 ff ff)

1110
2
5 (00 00 00 ff ff)

11110
2
6 (00 00 00 00 ff ff)

1111100
3
4 (00 00 ff ff)

1111101
3
5 (00 00 00 ff ff)

1111110
3
6 (00 00 00 00 ff ff)

Poskušal sem ilustrirati, ne vem, kako jasno se je izkazalo:
Moja izvedba medpomnilnika obroča v bliskavici NOR
Rumena tukaj označuje polje T, bela polje S, zelena L (dolžina stisnjenih podatkov v bajtih), modra stisnjene podatke, rdeča zadnje bajte stisnjenih podatkov, ki niso zapisani v bliskovni pomnilnik.

Tako lahko v en bajt zapišemo glave zapisov najpogostejše dolžine (do 63+5 bajtov v stisnjeni obliki).

Po vsakem zapisu se shrani kontrolna vsota CRC-32C, v kateri se kot začetna vrednost (init) uporabi obrnjena vrednost prejšnje kontrolne vsote.

CRC ima lastnost "trajanja", deluje naslednja formula (plus ali minus bitna inverzija v procesu): Moja izvedba medpomnilnika obroča v bliskavici NOR.
To pomeni, da dejansko izračunamo CRC vseh prejšnjih bajtov glav in podatkov na tej strani.

Neposredno za kontrolno vsoto je glava naslednjega zapisa.

Glava je zasnovana tako, da se njen prvi bajt vedno razlikuje od 0x00 in 0xff (če namesto prvega bajta glave naletimo na 0xff, to pomeni, da je to neuporabljeno področje; 0x00 signalizira napako).

Primer algoritmov

Branje iz Flash pomnilnika

Vsak odčitek je opremljen s preverjanjem kontrolne vsote.
Če se kontrolna vsota ne ujema, se branje večkrat ponovi v upanju, da se odčitajo pravilni podatki.

(to je smiselno, Linux ne predpomni branja iz NOR Flasha, preizkušeno)

Pišite v bliskovni pomnilnik

Podatke beležimo.
Preberimo jih.

Če se prebrani podatki ne ujemajo z zapisanimi podatki, zapolnimo območje z ničlami ​​in signaliziramo napako.

Priprava novega mikrovezja za delovanje

Za inicializacijo se na prvo (ali raje ničelno) stran zapiše glava z različico 1.
Po tem se začetni kontekst zapiše na to stran (vsebuje UUID naprave in privzete nastavitve).

To je to, flash pomnilnik je pripravljen za uporabo.

Polnjenje stroja

Pri nalaganju se prebere prvih 8 bajtov vsake strani (glava + CRC), strani z neznano magično številko ali nepravilnim CRC pa se prezrejo.
Izmed “pravilnih” strani se izberejo strani z največjo verzijo in iz njih se vzame stran z najvišjo številko.
Prebere se prvi zapis, preveri se pravilnost CRC in prisotnost zastavice »kontekst«. Če je vse v redu, se ta stran šteje za aktualno. Če ne, se vrnemo na prejšnjo, dokler ne najdemo »žive« strani.
in na najdeni strani preberemo vse zapise, tiste, ki jih uporabljamo z zastavico “context”.
Shranite zlib slovar (potreben bo za dodajanje na to stran).

To je to, prenos je končan, kontekst je obnovljen, lahko delate.

Dodajanje vnosa v dnevnik

Zapis stisnemo s pravilnim slovarjem in podamo Z_SYNC_FLUSH. Vidimo, ali stisnjen zapis ustreza trenutni strani.
Če se ne prilega (ali so bile na strani napake CRC), začnite novo stran (glejte spodaj).
Zapišemo zapis in CRC. Če pride do napake, zaženite novo stran.

Nova stran

Izberemo brezplačno stran z najmanjšim številom (za brezplačno stran štejemo stran z napačno kontrolno vsoto v glavi ali z različico, nižjo od trenutne). Če teh strani ni, izberite stran z najmanjšim številom izmed tistih, ki imajo različico, ki je enaka trenutni.
Izbrano stran izbrišemo. Vsebino preverimo z 0xff. Če je kaj narobe, vzemite naslednjo prosto stran itd.
Na izbrisano stran zapišemo glavo, prvi vnos je trenutno stanje konteksta, naslednji je nepopisan vnos v dnevnik (če obstaja).

Uporabnost formata

Po mojem mnenju se je izkazal za dober format za shranjevanje kakršnih koli bolj ali manj stisljivih informacijskih tokov (plain text, JSON, MessagePack, CBOR, morda protobuf) v NOR Flash.

Seveda je format "prikrojen" za SLC NOR Flash.

Ne sme se uporabljati z mediji z visokim BER, kot sta NAND ali MLC NOR (je takšen pomnilnik sploh na voljo za prodajo? Videl sem, da se omenja samo v delih o popravnih kodah).

Poleg tega se ne sme uporabljati z napravami, ki imajo svoj FTL: USB flash, SD, MicroSD itd (za tak pomnilnik sem ustvaril format z velikostjo strani 512 bajtov, podpisom na začetku vsake strani in edinstvenimi številkami zapisov - včasih je bilo mogoče obnoviti vse podatke iz "pokvarjenega" bliskovnega pogona s preprostim zaporednim branjem).

Odvisno od nalog se lahko format uporablja brez sprememb na bliskovnih pogonih od 128Kbit (16Kb) do 1Gbit (128MB). Če želite, ga lahko uporabite na večjih čipih, vendar boste verjetno morali prilagoditi velikost strani (Tu pa se že postavlja vprašanje ekonomske izvedljivosti; cena za NOR Flash velikega obsega ni spodbudna).

Če se komu zdi oblika zanimiva in jo želi uporabiti v odprtem projektu, naj piše, bom poskusil najti čas, izpiliti kodo in jo objaviti na githubu.

Zaključek

Kot lahko vidite, se je oblika na koncu izkazala za preprosto in celo dolgočasno.

Težko je odražati razvoj mojega stališča v članku, a verjemite mi: sprva sem želel ustvariti nekaj prefinjenega, neuničljivega, ki bi lahko preživelo celo jedrsko eksplozijo v neposredni bližini. Vendar je (upam) vseeno zmagal razum in postopoma so se prioritete premaknile k preprostosti in kompaktnosti.

Je mogoče, da sem se motil? Ja seveda. Lahko se na primer izkaže, da smo kupili serijo nizkokakovostnih mikrovezij. Ali pa iz kakšnega drugega razloga oprema ne bo izpolnila pričakovanj glede zanesljivosti.

Ali imam načrt za to? Mislim, da po branju članka ne dvomite, da obstaja načrt. In niti ne sama.

Nekoliko bolj resno je bil format razvit kot delovna možnost in kot "poskusni balon".

Trenutno vse na mizi deluje dobro, dobesedno drugi dan bo rešitev nameščena (približno) na stotine naprav, poglejmo, kaj se zgodi v "bojnem" delovanju (na srečo upam, da vam format omogoča zanesljivo odkrivanje napak; tako da lahko zberete celotno statistiko). Čez nekaj mesecev bo mogoče narediti zaključke (in če nimate sreče, še prej).

Če bodo na podlagi rezultatov uporabe odkrite resne težave in bodo potrebne izboljšave, bom o tem zagotovo pisal.

Literatura

Nisem želel delati dolgega dolgočasnega seznama uporabljenih del; navsezadnje imajo vsi Google.

Tukaj sem se odločil, da pustim seznam ugotovitev, ki so se mi zdele še posebej zanimive, vendar so se postopoma preselile neposredno v besedilo članka in ena točka je ostala na seznamu:

  1. Uporabnost infgen od avtorja zlib. Lahko jasno prikaže vsebino arhivov deflate/zlib/gzip. Če se morate ukvarjati z notranjo strukturo formata deflate (ali gzip), ga toplo priporočam.

Vir: www.habr.com

Dodaj komentar