Minu rõngaspuhvri rakendamine NOR flashis

eelajalugu

Seal on meie enda disainitud müügiautomaadid. Raspberry Pi sees ja osa juhtmestikku eraldi tahvlil. Ühendatud on mündiaktseptor, arve vastuvõtja, pangaterminal... Kõike juhib ise kirjutatud programm. Kogu tööajalugu kirjutatakse mälupulgale (MicroSD) logisse, mis seejärel edastatakse Interneti kaudu (USB-modemi abil) serverisse, kus see salvestatakse andmebaasi. Müügiinfo laetakse 1c-sse, seal on ka lihtne veebiliides jälgimiseks jne.

See tähendab, et ajakiri on eluliselt vajalik - raamatupidamise (tulu, müük jne), jälgimise (igasugused tõrked ja muud vääramatu jõu asjaolud) jaoks; Võib öelda, et see on kogu teave, mis meil selle masina kohta on.

probleem

Flash-draivid näitavad end väga ebausaldusväärsete seadmetena. Nad ebaõnnestuvad kadestamisväärse korrapärasusega. See toob kaasa nii masina seisakuid kui ka (kui logi ei saanud mingil põhjusel võrku edastada) andmete kadumiseni.

See pole esmakordne mälupulkade kasutamise kogemus, enne seda oli veel üks enam kui saja seadmega projekt, kus ajakiri salvestati USB-mälupulkadele, probleeme oli ka töökindlusega, kohati oli ka neid, mis ebaõnnestusid. kuu oli kümnetes. Proovisime erinevaid välkmäluseadmeid, sealhulgas SLC-mäluga kaubamärgiga mäluseadmeid ja mõned mudelid on töökindlamad kui teised, kuid mälupulkade asendamine ei lahendanud probleemi radikaalselt.

Hoiatus! Kaua lugenud! Kui teid ei huvita "miks", vaid ainult "kuidas", võite minna otse Lõpuks artiklid.

otsus

Esimese asjana tuleb meelde: loobuda MicroSD-st, installida näiteks SSD ja käivitada sellelt. Teoreetiliselt võimalik ilmselt, kuid suhteliselt kallis ja mitte nii töökindel (lisatud on USB-SATA adapter; eelarveliste SSD-de rikete statistika pole samuti julgustav).

USB HDD ei tundu samuti eriti ahvatlev lahendus.

Seetõttu jõudsime sellise võimaluseni: jätke MicroSD-lt käivitamine, kuid kasutage neid kirjutuskaitstud režiimis ja salvestage operatsioonilogi (ja muu konkreetse riistvaraosa jaoks ainulaadne teave – seerianumber, andurite kalibreeringud jne) mujale. .

Vaarikate kirjutuskaitstud FS-i teemat on juba seest ja väljast uuritud, ma ei peatu selles artiklis rakendamise üksikasjadel (aga kui on huvi, siis võib-olla kirjutan sellel teemal miniartikli). Ainus punkt, mida tahaksin märkida, on see, et nii isikliku kogemuse kui ka selle juba rakendanud inimeste arvustuste põhjal on usaldusväärsus suurenenud. Jah, riketest on võimatu täielikult vabaneda, kuid nende sageduse märkimisväärne vähendamine on täiesti võimalik. Ja kaardid on muutumas ühtseks, mis muudab hoolduspersonali asendamise palju lihtsamaks.

Riistvara

Mälutüübi valikus polnud erilist kahtlust - NOR Flash.
Argumendid:

  • lihtne ühendus (enamasti SPI-siin, mille kasutamise kogemus on juba olemas, seega pole riistvaraprobleeme ette näha);
  • naeruväärne hind;
  • standardne tööprotokoll (rakendus on juba Linuxi tuumas, soovi korral võite võtta kolmanda osapoole, mis on samuti olemas, või isegi kirjutada oma, õnneks on kõik lihtne);
  • usaldusväärsus ja ressurss:
    tüüpilisest andmelehest: andmeid säilitatakse 20 aastat, iga ploki kohta 100000 XNUMX kustutamistsüklit;
    kolmandate osapoolte allikatest: äärmiselt madal BER, eeldab, et pole vaja veaparanduskoode (mõned tööd peavad ECC-d NOR-i jaoks, kuid tavaliselt tähendavad need siiski MLC NOR-i; juhtub ka seda).

Hinnakem mahu ja ressursi nõudeid.

Soovin, et andmed oleksid garanteeritud mitmeks päevaks. See on vajalik selleks, et kommunikatsiooniprobleemide korral ei läheks müügiajalugu kaduma. Keskendume sel perioodil 5 päevale (isegi kui arvestada nädalavahetusi ja pühasid) probleemi saab lahendada.

Hetkel kogume umbes 100kb logisid päevas (3-4 tuhat kirjet), kuid tasapisi see arv kasvab - detailsus suureneb, uusi sündmusi lisandub. Lisaks on mõnikord katkestusi (mõni andur hakkab näiteks rämpsposti saatma valepositiivsete tulemustega). Arvutame 10 tuhande kirje jaoks 100 baiti - megabaiti päevas.

Kokku tuleb välja 5MB puhast (hästi tihendatud) andmeid. Rohkem neile (ligikaudne hinnang) 1 MB teenindusandmeid.

See tähendab, et me vajame 8 MB kiipi, kui me pakkimist ei kasuta, või 4 MB, kui me seda kasutame. Üsna realistlikud numbrid seda tüüpi mälu kohta.

Mis puudutab ressurssi: kui plaanime, et kogu mälu kirjutatakse ümber mitte rohkem kui üks kord 5 päeva jooksul, siis üle 10 tööaasta saame alla tuhande ümberkirjutamistsükli.
Tuletan meelde, et tootja lubab sada tuhat.

Natuke NOR vs NAND kohta

Tänapäeval on NAND-mälu muidugi palju populaarsem, kuid selle projekti jaoks ma seda ei kasutaks: NAND nõuab erinevalt NOR-ist tingimata veaparanduskoodide, vigaste plokkide tabeli jms kasutamist ning ka NAND-kiibid tavaliselt palju rohkem.

NOR-i puudused hõlmavad järgmist:

  • väike maht (ja vastavalt kõrge hind megabaidi kohta);
  • madal sidekiirus (peamiselt tänu sellele, et kasutatakse jadaliidest, tavaliselt SPI või I2C);
  • aeglane kustutamine (olenevalt ploki suurusest kulub sekundi murdosast mitme sekundini).

Tundub, et meie jaoks pole midagi kriitilist, nii et jätkame.

Kui detailid huvitavad, on mikrolülitus valitud at25df321a (see pole aga oluline, turul on palju analooge, mis ühilduvad pinout- ja käsusüsteemis; isegi kui tahame paigaldada mõne teise tootja ja/või erineva suurusega mikroskeemi, töötab kõik ilma konfiguratsiooni muutmata kood).

Kasutan Linuxi kernelisse sisseehitatud draiverit, Raspberry puhul on tänu seadmepuu ülekatte toele kõik väga lihtne – tuleb kompileeritud ülekate panna kausta /boot/overlays ja faili /boot/config.txt veidi muuta.

Dts-faili näide

Ausalt öeldes pole ma kindel, et see on vigadeta kirjutatud, kuid see töötab.

/*
 * 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?";
    };
};

Ja veel üks rida failis config.txt

dtoverlay=at25:spimaxfrequency=50000000

Kiibi Raspberry Pi-ga ühendamise kirjelduse jätan välja. Ühest küljest pole ma elektroonikaekspert, teisalt on siin kõik isegi minu jaoks banaalne: mikroskeemil on ainult 8 jalga, millest vajame maandust, toidet, SPI-d (CS, SI, SO, SCK ); tasemed on samad, mis Raspberry Pi-l, lisajuhtmeid pole vaja – lihtsalt ühenda näidatud 6 tihvti.

Probleemi avaldus

Nagu tavaliselt, läbib probleemipüstitus mitu iteratsiooni ja mulle tundub, et on aeg järgmiseks. Seega peatume, paneme kokku juba kirjutatu ja teeme selgeks need detailid, mis jäävad varju.

Seega oleme otsustanud, et logi salvestatakse SPI NOR Flashi.

Mis on NOR Flash neile, kes ei tea?

See on püsimälu, millega saate teha kolme toimingut:

  1. Lugemine:
    Levinuim lugemine: edastame aadressi ja loeme nii palju baite kui vaja;
  2. Kirje:
    NOR-välklambi kirjutamine näeb välja nagu tavaline, kuid sellel on üks eripära: saate muuta ainult 1 väärtuseks 0, kuid mitte vastupidi. Näiteks kui meil oli mälulahtris 0x55, siis pärast 0x0f kirjutamist sinna salvestatakse juba 0x05 (vt tabelit allpool);
  3. Kustuta:
    Muidugi peame suutma teha vastupidist toimingut – muutke 0 1-ks, just selleks on kustutamisoperatsioon. Erinevalt kahest esimesest ei tööta see mitte baitidega, vaid plokkidega (valitud kiibi minimaalne kustutamisplokk on 4 kb). Kustutamine hävitab kogu ploki ja on ainus viis muuta 0 väärtuseks 1. Seetõttu tuleb välkmäluga töötades sageli andmestruktuurid joondada kustutamisploki piiriga.
    NOR Flashiga salvestamine:

Binaarsed andmed

Oli
01010101

Salvestatud
00001111

On saanud
00000101

Logi ise esindab muutuva pikkusega kirjete jada. Kirje tüüpiline pikkus on umbes 30 baiti (kuigi mõnikord tuleb ette ka mitme kilobaidi pikkuseid kirjeid). Sel juhul töötame nendega lihtsalt baitide komplektina, kuid kui olete huvitatud, kasutatakse kirjete sees CBOR-i

Lisaks logile peame salvestama nii värskendatud kui ka mitte seadistusteavet: teatud seadme ID, andurite kalibreeringud, lipuke "seade on ajutiselt keelatud" jne.
See teave on võtmeväärtuste kirjete kogum, mis on samuti salvestatud CBOR-i. Meil ​​pole seda teavet palju (kõige rohkem paar kilobaiti) ja seda värskendatakse harva.
Järgnevalt nimetame seda kontekstiks.

Kui meenutada, kust see artikkel alguse sai, siis on väga oluline tagada usaldusväärne andmete salvestamine ja võimalusel pidev töö ka riistvaratõrgete/andmete riknemise korral.

Milliseid probleemide allikaid võib pidada?

  • Lülitage kirjutamise/kustutamise ajal välja. See pärineb kategooriast "Kangrauda vastu pole trikki".
    Teave alates arutelud virnavahetusel: kui välguga töötamise ajal toide välja lülitatakse, põhjustavad nii kustutamine (1) kui ka kirjutamine (0) määratlemata käitumist: andmeid saab kirjutada, osaliselt kirjutada (ütleme, et edastasime 10 baiti/80 bitti , kuid veel ei saa kirjutada ainult 45 bitti), on ka võimalik, et osa bitte on vahepealses olekus (lugemine võib anda nii 0 kui 1);
  • Vead välkmälus endas.
    BER, kuigi väga madal, ei saa olla võrdne nulliga;
  • Bussi vead
    SPI kaudu edastatavad andmed ei ole mingil viisil kaitstud, võib esineda nii üksiku biti vigu kui ka sünkroonimisvigu - bittide kadu või sisestamine (mis toob kaasa tohutu andmemoonutuse);
  • Muud vead/tõrked
    Vead koodis, Raspberry tõrked, tulnukate sekkumine ...

Olen sõnastanud nõuded, mille täitmine on minu hinnangul usaldusväärsuse tagamiseks vajalik:

  • kirjed peavad koheselt välkmällu minema, hilinenud kirjutamisi arvesse ei võeta;- tõrke ilmnemisel tuleb see võimalikult vara tuvastada ja töödelda;- süsteem peab võimalusel vigadest taastuma.
    (näide elust "kuidas see ei peaks olema", millega ma arvan, et kõik on kokku puutunud: pärast hädaolukorra taaskäivitamist on failisüsteem "katki" ja operatsioonisüsteem ei käivitu)

Ideed, lähenemised, mõtisklused

Kui ma sellele probleemile mõtlema hakkasin, sähvatas mu peast palju ideid, näiteks:

  • kasutada andmete tihendamist;
  • kasutage nutikaid andmestruktuure, näiteks salvestage kirje päised kirjetest endist eraldi, nii et kui mõnes kirjes on viga, saate ülejäänud osa probleemideta lugeda;
  • kasutage bitivälju, et kontrollida salvestamise lõpetamist, kui toide on välja lülitatud;
  • salvestage kõige jaoks kontrollsummad;
  • kasutage mõnda tüüpi mürakindlat kodeerimist.

Mõnda neist ideedest kasutati ära, osadest aga otsustati loobuda. Lähme järjekorras.

Andmete tihendamine

Sündmused ise, mida ajakirjas kirja paneme, on üsna sarnased ja korratavad (“viskas 5-rublase mündi”, “vajutas vahetusraha andmise nuppu”, ...). Seetõttu peaks kompressioon olema üsna tõhus.

Kompressioon on tühine (meie protsessor on üsna võimas, isegi esimesel Pi-l oli üks tuum sagedusega 700 MHz, praegustel mudelitel on mitu tuuma sagedusega üle gigahertsi), vahetuskurss salvestusruumiga on madal (mitu megabaiti sekundis), on kirjete suurus väike. Üldiselt, kui tihendamine mõjutab jõudlust, on see ainult positiivne. (täiesti kriitikavaba, lihtsalt ütlen). Lisaks pole meil päris manustatud, vaid tavaline Linux - nii et juurutamine ei tohiks palju vaeva nõuda (piisab lihtsalt raamatukogu linkimisest ja selle mitme funktsiooni kasutamisest).

Töötavast seadmest võeti logitükk (1.7 MB, 70 tuhat kirjet) ja esmalt kontrolliti tihendatavust arvutis saadaolevate gzip, lz4, lzop, bzip2, xz, zstd abil.

  • gzip, xz, zstd näitasid sarnaseid tulemusi (40Kb).
    Mind üllatas, et moekas xz näitas end siin gzip või zstd tasemel;
  • lzip vaikeseadetega andis veidi halvemaid tulemusi;
  • lz4 ja lzop ei näidanud väga häid tulemusi (150Kb);
  • bzip2 näitas üllatavalt head tulemust (18Kb).

Seega on andmed väga hästi tihendatud.
Seega (kui me ei leia saatuslikke vigu) toimub tihendus! Lihtsalt sellepärast, et samale mälupulgale mahub rohkem andmeid.

Mõelgem miinuste peale.

Esimene probleem: oleme juba kokku leppinud, et iga plaat peab koheselt vilkuma. Tavaliselt kogub arhiveerija andmeid sisendvoost seni, kuni otsustab, et on aeg kirjutada nädalavahetusel. Peame kohe vastu võtma tihendatud andmeploki ja salvestama selle püsimällu.

Ma näen kolme võimalust:

  1. Tihendage iga kirje, kasutades ülalkirjeldatud algoritmide asemel sõnastiku tihendamist.
    See on täiesti töötav variant, aga mulle see ei meeldi. Enam-vähem korraliku tihendustaseme tagamiseks peab sõnastik olema konkreetsete andmete järgi “kohandatud”, mis tahes muudatus toob kaasa tihendustaseme katastroofilise languse. Jah, probleemi saab lahendada sõnastiku uue versiooni loomisega, kuid see on peavalu – peame salvestama kõik sõnastiku versioonid; igas kirjes peame märkima, millise sõnastiku versiooniga see tihendati...
  2. Tihendage iga kirje "klassikaliste" algoritmide abil, kuid teistest sõltumatult.
    Vaadeldavad tihendusalgoritmid ei ole loodud töötama sellise suurusega (kümneid baite) kirjetega, tihendussuhe on selgelt väiksem kui 1 (st tihendamise asemel andmemahu suurendamine);
  3. Pärast iga salvestamist loputage.
    Paljud tihendusteegid toetavad FLUSH-i. See on käsk (või tihendusprotseduuri parameeter), mille vastuvõtmisel moodustab arhiveerija tihendatud voo, et seda saaks kasutada taastamiseks kõik tihendamata andmed, mis on juba vastu võetud. Selline analoog sync failisüsteemides või commit SQL-is.
    Oluline on see, et järgnevad tihendustoimingud saaksid kasutada kogutud sõnastikku ja tihendusaste ei kannata nii palju kui eelmises versioonis.

Arvan, et on ilmne, et valisin kolmanda võimaluse, vaatame seda üksikasjalikumalt.

Leitud suurepärane artikkel FLUSHi kohta zlibis.

Tegin artikli põhjal põlvetesti, võtsin päris seadmest 70 tuhat logikirjet, lehe suurusega 60Kb (tuleme lehe suuruse juurde hiljem tagasi) sai:

Toorandmed
Pakkimine gzip -9 (ei ole FLUSH)
zlib koos Z_PARTIAL_FLUSHiga
zlib koos Z_SYNC_FLUSH-iga

Maht, KB
1692
40
352
604

Esmapilgul on FLUSH-i panustatud hind ülemäära kõrge, kuid tegelikkuses on meil vähe valikut - kas üldse mitte kokku suruda või kompresseerida (ja väga tõhusalt) FLUSHiga. Ei tohi unustada, et meil on 70 tuhat kirjet, Z_PARTIAL_FLUSH-i poolt kasutusele võetud liiasus on vaid 4-5 baiti kirje kohta. Ja tihendussuhe osutus peaaegu 5:1, mis on enam kui suurepärane tulemus.

See võib tulla üllatusena, kuid Z_SYNC_FLUSH on tegelikult tõhusam viis FLUSH-i tegemiseks

Funktsiooni Z_SYNC_FLUSH kasutamisel on iga kirje viimased 4 baiti alati 0x00, 0x00, 0xff, 0xff. Ja kui me neid teame, siis me ei pea neid salvestama, seega on lõplik suurus vaid 324 Kb.

Artiklil, millele linkisin, on selgitus:

Lisatakse uus tühja sisuga 0 tüüpi plokk.

Tühja sisuga 0-tüüpi plokk koosneb:

  • kolmebitise ploki päis;
  • 0 kuni 7 bitti, mis on võrdne nulliga, et saavutada baitide joondamine;
  • neljabaidine jada 00 00 FF FF.

Nagu näete, on viimases plokis enne neid 4 baiti 3 kuni 10 nullbitti. Praktika on aga näidanud, et tegelikult on seal vähemalt 10 nullbitti.

Selgub, et sellised lühikesed andmeplokid on tavaliselt (alati?) kodeeritud 1. tüüpi plokki (fikseeritud plokk) abil, mis lõppeb tingimata 7 nullbitiga, mis annab kokku 10-17 garanteeritud nullbitti (ja ülejäänud on olema null umbes 50% tõenäosusega.

Seega on testandmetel 100% juhtudest üks null bait enne 0x00, 0x00, 0xff, 0xff ja enam kui kolmandikul juhtudest on kaks nullbaiti (võib-olla on tõsiasi, et ma kasutan binaarset CBOR-i ja teksti JSON-i kasutamisel on 2. tüüpi plokid tavalisemad - dünaamiline plokk oleks vastavalt tavalisem, plokke ilma täiendavate nullbaitideta enne 0x00, 0x00, 0xff, 0xff).

Kokku on olemasolevaid testandmeid kasutades võimalik mahtuda alla 250Kb tihendatud andmete hulka.

Bittide žongleerimisega saab veidi rohkem säästa: praegu eirame mõne nullbiti olemasolu ploki lõpus, paar bitti ploki alguses samuti ei muutu...
Kuid siis tegin tugeva tahtega otsuse lõpetada, vastasel juhul võin sellisel kiirusel välja töötada oma arhiivi.

Kokku sain oma testiandmetest 3-4 baiti kirjutamise kohta, tihendussuhe osutus üle 6:1. Ütlen ausalt: ma ei oodanud sellist tulemust, minu arvates on kõik parem kui 2:1 juba tulemus, mis õigustab kompressiooni kasutamist.

Kõik on korras, kuid zlib (deflate) on siiski arhailine, väljateenitud ja veidi vanamoodne tihendusalgoritm. Ainuüksi asjaolu, et viimast 32Kb tihendamata andmevoost kasutatakse sõnaraamatuna, tundub tänapäeval kummaline (st kui mõni andmeplokk on väga sarnane sellele, mis oli sisendvoos 40Kb tagasi, siis hakatakse seda uuesti arhiveerima, ja ei viita varasemale esinemisele). Moodsates kaasaegsetes arhiivides mõõdetakse sõnastiku suurust sageli pigem megabaitides kui kilobaitides.

Seega jätkame arhiivipidajate miniuuringut.

Järgmisena testisime bzip2-d (pidage meeles, et ilma FLUSHita näitas see fantastilist tihendussuhet peaaegu 100:1). Kahjuks toimis see FLUSH-iga väga halvasti; tihendatud andmete suurus osutus tihendamata andmetest suuremaks.

Minu oletused ebaõnnestumise põhjuste kohta

Libbz2 pakub ainult ühte loputusvalikut, mis näib sõnastiku tühjendamist (analoogselt Z_FULL_FLUSH-ga zlib-is); pärast seda pole enam juttugi tõhusast tihendamisest.

Ja viimane, mida testiti, oli zstd. Sõltuvalt parameetritest tihendab see kas gzipi tasemel, kuid palju kiiremini või paremini kui gzip.

Paraku FLUSH-iga see väga hästi ei toiminud: tihendatud andmete suurus oli umbes 700 Kb.

Я esitas küsimuse projekti githubi lehel sain vastuse, et iga tihendatud andmeploki kohta peaksite arvestama kuni 10 baiti teenuseandmetega, mis on ligilähedane saadud tulemustele; deflatsioonile pole kuidagi võimalik järele jõuda.

Otsustasin siinkohal oma katsetes arhiveerijatega peatuda (tuletan teile meelde, et xz, lzip, lzo, lz4 ei näidanud end isegi testimisetapis ilma FLUSH-ita ja ma ei kaalunud eksootilisemaid tihendusalgoritme).

Tuleme tagasi arhiveerimisprobleemide juurde.

Teine (nagu öeldakse järjekorras, mitte väärtuses) probleem on see, et kokkusurutud andmed on üks voog, milles on pidevalt viiteid eelmistele jaotistele. Seega, kui tihendatud andmete osa on kahjustatud, kaotame mitte ainult sellega seotud tihendamata andmete ploki, vaid ka kõik järgnevad.

Selle probleemi lahendamiseks on lähenemisviis:

  1. Enneta probleemi tekkimist – lisa tihendatud andmetele liiasust, mis võimaldab tuvastada ja parandada vigu; me räägime sellest hiljem;
  2. Probleemi ilmnemisel minimeerige tagajärjed
    Oleme juba varem öelnud, et iga andmeploki saab tihendada iseseisvalt ja probleem kaob iseenesest (ühe ploki andmete kahjustamine toob kaasa andmete kadumise ainult selle ploki puhul). See on aga äärmuslik juhtum, kus andmete tihendamine on ebaefektiivne. Vastupidine äärmus: kasutage kogu meie kiipi 4 MB ühtse arhiivina, mis annab meile suurepärase tihendamise, kuid andmete kahjustamise korral katastroofilised tagajärjed.
    Jah, usaldusväärsuse osas on vaja kompromissi. Kuid me peame meeles pidama, et töötame välja ülimadala BER-i ja deklareeritud andmete säilitamise perioodiga 20 aastat püsimälu jaoks mõeldud andmesalvestusvormingut.

Katsete käigus avastasin, et alla 10 KB suuruste tihendatud andmeplokkide puhul algavad enam-vähem märgatavad tihendustaseme kaod.
Eelnevalt sai mainitud, et kasutatav mälu on pagetud, ma ei näe põhjust, miks ei peaks kasutama kirjavahetust “üks leht – üks tihendatud andmete plokk”.

See tähendab, et minimaalne mõistlik lehe suurus on 16 Kb (koos reserviga teenuseteabe jaoks). Nii väike lehe suurus seab aga olulisi piiranguid kirje maksimaalsele suurusele.

Kuigi ma ei oota veel tihendatud kujul mõne kilobaidi suuremaid kirjeid, otsustasin kasutada 32 Kb lehti (kokku 128 lehekülge kiibi kohta).

Kokkuvõte:

  • Salvestame zlib (deflate) abil tihendatud andmed;
  • Iga kirje jaoks määrame Z_SYNC_FLUSH;
  • Iga tihendatud kirje puhul kärbime lõpubaite (nt 0x00, 0x00, 0xff, 0xff); päises märgime, mitu baiti me ära lõikame;
  • Andmeid salvestame 32Kb lehtedena; lehe sees on üks tihendatud andmete voog; Igal lehel alustame tihendamist uuesti.

Ja enne pakkimise lõpetamist juhin teie tähelepanu asjaolule, et meil on ainult paar baiti tihendatud andmeid ühe kirje kohta, seega on äärmiselt oluline mitte paisutada teenuseteavet, siin loeb iga bait.

Andmete päiste salvestamine

Kuna meil on muutuva pikkusega kirjed, siis peame kuidagi määrama kirjete paigutuse/piirid.

Tean kolme lähenemist:

  1. Kõik kirjed salvestatakse pidevas voos, kõigepealt on kirje päis, mis sisaldab pikkust, ja seejärel kirje ise.
    Selles teostuses võivad nii päised kui ka andmed olla erineva pikkusega.
    Sisuliselt saame üksikult lingitud loendi, mida kasutatakse kogu aeg;
  2. Päised ja kirjed ise salvestatakse eraldi voogudesse.
    Konstantse pikkusega päiseid kasutades tagame, et ühe päise kahjustus ei mõjuta teisi.
    Sarnast lähenemist kasutatakse näiteks paljudes failisüsteemides;
  3. Kirjed salvestatakse pidevas voos, kirje piiri määrab teatud marker (märk/märgijada, mis on andmeplokkides keelatud). Kui kirje sees on marker, siis asendame selle mingi jadaga (escep it).
    Sarnast lähenemist kasutatakse näiteks PPP protokollis.

Ma illustreerin.

Võimalus 1:
Minu rõngaspuhvri rakendamine NOR flashis
Siin on kõik väga lihtne: teades kirje pikkust, saame arvutada järgmise päise aadressi. Nii liigume läbi pealkirjade, kuni kohtame ala, mis on täidetud 0xff-ga (vaba ala) või lehe lõppu.

Võimalus 2:
Minu rõngaspuhvri rakendamine NOR flashis
Kirje muutuva pikkuse tõttu ei saa me ette öelda, mitu kirjet (ja seega ka päiseid) meil ühele lehele vaja läheb. Päiseid ja andmeid ise saab erinevatele lehtedele hajutada, kuid eelistan teistsugust lähenemist: paigutame nii päised kui ka andmed ühele lehele, kuid päised (konstantse suurusega) tulevad lehe algusest ja andmed (muutuva pikkusega) pärinevad lõpust. Niipea kui nad "kohtuvad" (uue kirje jaoks pole piisavalt vaba ruumi), loeme selle lehe täielikuks.

Võimalus 3:
Minu rõngaspuhvri rakendamine NOR flashis
Päisesse pole vaja salvestada pikkust ega muud infot andmete asukoha kohta, piisab kirjete piire tähistavatest markeritest. Kirjutamisel/lugemisel tuleb aga andmeid töödelda.
Mina kasutaksin markerina 0xff (mis pärast kustutamist täidab lehe), nii et vaba ala kindlasti andmetena ei käsitleta.

Võrdlustabel:

Valik 1
Valik 2
Valik 3

Vea taluvus
-
+
+

Kompaktne
+
-
+

Rakenduse keerukus
*
**
**

1. valikul on saatuslik viga: kui mõni päistest on kahjustatud, hävib kogu järgnev ahel. Ülejäänud valikud võimaldavad teil mõningaid andmeid taastada isegi suurte kahjustuste korral.
Kuid siinkohal on asjakohane meeles pidada, et otsustasime andmed salvestada tihendatud kujul ja nii kaotame kõik lehel olevad andmed pärast "katkist" kirjet, nii et kuigi tabelis on miinus, me seda ei tee. sellega arvestama.

Kompaktsus:

  • esimeses variandis peame päisesse salvestama ainult pikkuse, kui kasutame muutuva pikkusega täisarve, siis enamikul juhtudel saame hakkama ühe baidiga;
  • teises valikus peame salvestama algusaadressi ja pikkuse; kirje peab olema konstantse suurusega, hinnanguliselt 4 baiti kirje kohta (kaks baiti nihkeks ja kaks baiti pikkuseks);
  • kolmas valik vajab ainult ühte märki, mis näitab salvestamise algust, pluss salvestus ise suureneb varjestuse tõttu 1-2%. Üldiselt ligikaudu võrdne esimese variandiga.

Esialgu pidasin peamiseks teist võimalust (ja kirjutasin isegi teostuse). Loobusin sellest alles siis, kui lõpuks otsustasin kompressiooni kasutada.

Võib-olla kasutan kunagi sarnast võimalust. Näiteks kui ma pean tegelema Maa ja Marsi vahet sõitva laeva andmete salvestamisega, siis on töökindluse, kosmilise kiirguse, ...

Mis puutub kolmandasse varianti: andsin sellele kaks tärni rakendamise raskuse eest lihtsalt sellepärast, et mulle ei meeldi varjestusega jamada, pikkust protsessi käigus muuta jne. Jah, võib-olla olen erapoolik, aga pean koodi kirjutama – milleks sundida end tegema midagi, mis sulle ei meeldi.

Kokkuvõte: Tõhususe ja teostamise lihtsuse tõttu valime salvestusvõimaluse kettide kujul “Pikkusega päis - muutuva pikkusega andmed”.

Bitiväljade kasutamine kirjutustoimingute õnnestumise jälgimiseks

Ma ei mäleta praegu, kust see idee tuli, aga see näeb välja umbes selline:
Iga kirje jaoks eraldame lippude salvestamiseks mitu bitti.
Nagu me varem ütlesime, täidetakse pärast kustutamist kõik bitid 1-ga ja me saame muuta 1 väärtuseks 0, kuid mitte vastupidi. Nii et "lipp pole seatud" jaoks kasutame 1, "lipp on seatud" jaoks kasutame 0.

Muutuva pikkusega salvestuse välklampi panemine võib välja näha järgmine:

  1. Määrake lipp "pikkuse salvestamine on alanud";
  2. Salvestage pikkus;
  3. Määrake lipp "andmete salvestamine on alanud";
  4. Salvestame andmeid;
  5. Määrake lipp "salvestus on lõppenud".

Lisaks on meil "viga ilmnenud" lipp, kokku 4 biti lippe.

Sel juhul on meil kaks stabiilset olekut "1111" - salvestamine ei ole alanud ja "1000" - salvestamine õnnestus; salvestusprotsessi ootamatu katkestuse korral saame vaheolekud, mida saame seejärel tuvastada ja töödelda.

Lähenemine on huvitav, kuid kaitseb vaid äkiliste elektrikatkestuste ja sarnaste rikete eest, mis on muidugi oluline, kuid see pole kaugeltki ainus (või isegi peamine) võimalike rikete põhjus.

Kokkuvõte: Liigume edasi head lahendust otsima.

Kontrollsummad

Kontrollsummad võimaldavad ka (mõistliku tõenäosusega) veenduda, et loeme täpselt seda, mida oleks pidanud kirjutama. Ja erinevalt ülalpool käsitletud bitiväljadest töötavad need alati.

Kui arvestada ülalpool käsitletud võimalike probleemide allikate loendit, suudab kontrollsumma tuvastada vea olenemata selle päritolust. (välja arvatud ehk pahatahtlikud tulnukad - ka nemad võivad kontrollsummat võltsida).

Nii et kui meie eesmärk on kontrollida, kas andmed on terved, on kontrollsummad suurepärane idee.

Kontrollsumma arvutamise algoritmi valik ei tekitanud küsimusi – CRC. Ühelt poolt võimaldavad matemaatilised omadused teatud tüüpi vigu 100% tabada, teisalt näitab see algoritm juhuslikel andmetel tavaliselt teoreetilisest piirist mitte palju suuremat kokkupõrgete tõenäosust. Minu rõngaspuhvri rakendamine NOR flashis. See ei pruugi olla kõige kiirem algoritm ega ka alati minimaalne kokkupõrgete arvu poolest, kuid sellel on väga oluline omadus: katsetes, millega kokku puutusin, ei olnud mustreid, milles see selgelt ebaõnnestus. Stabiilsus on sel juhul peamine kvaliteet.

Näide mahulisest uuringust: Osa 1, Osa 2 (lingid saidile narod.ru, vabandust).

Kontrollsumma valimise ülesanne ei ole aga täielik, CRC on terve kontrollsummade perekond. Peate otsustama pikkuse üle ja seejärel valima polünoomi.

Kontrollsumma pikkuse valimine pole nii lihtne küsimus, kui esmapilgul tundub.

Lubage mul illustreerida:
Olgu meil igas baidis vea tõenäosus Minu rõngaspuhvri rakendamine NOR flashis ja ideaalne kontrollsumma, arvutame keskmise vigade arvu miljoni kirje kohta:

Andmed, bait
Kontrollsumma, bait
Avastamata vead
Valed veatuvastused
Valepositiivseid tulemusi kokku

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

Näib, et kõik on lihtne - sõltuvalt kaitstavate andmete pikkusest valige kontrollsumma pikkus minimaalselt valede positiivsetega - ja trikk on kotis.

Lühikeste kontrollsummade puhul tekib aga probleem: kuigi nad suudavad hästi tuvastada ühebitise vigu, suudavad nad üsna suure tõenäosusega aktsepteerida täiesti juhuslikke andmeid õigetena. Habré kohta oli juba artikkel, mis kirjeldas probleem päriselus.

Seetõttu peate juhusliku kontrollsumma sobitamise peaaegu võimatuks muutmiseks kasutama kontrollsummasid, mis on 32 bitti või pikemad. (üle 64 biti pikkuste puhul kasutatakse tavaliselt krüptograafilisi räsifunktsioone).

Hoolimata sellest, et kirjutasin varem, et ruumi tuleb igal juhul kokku hoida, kasutame siiski 32-bitist kontrollsummat (16 bitist ei piisa, kokkupõrke tõenäosus on üle 0.01% ja 24 bitti, kuna need öelda, ei ole siin ega seal) .

Siin võib tekkida vastuväide: kas pakkimise valimisel salvestasime iga baidi, et anda nüüd 4 baiti korraga? Kas poleks parem mitte tihendada ega lisada kontrollsummat? Muidugi mitte, ei mingit kompressiooni ei tähenda, et me ei vaja terviklikkuse kontrollimist.

Polünoomi valimisel me ratast uuesti ei leiuta, vaid võtame nüüd populaarse CRC-32C.
See kood tuvastab 6-bitised vead kuni 22-baidistel pakettidel (meie jaoks võib-olla kõige levinum juhtum), 4-bitised vead kuni 655-baidistel pakettidel (samuti tavaline juhtum meie jaoks), 2- või mis tahes paaritu arvu bitivigu pakettidel mis tahes mõistliku pikkusega.

Kui kedagi huvitab detailid

Wikipedia artikkel CRC kohta.

Koodi parameetrid crc-32c edasi Koopmani veebisait — võib-olla planeedi juhtiv CRC spetsialist.

В tema artikkel on veel üks huvitav kood, mis annab meile asjakohastele pakettide pikkustele veidi paremad parameetrid, kuid ma ei pidanud erinevust oluliseks ning olin piisavalt pädev valima standardse ja põhjalikult uuritud koodi asemel kohandatud koodi.

Samuti, kuna meie andmed on tihendatud, tekib küsimus: kas peaksime arvutama tihendatud või tihendamata andmete kontrollsumma?

Argumendid tihendamata andmete kontrollsumma arvutamise kasuks:

  • Lõppkokkuvõttes peame kontrollima andmete salvestamise ohutust - seega kontrollime seda otse (samal ajal kontrollitakse ka võimalikke vigu tihendamise/dekompressiooni realiseerimisel, katkisest mälust põhjustatud kahjustusi jne);
  • Zlib-i tühjendamise algoritmil on üsna küps teostus ja ei peaks langeb "kõverate" sisendandmetega; pealegi suudab see sageli iseseisvalt tuvastada sisendvoos olevaid vigu, vähendades üldist vea tuvastamata jätmise tõenäosust (sooritas test lühikese kirje ühe biti inverteerimisega, zlib tuvastas vea umbes kolmandikul juhtudest).

Argumendid tihendamata andmete kontrollsumma arvutamise vastu:

  • CRC on “kohandatud” spetsiaalselt väheste välkmälule omaste bitivigade jaoks (bitiviga tihendatud voos võib põhjustada tohutu muutuse väljundvoos, mille puhul puhtteoreetiliselt saame kokkupõrke “püüda”);
  • Mulle ei meeldi mõte potentsiaalselt katkiste andmete edastamisest dekompressorisse, Kes teabkuidas ta reageerib.

Selles projektis otsustasin kalduda kõrvale üldtunnustatud tavast salvestada tihendamata andmete kontrollsumma.

Kokkuvõte: Kasutame CRC-32C, kontrollsumma arvutame andmetest sellisel kujul, nagu need on flash’iks kirjutatud (pärast tihendamist).

Koondamine

Üleliigse kodeerimise kasutamine ei välista loomulikult andmete kadu, kuid võib märkimisväärselt (sageli mitme suurusjärgu võrra) vähendada taastamatu andmekao tõenäosust.

Vigade parandamiseks saame kasutada erinevat tüüpi liiasust.
Hamming-koodid võivad parandada ühebitiseid vigu, Reed-Solomoni märgikoode, mitut andmete koopiat koos kontrollsummadega või kodeeringud, nagu RAID-6, võivad aidata andmeid taastada isegi ulatusliku korruptsiooni korral.
Algselt olin pühendunud veakindla kodeerimise laialdasele kasutamisele, kuid siis mõistsin, et esmalt peab meil olema ettekujutus, milliste vigade eest tahame end kaitsta, ja seejärel valida kodeerimine.

Me ütlesime varem, et vead tuleb võimalikult kiiresti tabada. Millistes punktides võime esineda vigu?

  1. Lõpetamata salvestamine (mingil põhjusel oli salvestamise ajal toide välja lülitatud, Raspberry hangus, ...)
    Paraku ei jää sellise tõrke korral üle muud, kui ignoreerida kehtetuid kirjeid ja lugeda andmed kadunuks;
  2. Kirjutamisvead (mingil põhjusel ei olnud välkmällu kirjutatud see, mis kirjutati)
    Selliseid vigu saame kohe tuvastada, kui teeme kohe pärast salvestamist testloe;
  3. Andmete moonutamine mälus salvestamise ajal;
  4. Lugemisvead
    Selle parandamiseks piisab, kui kontrollsumma ei ühti, korrata lugemist mitu korda.

See tähendab, et ainult kolmandat tüüpi vigu (andmete spontaanne rikkumine salvestamise ajal) ei saa parandada ilma veakindla kodeerimiseta. Tundub, et sellised vead on endiselt äärmiselt ebatõenäolised.

Kokkuvõte: otsustati loobuda üleliigsest kodeerimisest, kuid kui operatsioon näitab selle otsuse viga, naaske probleemi käsitlemise juurde (koos juba kogutud tõrgete statistikaga, mis võimaldab valida optimaalse kodeerimise tüübi).

Muu

Loomulikult ei võimalda artikli formaat õigustada igat vormingut (ja mu jõud on juba otsa saanud), seega käsitlen lühidalt mõnda punkti, mida varem ei puudutatud.

  • Otsustati muuta kõik lehed "võrdseks"
    See tähendab, et ei teki spetsiaalseid metaandmetega lehti, eraldi lõime jne, vaid üks lõim, mis kirjutab kõik lehed kordamööda ümber.
    See tagab lehtede ühtlase kulumise, ühegi tõrkepunkti puudumise ja mulle lihtsalt meeldib;
  • Vormingu versioonimine on hädavajalik.
    Formaat, mille päises pole versiooninumbrit, on kurjast!
    Piisab, kui lisada lehe päisesse teatud maagilise numbriga väli (allkiri), mis näitab kasutatava vormingu versiooni (Ma ei usu, et praktikas on neid kümmekond);
  • Kasutage kirjete jaoks (mida on palju) muutuva pikkusega päist, püüdes enamikul juhtudel teha selle pikkuseks 1 bait;
  • Tihendatud kirje päise pikkuse ja kärbitud osa pikkuse kodeerimiseks kasutage muutuva pikkusega binaarkoode.

Aitas palju võrgugeneraator Huffmani koodid. Vaid mõne minutiga saime valida vajalikud muutuva pikkusega koodid.

Andmete salvestamise vormingu kirjeldus

Baitijärjestus

Ühest baidist suuremad väljad salvestatakse big-endian-vormingus (võrgubaitide järjekord), see tähendab, et 0x1234 kirjutatakse kujul 0x12, 0x34.

Leheküljed

Kogu välkmälu on jagatud võrdse suurusega lehtedeks.

Vaikimisi on lehe suurus 32Kb, kuid mitte rohkem kui 1/4 mälukiibi kogumahust (4MB kiibi puhul saadakse 128 lehekülge).

Iga leht salvestab andmeid teistest sõltumatult (st ühel lehel olevad andmed ei viita teise lehe andmetele).

Kõik leheküljed on nummerdatud loomulikus järjekorras (aadresside kasvavas järjekorras), alustades numbriga 0 (null lehekülg algab aadressist 0, esimene leht algab 32Kb, teine ​​leht algab 64Kb jne)

Mälukiipi kasutatakse tsüklilise puhvrina (ring buffer), see tähendab, et esmalt läheb kirjutamine leheküljele number 0, siis number 1, ..., kui täidame viimase lehe, algab uus tsükkel ja salvestamine jätkub leheküljelt null .

Lehe sees

Minu rõngaspuhvri rakendamine NOR flashis
Lehe alguses salvestatakse 4-baidine lehe päis, seejärel päise kontrollsumma (CRC-32C), seejärel salvestatakse kirjed vormingus “päis, andmed, kontrollsumma”.

Lehe pealkiri (diagrammil määrdunudroheline) koosneb:

  • kahebaidine maagilise numbri väli (samuti vormingu versiooni märk)
    vormingu praeguse versiooni puhul arvutatakse see järgmiselt 0xed00 ⊕ номер страницы;
  • kahebaidine loendur “Lehekülje versioon” (mälu ümberkirjutamise tsükli number).

Lehe kirjed salvestatakse tihendatud kujul (kasutatakse tühjendusalgoritmi). Kõik ühel lehel olevad kirjed tihendatakse ühte lõime (kasutatakse tavalist sõnastikku) ja igal uuel lehel algab tihendamine uuesti. See tähendab, et mis tahes kirje lahtipakkimiseks on nõutavad kõik selle lehe varasemad kirjed (ja ainult see üks).

Iga kirje tihendatakse lipuga Z_SYNC_FLUSH ja tihendatud voo lõpus on 4 baiti 0x00, 0x00, 0xff, 0xff, millele võib eelneda veel üks või kaks nullbaiti.
Välkmällu kirjutades jätame selle jada (4, 5 või 6 baiti pikk).

Kirje päis on 1, 2 või 3 baiti, mis salvestab:

  • üks bitt (T), mis näitab kirje tüüpi: 0 - kontekst, 1 - logi;
  • muutuva pikkusega väli (S) 1 kuni 7 bitti, mis määrab päise pikkuse ja "saba", mis tuleb kirjele lahtipakkimiseks lisada;
  • rekordpikkus (L).

S väärtuste tabel:

S
Päise pikkus, bait
Loobutud kirjutamisel, bait

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)

Üritasin illustreerida, ma ei tea, kui selgelt see välja tuli:
Minu rõngaspuhvri rakendamine NOR flashis
Kollane tähistab siin T-välja, valge S-välja, roheline L (tihendatud andmete pikkus baitides), sinine tihendatud andmeid, punane tihendatud andmete viimaseid baite, mida välkmällu ei kirjutata.

Seega saame enimlevinud pikkusega (kuni 63+5 baiti tihendatud kujul) kirjepäised kirjutada ühes baidis.

Pärast iga kirjet salvestatakse CRC-32C kontrollsumma, milles kasutatakse algväärtusena (init) eelmise kontrollsumma ümberpööratud väärtust.

CRC-l on omadus "kestus", töötab järgmine valem (pluss või miinus biti inversioon protsessis): Minu rõngaspuhvri rakendamine NOR flashis.
See tähendab, et tegelikult arvutame sellel lehel kõigi eelnevate päiste ja andmete baitide CRC.

Otse kontrollsumma järel on järgmise kirje päis.

Päis on kujundatud nii, et selle esimene bait erineb alati 0x00-st ja 0xff-st (kui päise esimese baidi asemel kohtame 0xff, tähendab see, et tegemist on kasutamata alaga; 0x00 annab veast märku).

Näidisalgoritmid

Välkmälust lugemine

Iga lugemisega kaasneb kontrollsumma kontroll.
Kui kontrollsumma ei ühti, korratakse lugemist mitu korda lootuses lugeda õigeid andmeid.

(see on loogiline, Linux ei salvesta NOR Flashi lugemisi vahemällu, testitud)

Kirjutage välkmällu

Salvestame andmed.
Loeme neid.

Kui loetud andmed ei ühti kirjutatud andmetega, täidame ala nullidega ja anname veast märku.

Uue mikrolülituse ettevalmistamine tööks

Initsialiseerimiseks kirjutatakse esimesele (õigemini nullile) leheküljele päis versiooniga 1.
Pärast seda kirjutatakse sellele lehele esialgne kontekst (sisaldab masina UUID-d ja vaikesätteid).

See on kõik, välkmälu on kasutamiseks valmis.

Masina laadimine

Laadimisel loetakse iga lehe (päis + CRC) esimesed 8 baiti, tundmatu võlunumbriga või vale CRC-ga lehti ignoreeritakse.
“Õigetelt” lehekülgedelt valitakse välja maksimaalse versiooniga lehed, millest võetakse suurima numbriga leht.
Loetakse esimene kirje, kontrollitakse CRC õigsust ja “konteksti” lipu olemasolu. Kui kõik on korras, peetakse seda lehte ajakohaseks. Kui ei, siis naaseme eelmisele, kuni leiame "reaalajas" lehe.
ja leitud lehelt loeme kõik kirjed, need, mida kasutame “konteksti” lipuga.
Salvestage zlib-sõnastik (seda on vaja sellele lehele lisamiseks).

See on kõik, allalaadimine on lõppenud, kontekst on taastatud, saate töötada.

Päevikukirje lisamine

Tihendame kirje õige sõnastikuga, määrates Z_SYNC_FLUSH. Vaatame, kas tihendatud kirje mahub praegusele lehele.
Kui see ei sobi (või lehel oli CRC-vigu), alustage uut lehte (vt allpool).
Kirjutame rekordi ja CRC üles. Kui ilmneb tõrge, avage uus leht.

Uus leht

Valime minimaalse arvuga tasuta lehe (tasuta leheks loeme lehte, mille päises on vale kontrollsumma või mille versioon on praegusest väiksem). Kui selliseid lehti pole, valige minimaalse arvuga leht nende hulgast, mille versioon on võrdne praegusega.
Kustutame valitud lehe. Kontrollime sisu 0xff-ga. Kui midagi on valesti, võtke järgmine tasuta leht jne.
Kirjutame kustutatud lehele päise, esimene kirje on konteksti hetkeseisund, järgmine on kirjutamata logikirje (kui see on olemas).

Vormi rakendatavus

Minu arvates osutus see heaks vorminguks igasuguste enam-vähem tihendatavate infovoogude (lihttekst, JSON, MessagePack, CBOR, võimalik, et protobuf) salvestamiseks NOR Flashis.

Muidugi on vorming kohandatud SLC NOR Flashi jaoks.

Seda ei tohiks kasutada kõrge BER-i kandjatega, nagu NAND või MLC NOR (kas sellist mälu on isegi müügil? Olen näinud seda mainimist ainult paranduskoodide töödes).

Lisaks ei tohiks seda kasutada seadmetega, millel on oma FTL: USB-välklamp, SD, MicroSD jne (sellise mälu jaoks lõin vormingu, mille lehe suurus on 512 baiti, allkiri iga lehe alguses ja kordumatud kirjenumbrid - mõnikord oli võimalik kõik andmed "tõrkunud" mälupulgalt lihtsa järjestikulise lugemisega taastada).

Sõltuvalt ülesannetest saab vormingut ilma muudatusteta kasutada välkmälupulkadel vahemikus 128Kbit (16Kb) kuni 1Gbit (128MB). Soovi korral saab seda kasutada ka suuremate kiipide peal, kuid ilmselt tuleb lehe suurust kohandada (Kuid siin kerkib juba küsimus majandusliku teostatavuse kohta; suuremahulise NOR Flashi hind ei ole julgustav).

Kui kellelegi tundub formaat huvitav ja soovib seda avatud projektis kasutada, siis kirjutage, proovin leida aja, lihvin koodi ja postitan githubisse.

Järeldus

Nagu näete, osutus formaat lõpuks lihtsaks ja isegi igav.

Minu vaatenurga arengut on raske artiklis kajastada, kuid uskuge mind: algselt tahtsin luua midagi keerukat, hävimatut, mis suudaks üle elada isegi tuumaplahvatuse vahetus läheduses. Mõistus (ma loodan) siiski võitis ja tasapisi nihkusid prioriteedid lihtsuse ja kompaktsuse poole.

Kas võib olla, et ma eksisin? Jah muidugi. Näiteks võib selguda, et ostsime partii madala kvaliteediga mikroskeeme. Või muul põhjusel ei vasta seadmed töökindluse ootustele.

Kas mul on selleks plaan? Arvan, et pärast artikli lugemist pole teil kahtlustki, et plaan on olemas. Ja isegi mitte üksi.

Veidi tõsisemalt öeldes töötati formaat välja nii töövariandina kui ka “prooviõhupallina”.

Praegu töötab kõik laual hästi, sõna otseses mõttes teisel päeval võetakse lahendus kasutusele (umbes) sajas seadmes, vaatame, mis juhtub "võitluses" (õnneks loodan, et formaat võimaldab teil rikkeid usaldusväärselt tuvastada; nii saate koguda täielikku statistikat). Mõne kuu pärast on võimalik järeldusi teha (ja kui teil pole õnne, isegi varem).

Kui kasutustulemuste põhjal avastatakse tõsiseid probleeme ja on vaja parandusi, siis kirjutan sellest kindlasti.

Kirjandus

Ma ei tahtnud pikka tüütut kasutatud teoste nimekirja koostada; Google on ju kõigil olemas.

Siia otsustasin jätta nimekirja leidudest, mis mulle eriti huvitavad tundusid, kuid järk-järgult rändasid need otse artikli teksti ja üks punkt jäi nimekirja:

  1. Utiliit infgen autorilt zlib. Suudab selgelt kuvada deflate/zlib/gzip arhiivide sisu. Kui peate tegelema deflate (või gzip) vormingu sisemise struktuuriga, soovitan seda väga.

Allikas: www.habr.com

Lisa kommentaar