Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash

Virgeschicht

Et gi Automaten vun eisem eegenen Design. Bannen am Raspberry Pi an e puer Kabelen op engem getrennten Board. E Mënzacceptor, e Rechnungsacceptor, e Bankterminal sinn ugeschloss ... Alles gëtt vun engem selbstgeschriwwene Programm kontrolléiert. Déi ganz Aarbechtsgeschicht gëtt op e Log op engem Flash Drive (MicroSD) geschriwwe, deen dann iwwer den Internet (mat engem USB Modem) op de Server iwwerdroe gëtt, wou se an enger Datebank gespäichert gëtt. Verkafsinformatioun gëtt an 1c gelueden, et gëtt och eng einfach Webinterface fir Iwwerwaachung, etc.

Dat ass, de Journal ass vital - fir Comptablesmethod (Recetten, Ofsaz, etc.), Iwwerwachung (all Zorte vu Feeler an aner Force Majeure Ëmstänn); Dëst, kann ee soen, ass all d'Informatiounen déi mir iwwer dës Maschinn hunn.

Problem

Flash-Laufwerke weisen sech als ganz onzouverlässeg Geräter. Si falen mat beneideger Regularitéit. Dëst féiert souwuel zu Maschinnausbréch an (wann aus irgendege Grënn de Log net online konnt transferéiert ginn) zu Datenverloscht.

Dëst ass net déi éischt Erfarung fir Flash Drive ze benotzen, virdru gouf et e weidere Projet mat méi wéi honnert Apparater, wou de Magazin op USB Flash Drive gespäichert gouf, et waren och Probleemer mat Zouverlässegkeet, heiansdo d'Zuel vun deenen, déi gescheitert sinn. engem Mount war an der Dosende. Mir hu verschidde Flash-Laufwerke probéiert, dorënner Marken mat SLC-Erënnerung, an e puer Modeller si méi zouverlässeg wéi anerer, awer d'Ersatz vun Flash-Laufwerke huet de Problem net radikal geléist.

Opgepasst weg! Longread! Wann Dir net un "firwat" interesséiert sidd, awer nëmmen un "wéi", kënnt Dir direkt goen Schlussendlech Artikelen.

Decisioun

Déi éischt Saach, déi am Kapp kënnt ass: opginn MicroSD, installéieren, zum Beispill, eng SSD, a booten aus. Theoretesch méiglech, wahrscheinlech, awer relativ deier, an net sou zouverlässeg (en USB-SATA Adapter gëtt bäigefüügt; Feelerstatistike fir Budget SSDs sinn och net encouragéierend).

USB HDD gesäit och net aus wéi eng besonnesch attraktiv Léisung.

Dofir si mir op dës Optioun komm: loosst de Boot vun MicroSD, awer benotzt se am Read-only Modus, a späichert den Operatiounsprotokoll (an aner Informatioun eenzegaarteg fir e bestëmmten Hardware - Seriennummer, Sensorkalibratiounen, etc.) soss anzwousch anescht. .

D'Thema vu liesbare FS fir Hambieren ass scho bannen a bausse studéiert, ech wäert net iwwer d'Implementatiounsdetailer an dësem Artikel wunnen (awer wann et Interessi ass, schreiwen ech vläicht e Mini-Artikel iwwer dëst Thema). Deen eenzege Punkt, deen ech bemierken wëll, ass datt souwuel aus perséinlecher Erfahrung wéi och vu Rezensiounen vun deenen, déi et schonn ëmgesat hunn, e Gewënn an Zouverlässegkeet gëtt. Jo, et ass onméiglech komplett vun Decompte lass ze ginn, awer däitlech reduzéieren hir Frequenz ass ganz méiglech. An d'Kaarte ginn vereenegt, wat Ersatz vill méi einfach mécht fir Servicepersonal.

Hardware

Et war keen speziellen Zweiwel iwwert d'Wiel vun Erënnerung Typ - NOR Flash.
Argumenter:

  • einfach Verbindung (meeschtens de SPI Bus, deen Dir schonn Erfahrung hutt, also keng Hardwareproblemer virgesinn);
  • lächerlech Präis;
  • Standard Betribsprotokoll (d'Ëmsetzung ass schonn am Linux Kernel, wann Dir wëllt, kënnt Dir eng Drëtt Partei huelen, déi och präsent ass, oder souguer Är eege schreiwen, glécklecherweis ass alles einfach);
  • Zouverlässegkeet a Ressource:
    aus engem typeschen Dateblat: Daten gi fir 20 Joer gespäichert, 100000 Läschzyklen fir all Block;
    vun Drëttubidder Quellen: extrem niddereg BER, postuléiert kee Besoin fir Fehlerkorrekturcoden (e puer Wierker betruechten ECC fir NOR, awer normalerweis bedeiten se ëmmer nach MLC NOR; dëst geschitt och).

Loosst eis d'Ufuerderunge fir Volumen a Ressource schätzen.

Ech hätt gär datt d'Donnéeën garantéiert gi fir e puer Deeg gespäichert ze ginn. Dëst ass néideg fir datt am Fall vun Kommunikatiounsproblemer d'Verkafsgeschicht net verluer geet. Mir konzentréieren eis op 5 Deeg, während dëser Period (och wann een de Weekend a Feierdeeg berücksichtegt) de Problem kann geléist ginn.

Mir sammelen de Moment ongeféier 100kb Logbicher pro Dag (3-4 dausend Entréen), awer lues a lues wiisst dës Figur - den Detail geet erop, nei Eventer ginn derbäi. Plus, heiansdo ginn et Bursts (e puer Sensor fänkt mat falschen Positiven un, zum Beispill). Mir berechnen fir 10 dausend records 100 Bytes all - Megabytes pro Dag.

Am Ganzen kommen 5MB propper (gutt kompriméiert) Daten eraus. Méi hinnen (grofe Schätzung) 1 MB Servicedaten.

Dat ass, mir brauchen en 8MB Chip wa mir keng Kompressioun benotzen, oder 4MB wa mir et benotzen. Ganz realistesch Zuelen fir dës Zort Erënnerung.

Wat d'Ressource ugeet: wa mir plangen datt de ganze Gedächtnis net méi wéi eemol all 5 Deeg nei geschriwwe gëtt, da kréie mir iwwer 10 Joer Service manner wéi dausend Rewrite-Zyklen.
Loosst mech Iech drun erënneren datt den Hiersteller honnertdausend versprécht.

E bëssen iwwer NOR vs NAND

Haut ass natierlech d'NAND-Erënnerung vill méi populär, awer ech géif et net fir dëse Projet benotzen: NAND, am Géigesaz zu NOR, erfuerdert onbedéngt d'Benotzung vu Feelerkorrekturcoden, en Dësch vu schlechte Blocken, etc., an och d'Been vun NAND Chips normalerweis vill méi.

D'Nodeeler vum NOR enthalen:

  • klenge Volumen (an deementspriechend héije Präis pro Megabyte);
  • niddereg Kommunikatioun Vitesse (haaptsächlech wéinst der Tatsaach, datt eng Serien Interface benotzt gëtt, normalerweis SPI oder I2C);
  • lues ze läschen (ofhängeg vun der Blockgréisst, et dauert vun enger Fraktioun vun enger Sekonn bis e puer Sekonnen).

Et schéngt, datt et näischt kritesch fir eis ass, also mir weider.

Wann d'Detailer interessant sinn, ass de Mikrocircuit ausgewielt op 25df321a (awer dat ass onwichteg, et gi vill Analoga um Maart déi kompatibel sinn a Pinout a Kommandosystem; och wa mir e Mikrokrees vun engem aneren Hiersteller an/oder enger anerer Gréisst installéiere wëllen, funktionnéiert alles ouni d'Ännerung ze änneren Code).

Ech benotzen de Chauffer, deen an de Linux Kernel gebaut ass; op Raspberry, dank der Ënnerstëtzung vum Apparatbaum-Overlay, ass alles ganz einfach - Dir musst de kompiléierten Overlay an /boot/overlays setzen a liicht änneren /boot/config.txt.

Beispill dts Datei

Fir éierlech ze sinn, sinn ech net sécher datt et ouni Feeler geschriwwe gëtt, awer et funktionnéiert.

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

An eng aner Linn am config.txt

dtoverlay=at25:spimaxfrequency=50000000

Ech wäert d'Beschreiwung vun der Verbindung vum Chip op de Raspberry Pi ausgoen. Engersäits sinn ech keen Expert an der Elektronik, op der anerer Säit ass alles hei banal och fir mech: de Mikrokrees huet nëmmen 8 Been, vun deenen mir Buedem, Kraaft, SPI (CS, SI, SO, SCK brauchen) ); d'Niveaue sinn d'selwecht wéi déi vum Raspberry Pi, keng zousätzlech Drot ass erfuerderlech - verbënnt just déi uginn 6 Pins.

Problemerklärung

Wéi gewinnt geet d'Problem Ausso duerch e puer Iteratiounen, an et schéngt mir datt et Zäit ass fir déi nächst. Also loosst eis ophalen, zesummesetzen wat scho geschriwwe gouf, a klären d'Detailer déi am Schied bleiwen.

Also hu mir decidéiert datt de Log am SPI NOR Flash gespäichert gëtt.

Wat ass NOR Flash fir déi déi et net wëssen?

Dëst ass net-flüchteg Erënnerung mat deem Dir dräi Operatioune maache kënnt:

  1. Liesen:
    Déi heefegst Liesung: Mir iwwerdroen d'Adress a liesen esou vill Bytes wéi mir brauchen;
  2. Opname:
    Schreiwen op NOR Flash gesäit wéi eng regulär eent, mä et huet eng Besonderheet: Dir kënnt nëmmen änneren 1 ze 0, awer net Vize versa. Zum Beispill, wa mir 0x55 an enger Erënnerungszell haten, dann nodeems Dir 0x0f geschriwwen hutt, gëtt 0x05 schonn do gespäichert (kuckt Tabell just hei ënnen);
  3. Läschen:
    Natierlech musse mir fäeg sinn déi entgéintgesate Operatioun ze maachen - 0 op 1 änneren, dat ass genee fir wat d'Läschoperatioun ass. Am Géigesaz zu den éischten zwee funktionnéiert et net mat Bytes, mee mat Blocken (de Minimum Eraseblock am gewielten Chip ass 4kb). Erase zerstéiert de ganze Block an ass deen eenzege Wee fir 0 op 1 z'änneren. Dofir, wann Dir mat Flash Memory schafft, musst Dir dacks Datenstrukturen un d'Erase Block Grenz ausriichten.
    Opname am NOR Flash:

Binär Daten

Et wor
01010101

Opgeholl
00001111

Ass gin
00000101

De Log selwer stellt eng Sequenz vun records vun variabelen Längt duer. Déi typesch Längt vun engem Rekord ass ongeféier 30 Bytes (obwuel records déi e puer Kilobytes laang sinn heiansdo optrieden). An dësem Fall schaffe mir mat hinnen einfach als Set vu Bytes, awer wann Dir interesséiert sidd, gëtt CBOR an de Rekorder benotzt

Zousätzlech zum Logbuch musse mir e puer "Astellungs" Informatioun späicheren, souwuel aktualiséiert an net: eng gewëssen Apparat ID, Sensorkalibratiounen, e "Apparat ass temporär behënnert" Fändel, etc.
Dës Informatioun ass eng Rei vu Schlësselwäert records, och am CBOR gespäichert. Mir hunn net vill vun dëser Informatioun (maximal e puer Kilobytes), an se gëtt selten aktualiséiert.
An deem nächste wäerte mir et Kontext nennen.

Wa mir eis erënneren wou dësen Artikel ugefaang huet, ass et ganz wichteg fir zouverlässeg Datelagerung an, wa méiglech, kontinuéierlech Operatioun och am Fall vun Hardwarefehler / Datekorruptioun ze garantéieren.

Wéi eng Quelle vu Probleemer kënne berücksichtegt ginn?

  • Ausschalten wärend Schreiwen / Läschen Operatiounen. Dëst ass aus der Kategorie "et gëtt keen Trick géint Crowbar."
    Informatiounen aus Diskussiounen um Stackexchange: wann d'Kraaft ausgeschalt gëtt wärend Dir mam Flash schafft, souwuel d'Läschen (op 1 gesat) a Schreiwen (op 0 gesat) féieren zu ondefinéiert Verhalen: Daten kënne geschriwwe ginn, deelweis geschriwwe ginn (soen, mir hunn 10 Bytes / 80 Bits transferéiert , awer nach net nëmme 45 Bits kënne geschriwwe ginn), et ass och méiglech datt e puer vun de Bits an engem "Tëschestand" sinn (Liesen kann souwuel 0 wéi 1 produzéieren);
  • Feeler am Flash Erënnerung selwer.
    BER, obwuel ganz niddereg, kann net gläich Null sinn;
  • Bus Feeler
    Daten iwwer SPI iwwerdroen sinn op kee Fall geschützt; souwuel eenzel Bitfehler wéi och Synchroniséierungsfehler kënnen optrieden - Verloscht oder Aféierung vu Bits (wat zu massiver Dateverzerrung féiert);
  • Aner Feeler / Glitches
    Feeler am Code, Raspberry Glitches, Alien Interferenz ...

Ech hunn d'Ufuerderunge formuléiert, d'Erfëllung vun deenen, menger Meenung no, néideg ass fir Zouverlässegkeet ze garantéieren:

  • Opzeechnunge mussen direkt an d'Flash Memory ginn, verspéiten Schreiwe ginn net berücksichtegt; - wann e Feeler geschitt, muss et sou fréi wéi méiglech erkannt a veraarbecht ginn; - de System muss, wa méiglech, vu Feeler erholen.
    (e Beispill aus dem Liewen "wéi et sollt net sinn", wat ech mengen datt jiddereen begéint ass: no engem Nout-Reboot ass de Dateiesystem "gebrach" an de Betribssystem boott net)

Iddien, Approchen, Reflexiounen

Wéi ech ugefaang hunn un dëse Problem ze denken, sinn vill Iddien duerch mäi Kapp geblitzt, zum Beispill:

  • benotzen Datekompressioun;
  • benotzen clever Daten Strukturen, Zum Beispill, späicheren Rekord Header getrennt vun de records selwer, sou datt wann et e Feeler an all Rekord ass, kënnt Dir de Rescht ouni Problemer liesen;
  • benotzt Bitfelder fir d'Ofschloss vun der Opnam ze kontrolléieren wann d'Kraaft ausgeschalt ass;
  • Buttek Checksumme fir alles;
  • benotzen eng Zort Kaméidi-resistent géint coding.

E puer vun dësen Iddien goufen benotzt, anerer goufen decidéiert opginn ze ginn. Loosst eis an Uerdnung goen.

Datekompressioun

D'Evenementer selwer, déi mir am Journal notéieren, sinn zimlech ähnlech a widderhuelend ("eng 5 Rubel Mënz gehäit", "de Knäppchen gedréckt fir Ännerung ze ginn", ...). Dofir sollt d'Kompressioun zimlech effektiv sinn.

D'Kompressiounsoverhead ass net bedeitend (eise Prozessor ass zimmlech mächteg, och den éischte Pi hat e Kär mat enger Frequenz vu 700 MHz, aktuell Modeller hunn e puer Käre mat enger Frequenz vu méi wéi engem Gigahertz), den Austausch Taux mat der Späichere ass niddereg (e puer Megabytes pro Sekonn), ass d'Gréisst vun de Rekorder kleng. Am Allgemengen, wann d'Kompressioun en Impakt op d'Performance huet, wäert et nëmme positiv sinn. (absolut onkritesch, just feststellen). Plus, mir hu keng richteg embedded, awer regelméisseg Linux - sou datt d'Ëmsetzung net vill Effort erfuerdert (et ass genuch just d'Bibliothéik ze verbannen a verschidde Funktiounen dovun ze benotzen).

E Stéck vum Logbuch gouf vun engem funktionnéierenden Apparat (1.7 MB, 70 Tausend Entréen) geholl an als éischt iwwerpréift fir Kompressibilitéit mat gzip, lz4, lzop, bzip2, xz, zstd verfügbar um Computer.

  • gzip, xz, zstd hunn ähnlech Resultater gewisen (40Kb).
    Ech war iwwerrascht, datt de fashionable xz sech hei um Niveau vun gzip oder zstd gewisen huet;
  • lzip mat Standardastellungen huet e bësse méi schlecht Resultater ginn;
  • lz4 an lzop weisen net ganz gutt Resultater (150Kb);
  • bzip2 huet en iwwerraschend gutt Resultat gewisen (18Kb).

Also, d'Donnéeën sinn ganz gutt kompriméiert.
Also (wa mir net fatale Mängel fannen) gëtt et Kompressioun! Einfach well méi Daten op dee selwechte Flash Drive passen.

Loosst eis iwwer d'Nodeeler denken.

Éischte Problem: Mir hunn eis schonn eens ginn, datt all Rekord direkt muss op Flash goen. Typesch sammelt den Archiver Daten aus dem Input Stream bis en decidéiert datt et Zäit ass fir de Weekend ze schreiwen. Mir mussen direkt e kompriméierte Block vun Daten kréien an et an net-flüchtlech Erënnerung späicheren.

Ech gesinn dräi Weeër:

  1. Kompriméiert all Rekord mat Wierderbuchkompressioun amplaz vun den uewe diskutéierten Algorithmen.
    Et ass eng komplett funktionéierend Optioun, awer ech hunn et net gär. Fir e méi oder manner uerdentleche Kompressiounsniveau ze garantéieren, muss d'Wörterbuch op spezifesch Donnéeën "geschnidde" sinn; all Ännerung féiert dozou datt de Kompressiounsniveau katastrophal fällt. Jo, de Problem kann geléist ginn andeems Dir eng nei Versioun vum Wierderbuch erstallt, awer dëst ass e Kappwéi - mir mussen all Versioune vum Wierderbuch späicheren; an all Entrée musse mir uginn mat wéi enger Versioun vum Wierderbuch et kompriméiert gouf ...
  2. Kompriméiert all Rekord mat "klassesche" Algorithmen, awer onofhängeg vun deenen aneren.
    D'Kompressiounsalgorithmen déi berécksiichtegt sinn net entwéckelt fir mat Opzeechnunge vun dëser Gréisst (Zénger vu Bytes) ze schaffen, de Kompressiounsverhältnis wäert kloer manner wéi 1 sinn (dat heescht d'Erhéijung vum Datevolumen amplaz vun der Kompressioun);
  3. Maacht FLUSH no all Opnam.
    Vill Kompressiounsbibliothéiken hunn Ënnerstëtzung fir FLUSH. Dëst ass e Kommando (oder e Parameter fir d'Kompressiounsprozedur), beim Empfang deen den Archiver e kompriméierte Stroum formt fir datt et ka benotzt ginn fir ze restauréieren all dat onkompriméiert Donnéeën déi scho kritt goufen. Esou en Analog sync an Dateiesystemer oder commit op sql.
    Wat wichteg ass, ass datt spéider Kompressiounsoperatioune fäeg sinn dat akkumuléiert Wierderbuch ze benotzen an de Kompressiounsverhältnis wäert net sou vill leiden wéi an der viregter Versioun.

Ech mengen et ass evident datt ech déi drëtt Optioun gewielt hunn, loosst eis et méi detailléiert kucken.

fonnt super Artikel iwwer FLUSH an zlib.

Ech hunn e Knéi-Test baséiert op dem Artikel gemaach, 70 Tausend Log-Entréen aus engem richtegen Apparat geholl, mat enger Säitgréisst vun 60Kb (mir kommen méi spéit op d'Säitgréisst zréck) kritt:

Roude sinn
Kompressioun gzip -9 (kee FLUSH)
zlib mat Z_PARTIAL_FLUSH
zlib mat Z_SYNC_FLUSH

Volumen, KB
1692
40
352
604

Op den éischte Bléck ass de Präis vum FLUSH exzessiv héich, awer a Wierklechkeet hu mir wéineg Wiel - entweder guer net ze kompriméieren oder ze kompriméieren (a ganz effektiv) mat FLUSH. Mir däerfen net vergiessen datt mir 70 Tausend records hunn, d'Redundanz agefouert vun Z_PARTIAL_FLUSH ass nëmmen 4-5 Bytes pro Rekord. An de Kompressiounsverhältnis ass bal 5: 1 erausgestallt, wat méi wéi en exzellent Resultat ass.

Et kann als Iwwerraschung kommen, awer Z_SYNC_FLUSH ass tatsächlech e méi effiziente Wee fir FLUSH ze maachen

Wann Dir Z_SYNC_FLUSH benotzt, sinn déi lescht 4 Bytes vun all Entrée ëmmer 0x00, 0x00, 0xff, 0xff. A wa mir se kennen, da musse mir se net späicheren, sou datt d'endgülteg Gréisst nëmmen 324Kb ass.

Den Artikel deen ech verlinkt hunn huet eng Erklärung:

En neien Typ 0 Block mat eidelen Inhalt gëtt ugeschloss.

En Typ 0 Block mat eidelen Inhalter besteet aus:

  • den Dräi-Bit Block Header;
  • 0 bis 7 Bits gläich Null, fir Byte Ausrichtung z'erreechen;
  • déi véier-Byte Sequenz 00 00 FF FF.

Wéi Dir einfach gesitt, sinn am leschte Block virun dësen 4 Bytes vun 3 bis 10 Nullbits. Wéi och ëmmer, d'Praxis huet gewisen datt et tatsächlech op d'mannst 10 Nullbits sinn.

Et stellt sech eraus datt sou kuerz Datenblocken normalerweis (ëmmer?) mat engem Block vum Typ 1 (fixe Block) kodéiert sinn, deen onbedéngt mat 7 Nullbits endet, wat insgesamt 10-17 garantéiert Nullbits gëtt (an de Rescht wäert Null sinn mat enger Wahrscheinlechkeet vu ronn 50%).

Also, op Testdaten, an 100% vun de Fäll gëtt et een Nullbyte virum 0x00, 0x00, 0xff, 0xff, a méi wéi engem Drëttel vun de Fäll sinn et zwee Nullbytes (vläicht ass de Fakt datt ech binär CBOR benotzen, a wann Dir Text JSON benotzt, blockéiert Typ 2 - dynamesch Block wiere méi heefeg, respektiv Blocken ouni zousätzlech Nullbytes virun 0x00, 0x00, 0xff, 0xff géife begéint ginn).

Am Ganzen, mat der verfügbaren Testdaten, ass et méiglech a manner wéi 250Kb kompriméiert Daten ze passen.

Dir kënnt e bësse méi spueren andeems Dir e bësse Jongléiere mécht: fir elo ignoréiere mir d'Präsenz vun e puer Nullbits um Enn vum Block, e puer Bits um Ufank vum Block änneren och net ...
Awer dunn hunn ech e staarke Wëllen Entscheedung getraff fir opzehalen, soss kéint ech mat dësem Taux en eegenen Archiver entwéckelen.

Am Ganzen, aus menger Testdaten, krut ech 3-4 Bytes pro Schreiwen, huet de Kompressiounsverhältnis méi wéi 6: 1 erausgestallt. Ech wäert éierlech sinn: Ech hunn esou e Resultat net erwaart; menger Meenung no ass alles besser wéi 2: 1 schonn e Resultat dat d'Benotzung vun der Kompressioun justifiéiert.

Alles ass gutt, awer zlib (deflate) ass nach ëmmer en archaeschen, verdéngten a liicht almoudeschen Kompressiounsalgorithmus. Déi blo Tatsaach, datt déi lescht 32Kb vum onkompriméierten Datestroum als Wierderbuch benotzt gëtt, gesäit haut komesch aus (dat ass, wann e puer Dateblock ganz ähnlech ass wéi wat am Input Stream virun 40Kb war, da fänkt et erëm un ze archivéieren, a wäert net op e virdrun Optriede bezéien). A fashionable modernen Archiver gëtt d'Wörterbuchgréisst dacks a Megabytes gemooss anstatt Kilobytes.

Also maache mir eis Mini-Etude vun den Archiver weider.

Als nächst hu mir bzip2 getest (erënnert, ouni FLUSH huet et e fantastesche Kompressiounsverhältnis vu bal 100:1 gewisen). Leider huet et mat FLUSH ganz schlecht geschafft; d'Gréisst vun de kompriméierten Donnéeën huet sech méi grouss gewisen wéi déi onkompriméiert Donnéeën.

Meng Viraussetzungen iwwer d'Grënn fir den Echec

Libbz2 bitt nëmmen eng Spulloptioun, déi schéngt d'Wierderbuch ze läschen (analog zu Z_FULL_FLUSH an zlib); et gëtt keng Rieds vun enger effektiver Kompressioun duerno.

An déi lescht getest gouf zstd. Ofhängeg vun den Parameteren kompriméiert se entweder um Niveau vum gzip, awer vill méi séier oder besser wéi gzip.

Och, mat FLUSH huet et net ganz gutt geschafft: d'Gréisst vun de kompriméierten Donnéeën war ongeféier 700Kb.

Я eng Fro gestallt op der Github Säit vum Projet hunn ech eng Äntwert kritt datt Dir op bis zu 10 Bytes Servicedaten fir all Block vu kompriméierten Donnéeën ziele sollt, wat no bei de kritt Resultater ass; et gëtt kee Wee fir d'Deflate z'erreechen.

Ech hu beschloss op dësem Punkt an meng Experimenter mat Archiver ze stoppen (loosst mech drun erënneren datt xz, lzip, lzo, lz4 sech net souguer an der Teststadium ouni FLUSH gewisen hunn, an ech hunn net méi exotesch Kompressiounsalgorithmen ugesinn).

Komme mer zréck op d'Archivproblemer.

Déi zweet (wéi se soen an Uerdnung, net am Wäert) Problem ass, datt déi kompriméiert Donnéeën eng eenzeg Baach ass, an deem et dauernd Referenze zu virdrun Rubriken. Also, wann eng Sektioun vu kompriméierten Donnéeën beschiedegt ass, verléiere mir net nëmmen den assoziéierten Block vun onkompriméierten Donnéeën, awer och all spéider.

Et gëtt eng Approche fir dëse Problem ze léisen:

  1. Verhënnert datt de Problem geschitt - füügt Redundanz un déi kompriméiert Donnéeën, wat Iech erlaabt Iech Feeler z'identifizéieren an ze korrigéieren; doriwwer schwätze mer spéider;
  2. Miniméiere Konsequenzen wann e Problem geschitt
    Mir hu scho virdru gesot datt Dir all Datenblock onofhängeg kompriméiere kënnt, an de Problem wäert vu sech selwer verschwannen (Schued un d'Donnéeën vun engem Block féiert zum Verloscht vun Daten nëmme fir dëse Block). Wéi och ëmmer, dëst ass en extremen Fall an deem Datekompressioun net effikass ass. De Géigendeel Extrem: benotzt all 4MB vun eisem Chip als eenzegen Archiv, wat eis eng exzellente Kompressioun gëtt, awer katastrophal Konsequenzen am Fall vun Datekorruptioun.
    Jo, e Kompromiss ass néideg a punkto Zouverlässegkeet. Awer mir mussen drun erënneren datt mir en Datelagerungsformat fir net flüchteg Erënnerung entwéckelen mat extrem nidderegen BER an enger deklaréierter Datespäicherzäit vun 20 Joer.

Wärend den Experimenter hunn ech entdeckt datt méi oder manner merkbare Verloschter am Kompressiounsniveau op Blocke vu kompriméierte Donnéeën manner wéi 10 KB an der Gréisst ufänken.
Et gouf virdru erwähnt datt d'Erënnerung déi benotzt gëtt paged ass; Ech gesinn kee Grond firwat d'Korrespondenz "eng Säit - ee Block vu kompriméierten Donnéeën" net sollt benotzt ginn.

Dat ass, déi minimal raisonnabel Säitgréisst ass 16Kb (mat enger Reserve fir Serviceinformatioun). Wéi och ëmmer, sou eng kleng Säitgréisst setzt bedeitend Restriktiounen op déi maximal Rekordgréisst.

Obwuel ech erwaarden nach net records méi grouss wéi e puer kilobytes an kompriméiert Form, Ech decidéiert 32Kb Säiten ze benotzen (fir am Ganzen 128 Säiten pro Chip).

Zesummefaassung:

  • Mir späicheren Daten kompriméiert mat zlib (deflate);
  • Fir all Entrée setzen mir Z_SYNC_FLUSH;
  • Fir all kompriméierte Rekord trimme mir déi hannendrunn Bytes (zB 0x00, 0x00, 0xff, 0xff); am Header weisen mir wéivill Bytes mir ofgeschnidden hunn;
  • Mir späicheren Daten op 32Kb Säiten; et gëtt en eenzege Stroum vu kompriméierten Donnéeën op der Säit; Op all Säit fänke mer erëm mat Kompressioun un.

An, ier ech mat der Kompressioun ofgeschloss hunn, wëll ech Iech op d'Tatsaach opmierksam maachen datt mir nëmmen e puer Bytes vu kompriméierten Donnéeën pro Rekord hunn, also ass et extrem wichteg d'Serviceinformatioun net opzepompelen, all Byte zielt hei.

Späicheren Daten Header

Well mir records vun variabelen Längt hunn, musse mir iergendwéi d'Placement / Grenze vun records bestëmmen.

Ech kennen dräi Approche:

  1. All Opzeechnunge ginn an engem kontinuéierleche Stroum gespäichert, als éischt gëtt et e Rekordheader mat der Längt, an dann de Rekord selwer.
    An dëser Ausféierung kënne béid Header an Daten vu variabelen Längt sinn.
    Wesentlech kréie mir eng eenzeg verlinkt Lëscht déi déi ganzen Zäit benotzt gëtt;
  2. Header an d'Opzeechnunge selwer ginn an getrennten Streamen gespäichert.
    Andeems Dir Header vu konstanter Längt benotzt, suerge mir fir datt Schued un engem Header net déi aner beaflosst.
    Eng ähnlech Approche gëtt zum Beispill a ville Dateiesystemer benotzt;
  3. D'Opzeechnunge ginn an engem kontinuéierleche Stroum gespäichert, d'Rekordgrenz gëtt vun engem bestëmmte Marker festgeluegt (e Charakter / Sequenz vun Zeechen, déi bannent Datenblocken verbueden ass). Wann et e Marker am Rekord ass, da ersetzen mir et mat enger Sequenz (entkommen).
    Eng ähnlech Approche gëtt zum Beispill am PPP-Protokoll benotzt.

Ech illustréieren.

Optioun 1:
Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash
Hei ass alles ganz einfach: wann Dir d'Längt vum Rekord kennt, kënne mir d'Adress vum nächste Header berechnen. Also réckelen mir duerch d'Rubriken bis mir e Gebitt begéinen mat 0xff (fräie Beräich) oder um Enn vun der Säit.

Optioun 2:
Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash
Wéinst der verännerlecher Rekordlängt kënne mir net am Viraus soen wéivill records (an dofir Header) mir pro Säit brauchen. Dir kënnt d'Header an d'Daten selwer iwwer verschidde Säiten verdeelen, awer ech léiwer eng aner Approche: mir setzen souwuel d'Header an d'Donnéeën op enger Säit, awer d'Header (vun konstanter Gréisst) kommen vum Ufank vun der Säit, an daten (vu variabel Längt) kënnt vum Enn. Soubal se "treffen" (et gëtt net genuch fräi Plaz fir en neien Entrée), mir betruechten dës Säit komplett.

Optioun 3:
Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash
Et ass net néideg d'Längt oder aner Informatioun iwwer d'Location vun den Donnéeën am Header ze späicheren; Marker, déi d'Grenze vun den Opzeechnungen uginn, si genuch. D'Donnéeë mussen awer beim Schreiwen/Liesen veraarbecht ginn.
Ech géif 0xff als Marker benotzen (deen d'Säit fëllt no der Läschung), sou datt de fräie Beräich definitiv net als Daten behandelt gëtt.

Vergläichstabell:

Option 1
Option 2
Option 3

Feeler Toleranz
-
+
+

Kompaktheet
+
-
+

Ëmsetzung Komplexitéit
*
**
**

Optioun 1 huet e fatale Feeler: wann ee vun den Header beschiedegt ass, gëtt déi ganz spéider Kette zerstéiert. Déi reschtlech Optiounen erlaben Iech e puer Daten och am Fall vu massive Schued ze recuperéieren.
Awer hei ass et ubruecht ze erënneren datt mir décidéiert hunn d'Donnéeën an enger kompriméierter Form ze späicheren, an dofir verléieren mir all d'Donnéeën op der Säit no engem "gebrach" Rekord, also och wann et e Minus an der Tabell ass, maache mir net huelen et Rechnung.

Kompaktheet:

  • an der éischter Optioun musse mir nëmmen d'Längt am Header späicheren; wa mir Variabel-Längt ganz Zuelen benotzen, da kënne mir an de meeschte Fäll mat engem Byte duerchgoen;
  • an der zweeter Optioun musse mir d'Startadress an d'Längt späicheren; de Rekord muss eng konstant Gréisst ginn, ech schätzen 4 Bytes pro Rekord (zwee Bytes fir d'Offset, an zwee Bytes fir d'Längt);
  • déi drëtt Optioun brauch nëmmen ee Charakter fir den Ufank vun der Opnahmen unzeginn, plus d'Opnahm selwer wäert eropgoen duerch 1-2% wéinst Schirmung. Am Allgemengen, ongeféier Paritéit mat der éischter Optioun.

Am Ufank hunn ech déi zweet Optioun als Haaptgrond ugesinn (a souguer d'Ëmsetzung geschriwwen). Ech hunn et nëmmen opginn wann ech endlech decidéiert hunn Kompressioun ze benotzen.

Vläicht enges Daags wäert ech nach eng ähnlech Optioun benotzen. Zum Beispill, wann ech mat Datelagerung fir e Schëff tëscht der Äerd a Mars ze këmmeren muss, ginn et komplett aner Ufuerderunge fir Zouverlässegkeet, kosmesch Stralung, ...

Wat d'drëtt Optioun ugeet: Ech hunn et zwee Stäre ginn fir d'Schwieregkeet vun der Ëmsetzung einfach well ech net gär mat Schirm ze messen, d'Längt am Prozess änneren, etc. Jo, vläicht sinn ech partiell, awer ech muss de Code schreiwen - firwat zwéngt Iech eppes ze maachen wat Dir net gär hutt.

Zesummefaassung: Mir wielen d'Späicheroptioun a Form vu Ketten "Header mat Längt - Daten vu variabelen Längt" wéinst Effizienz an der Einfachheet vun der Ëmsetzung.

Bit Felder benotze fir den Erfolleg vu Schreifoperatiounen ze iwwerwaachen

Ech erënnere mech elo net wou ech d'Iddi krut, awer et gesäit sou eppes aus:
Fir all Entrée verdeele mir e puer Bits fir Fändelen ze späicheren.
Wéi mir virdru gesot hunn, no der Läsch sinn all Bits mat 1s gefëllt, a mir kënnen 1 op 0 änneren, awer net ëmgedréint. Also fir "de Fändel ass net gesat" benotze mir 1, fir "de Fändel ass gesat" benotze mir 0.

Hei ass wéi e Rekord vun variabelen Längt an de Flash setzen kéint ausgesinn:

  1. Set de Fändel "Längt Opnahmen huet ugefaangen";
  2. Rekord d'Längt;
  3. Setzt de Fändel "Datenopnam huet ugefaang";
  4. Mir Rekord Daten;
  5. Setzt de Fändel "Opnam eriwwer".

Zousätzlech wäerte mir e "Feeler geschitt" Fändel hunn, fir am Ganzen 4 Bit Fändelen.

An dësem Fall hu mir zwee stabil Staaten "1111" - Opnam huet net ugefaangen an "1000" - Opnahmen war erfollegräich; am Fall vun enger onerwaarter Ënnerbriechung vum Opnamprozess kréie mir Tëschestänn, déi mir dann erkennen a veraarbecht.

D'Approche ass interessant, awer et schützt nëmme vu plötzlechen Stroumausfall an ähnlechen Ausfäll, wat natierlech wichteg ass, awer dëst ass wäit vum eenzegen (oder souguer den Haapt) Grond fir méiglech Feeler.

Zesummefaassung: Loosst eis weidergoen op der Sich no enger gudder Léisung.

Checksummen

Checksums maachen et och méiglech sécher ze maachen (mat raisonnabel Wahrscheinlechkeet) datt mir genee liesen wat geschriwwe ginn hätt. An, am Géigesaz zu de Bitfelder hei uewen diskutéiert, funktionnéieren se ëmmer.

Wa mir d'Lëscht vu potenziellen Quelle vu Probleemer betruechten, déi mir uewe diskutéiert hunn, ass d'Kontrollsum fäeg e Feeler ze erkennen onofhängeg vu senger Hierkonft (ausser, vläicht, fir béiswëlleg Auslänner - si kënnen och d'Kontrollsum ausfalen).

Also wann eis Zil ass et z'iwwerpréiwen datt d'Donnéeën intakt sinn, Checksumme sinn eng super Iddi.

D'Wiel vum Algorithmus fir d'Berechnung vum Checksum huet keng Froen opgeworf - CRC. Engersäits, mathematesch Eegeschafte maachen et méiglech verschidden Zorte vu Feeler 100% ze fänken; op der anerer Säit, op zoufälleg Donnéeën dësen Algorithmus weist normalerweis d'Wahrscheinlechkeet vun Kollisiounen net vill méi grouss wéi déi theoretesch Limite Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash. Et ass vläicht net de schnellsten Algorithmus, an et ass och net ëmmer de Minimum wat d'Zuel vun de Kollisiounen ugeet, awer et huet eng ganz wichteg Qualitéit: an den Tester, déi ech begéint hunn, gouf et keng Muster an deenen et kloer gescheitert ass. Stabilitéit ass d'Haaptqualitéit an dësem Fall.

Beispill vun enger volumetrescher Studie: Deel vun 1, Deel vun 2 (Linken op narod.ru, sorry).

Wéi och ëmmer, d'Aufgab fir e Checksum ze wielen ass net komplett; CRC ass eng ganz Famill vu Checksummen. Dir musst iwwer d'Längt entscheeden, a wielt dann e Polynom.

D'Auswiel vun der Checksum Längt ass net sou einfach eng Fro wéi et op den éischte Bléck schéngt.

Loosst mech illustréieren:
Loosst eis d'Wahrscheinlechkeet vun engem Feeler an all Byte hunn Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash an eng ideal Checksum, loosst eis d'Duerchschnëttszuel vu Feeler pro Millioun records berechnen:

Daten, Byte
Checksum, Byte
Ondetektéiert Feeler
Falsch Feeler Detektioun
Total falsch Positiver

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

Et géif schéngen datt alles einfach ass - ofhängeg vun der Längt vun den Donnéeën, déi geschützt sinn, wielt d'Längt vum Checksum mat engem Minimum vu falschen Positiven - an den Trick ass an der Täsch.

Wéi och ëmmer, e Problem entsteet mat kuerze Kontrollsummen: obwuel si gutt sinn fir eenzel Bitfehler z'entdecken, kënne se mat enger zimlech héicher Wahrscheinlechkeet komplett zoufälleg Daten als korrekt akzeptéieren. Et gouf schonn en Artikel op Habré beschriwwen Problem am richtege Liewen.

Dofir, fir e zoufälleg Checksum Match bal onméiglech ze maachen, musst Dir Kontrollsumme benotzen déi 32 Bits oder méi laang sinn. (fir Längt méi wéi 64 Bits gi kryptografesch Hashfunktiounen normalerweis benotzt).

Trotz der Tatsaach, datt ech virdru geschriwwen hunn, datt mir mat alle Mëttele musse Plaz spueren, wäerte mir nach ëmmer en 32-Bit Checksum benotzen (16 Bits sinn net genuch, d'Wahrscheinlechkeet vun enger Kollisioun ass méi wéi 0.01%; an 24 Bits, well se soen, si weder hei nach do).

Hei kann en Opschwong kommen: hu mir all Byte bei der Auswiel vun der Kompressioun gespäichert fir elo 4 Bytes gläichzäiteg ze ginn? Wär et net besser net ze kompriméieren oder e Checksum derbäizesetzen? Natierlech net, keng Kompressioun heescht net, datt mir keng Integritéitskontrolle brauchen.

Wann Dir e Polynom auswielt, wäerte mir d'Rad net nei erfannen, awer den elo populäre CRC-32C huelen.
Dëse Code detektéiert 6 Bit Feeler op Pakete bis zu 22 Bytes (vläicht den allgemengste Fall fir eis), 4 Bit Feeler op Pakete bis zu 655 Bytes (och e gemeinsame Fall fir eis), 2 oder all komesch Unzuel vu Bitfehler op Paketen vun all raisonnabel Längt.

Wann een un den Detailer interesséiert ass

Wikipedia Artikel iwwer CRC.

Code Parameteren crc-32c op Koopman Websäit - vläicht de féierende CRC Spezialist um Planéit.

В säin Artikel ass aner interessant Code, déi e bësse besser Parameteren fir de Pak Längt gëtt, datt fir eis relevant sinn, mee ech hunn den Ënnerscheed net bedeitendst betruecht, an ech war kompetent genuch Mooss Code amplaz vun der Norm a gutt recherchéiert ze wielen.

Och, well eis Donnéeën kompriméiert sinn, stellt sech d'Fro: Solle mir d'Kontrollsum vu kompriméierten oder onkompriméierten Donnéeën berechnen?

Argumenter fir d'Berechnung vun der Checksum vun onkompriméierten Donnéeën:

  • Mir mussen schlussendlech d'Sécherheet vun der Datelagerung iwwerpréiwen - also iwwerpréift mir et direkt (gläichzäiteg, méiglech Fehler an der Ëmsetzung vun der Kompressioun / Dekompressioun, Schued verursaacht duerch gebrach Erënnerung, etc.)
  • Den Deflat Algorithmus an zlib huet eng zimlech reife Implementatioun an sollt net falen mat "kromme" Inputdaten; Ausserdeem ass et dacks fäeg Feeler am Input Stream onofhängeg z'entdecken, d'Gesamtwahrscheinlechkeet ze reduzéieren fir e Feeler z'entdecken (en Test gemaach mat engem Invertéiere vun engem eenzege Bit an engem Kuerzrekord, zlib huet e Feeler entdeckt an ongeféier engem Drëttel vun de Fäll).

Argumenter géint d'Berechnung vun der Kontrollsumme vun onkompriméierten Donnéeën:

  • CRC ass speziell "opgepasst" fir déi puer Bitfehler, déi charakteristesch fir Flash Memory sinn (e Bitfehler an engem kompriméierte Stroum kann e massive Changement am Ausgangsstroum verursaachen, op deem mir reng theoretesch eng Kollisioun "fänken" kënnen);
  • Ech hu wierklech net gär d'Iddi fir potenziell futtis Daten un den Dekomprimerer weiderzeginn, Wie weesswéi hie wäert reagéieren.

An dësem Projet hunn ech décidéiert vun der allgemeng akzeptéierter Praxis ofwäichen fir e Checksum vun onkompriméierten Donnéeën ze späicheren.

Zesummefaassung: Mir benotzen CRC-32C, mir berechnen d'Kontrollsumme vun den Donnéeën an der Form an där se geschriwwe ginn fir ze flashen (no Kompressioun).

Redundanz

D'Benotzung vun redundante Kodéierung eliminéiert selbstverständlech net Datenverloscht, awer et kann däitlech (dacks vu villen Uerderen) d'Wahrscheinlechkeet vum irrecuperablen Dateverloscht reduzéieren.

Mir kënne verschidden Aarte vu Redundanz benotze fir Feeler ze korrigéieren.
Hamming Coden kënnen eenzel Bitfehler korrigéieren, Reed-Solomon Charaktercoden, Multiple Kopien vun Daten kombinéiert mat Kontrollsummen, oder Kodéierungen wéi RAID-6 kënnen hëllefen, Daten ze recuperéieren och am Fall vu massiver Korruptioun.
Am Ufank war ech fir déi verbreet Notzung vu Feeler-resistente Kodéierung engagéiert, awer dunn hunn ech gemierkt datt mir als éischt eng Iddi musse hunn vu wéi enge Feeler mir eis wëllen schützen, an dann Kodéierung wielen.

Mir hu virdru gesot datt Feeler esou séier wéi méiglech musse gefaange ginn. A wéi enge Punkte kënne mir Feeler begéinen?

  1. Onfäerdeg Opnam (aus irgendege Grënn zum Zäitpunkt vun der Opnam war d'Kraaft ausgeschalt, de Raspberry gefruer, ...)
    Och, am Fall vun esou engem Feeler bleift nëmmen ongëlteg records ze ignoréieren an d'Donnéeë verluer ze betruecht;
  2. Schreiffehler (aus e puer Grënn, wat an de Flash Memory geschriwwe gouf war net dat wat geschriwwe gouf)
    Mir kënnen esou Feeler direkt entdecken wa mir en Test liesen direkt no der Opnam;
  3. Verzerrung vun Daten am Erënnerung während der Späichere;
  4. Liesfehler
    Fir et ze korrigéieren, wann de Checksum net entsprécht, ass et genuch fir d'Liesen e puer Mol ze widderhuelen.

Dat ass, nëmme Feeler vun der drëtter Zort (spontan Korruptioun vun Daten während Stockage) kann net ouni Feeler-resistent géint coding korrigéiert ginn. Et schéngt, datt esou Feeler nach extrem onwahrscheinlech sinn.

Zesummefaassung: Et gouf decidéiert iwwerflësseg Kodéierung opzeginn, awer wann d'Operatioun de Feeler vun dëser Entscheedung weist, da gitt zréck op d'Iwwerleeung vum Thema (mat scho cumuléierte Statistiken iwwer Feeler, wat et erlaabt d'optimal Aart vu Kodéierung ze wielen).

Прочее

Natierlech erlaabt d'Format vum Artikel eis net all Stéck am Format ze justifiéieren (a meng Kraaft ass schonn ausgaang), dofir ginn ech kuerz op e puer Punkten, déi net virdru beréiert sinn.

  • Et gouf decidéiert all Säiten "gläich" ze maachen
    Dat heescht, et gi keng speziell Säiten mat Metadaten, getrennten Threads, etc., mee amplaz en eenzegen Thread deen all Säiten ëmdréit.
    Dëst garantéiert souguer Verschleiung op de Säiten, keen eenzege Punkt vun Echec, an ech hunn et just gär;
  • Et ass néideg fir d'Versioun vum Format ze bidden.
    E Format ouni Versiounsnummer am Header ass béis!
    Et ass genuch fir e Feld mat enger bestëmmter Magic Number (Ënnerschrëft) un den Header vun der Säit ze addéieren, wat d'Versioun vum benotzte Format uginn (Ech denken net datt et an der Praxis souguer eng Dose vun hinnen wäert sinn);
  • Benotzt e verännerleche Längt Header fir Opzeechnungen (vun deenen et vill sinn), probéiert et an de meeschte Fäll 1 Byte laang ze maachen;
  • Fir d'Längt vum Header an d'Längt vum ofgeschniddenen Deel vum kompriméierte Rekord ze codéieren, benotzt variabel Längt binär Coden.

Vill gehollef online generator Huffman Coden. An nëmmen e puer Minutten konnten mir déi néideg Variabel Längt Coden auswielen.

Beschreiwung vun Daten Stockage Format

Byte Uerdnung

Felder méi grouss wéi ee Byte ginn am Big-endian Format (Netzwierkbyte Uerdnung) gespäichert, dat heescht 0x1234 gëtt als 0x12, 0x34 geschriwwe.

Paginatioun

All Flash Memory ass a Säiten vun der selwechter Gréisst opgedeelt.

D'Standard Säitgréisst ass 32Kb, awer net méi wéi 1/4 vun der Gesamtgréisst vum Memory Chip (fir e 4MB Chip ginn 128 Säiten kritt).

All Säit späichert Daten onofhängeg vun deenen aneren (dat ass, Daten op enger Säit referenzéieren keng Daten op enger anerer Säit).

All Säiten sinn an der natierlecher Uerdnung nummeréiert (an opsteigend Uerdnung vun Adressen), ugefaange mat Nummer 0 (Säit Null fänkt un Adress 0 un, déi éischt Säit fänkt un 32Kb un, déi zweet Säit fänkt un 64Kb un, asw.)

De Memory Chip gëtt als zyklesche Puffer (Ringbuffer) benotzt, dat heescht, éischt Schreiwen geet op d'Säit Nummer 0, dann d'Nummer 1, ..., wa mir déi lescht Säit ausfëllen, fänkt en neien Zyklus un an d'Opnahm geet weider vun der Säit Null .

Bannen op der Säit

Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash
Um Ufank vun der Säit gëtt e 4-Byte Säit Header gespäichert, dann e Header Checksum (CRC-32C), da ginn records am Format "Header, Data, Checksum" gespäichert.

Den Titel vun der Säit (dreckeg gréng am Diagramm) besteet aus:

  • zwee-Byte Magic Number Feld (och en Zeechen vun der Format Versioun)
    fir déi aktuell Versioun vum Format gëtt et als berechent 0xed00 ⊕ номер страницы;
  • zwee-Byte Konter "Säit Versioun" (Erënnerung ëmschreiwen Zyklus Zuel).

Entréen op der Säit ginn a kompriméierter Form gespäichert (den Deflat Algorithmus gëtt benotzt). All records op enger Säit sinn an engem thread kompriméiert (e gemeinsame Wierderbuch gëtt benotzt), an op all nei Säit fänkt d'Kompressioun nei un. Dat ass, fir all Rekord ze dekompriméieren, sinn all virdrun records vun dëser Säit (an nëmmen dësen) erfuerderlech.

All Rekord gëtt mat der Z_SYNC_FLUSH Fändel kompriméiert, an um Enn vun der kompriméierter Baach ginn et 4 Bytes 0x00, 0x00, 0xff, 0xff, méiglecherweis vun engem oder zwee méi Null Bytes viraus.
Mir verwerfen dës Sequenz (4, 5 oder 6 Bytes laang) wann Dir op Flash Memory schreift.

De Rekordheader ass 1, 2 oder 3 Bytes déi späicheren:

  • ee bëssen (T) besot der Zort Rekord: 0 - Kontext, 1 - aloggen;
  • e verännerleche Längtfeld (S) vun 1 bis 7 Bits, definéiert d'Längt vum Header an de "Schwänz", deen op de Rekord fir Dekompressioun bäigefüügt muss ginn;
  • Rekordlängt (L).

S Wäert Dësch:

S
Header Längt, Bytes
Op Schreiwen verworf, Byte

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)

Ech hu probéiert ze illustréieren, ech weess net wéi kloer et erausgaang ass:
Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash
Giel weist hei d'T-Feld, wäiss d'S-Feld, gréng L (d'Längt vun de kompriméierten Donnéeën an Bytes), Blo déi kompriméiert Donnéeën, rout déi lescht Bytes vun de kompriméierten Donnéeën, déi net op Flash-Erënnerung geschriwwe sinn.

Also kënne mir Rekordheader vun der üblecher Längt (bis zu 63+5 Bytes a kompriméierter Form) an engem Byte schreiwen.

No all Rekord gëtt e CRC-32C Checksum gespäichert, an deem den invertéierte Wäert vun der viregter Checksum als initial Wäert (init) benotzt gëtt.

CRC huet de Besëtz vun "Dauer", déi folgend Formel funktionnéiert (plus oder minus Bit Inversioun am Prozess): Meng Ëmsetzung vun engem Ring Prellbock am NOR Flash.
Dat ass, tatsächlech, berechent mir den CRC vun alle fréiere Bytes vun Header an Daten op dëser Säit.

Direkt no der Checksum ass den Header vum nächste Rekord.

Den Header ass sou entworf datt säin éischte Byte ëmmer anescht ass wéi 0x00 an 0xff (wann amplaz vum éischte Byte vum Header mir 0xff begéinen, heescht dat datt dëst en onbenotzt Gebitt ass; 0x00 signaliséiert e Feeler).

Beispill Algorithmen

Liesen aus Flash Memory

All Liesung kënnt mat engem Checksum Check.
Wann de Checksum net entsprécht, gëtt d'Liesen e puer Mol widderholl an der Hoffnung déi richteg Donnéeën ze liesen.

(dëst mécht Sënn, Linux liest net aus NOR Flash Cache, getest)

Schreift op Flash Memory

Mir notéieren d'Donnéeën.
Loosst eis se liesen.

Wann d'Liesdaten net mat den schrëftlechen Donnéeën passen, fëllen mir d'Fläche mat Nullen a signaliséieren e Feeler.

Preparéieren en neie microcircuit fir Operatioun

Fir d'Initialiséierung gëtt en Header mat Versioun 1 op déi éischt (oder éischter Null) Säit geschriwwe.
Duerno gëtt den initialen Kontext op dës Säit geschriwwe (enthält d'UUID vun der Maschinn an d'Standardastellungen).

Dat ass et, de Flash Memory ass prett fir ze benotzen.

Luede der Maschinn

Beim Luede ginn déi éischt 8 Bytes vun all Säit (Header + CRC) gelies, Säiten mat enger onbekannter Magic Number oder enger falscher CRC ginn ignoréiert.
Vun de "korrekt" Säiten ginn Säiten mat der maximaler Versioun ausgewielt, an d'Säit mat der héchster Zuel gëtt vun hinnen geholl.
Den éischte Rekord gëtt gelies, d'Korrektheet vum CRC an d'Präsenz vum "Kontext" Fändel ginn iwwerpréift. Wann alles gutt ass, gëtt dës Säit als aktuell ugesinn. Wann net, rullt mir zréck op déi virdrun bis mir eng "Live" Säit fannen.
an op der fonnt Säit liesen mir all records, déi mir mat der "Kontext" Fändel benotzen.
Späichert den zlib Wierderbuch (et wäert gebraucht ginn fir op dës Säit ze addéieren).

Dat ass et, den Download ass fäerdeg, de Kontext ass restauréiert, Dir kënnt schaffen.

Dobäizemaachen vun engem Journal Entrée

Mir kompriméieren de Rekord mat dem richtege Wierderbuch, spezifizéiert Z_SYNC_FLUSH Mir kucken ob de kompriméierte Rekord op déi aktuell Säit passt.
Wann et net passt (oder et waren CRC Feeler op der Säit), fänkt eng nei Säit un (kuckt hei ënnen).
Mir schreiwen de Rekord an CRC. Wann e Feeler geschitt, fänkt eng nei Säit un.

Nei Säit

Mir wielen eng gratis Säit mat der Mindestzuel (mir betruechten eng gratis Säit als eng Säit mat engem falschen Checksum am Header oder mat enger Versioun manner wéi déi aktuell). Wann et keng sou Säite gëtt, wielt d'Säit mat der Mindestzuel vun deenen déi eng Versioun gläich wéi déi aktuell hunn.
Mir läschen déi gewielte Säit. Mir kontrolléieren den Inhalt mat 0xff. Wann eppes falsch ass, huelt déi nächst fräi Säit, etc.
Mir schreiwen en Header op der geläscht Säit, déi éischt Entrée ass den aktuellen Zoustand vum Kontext, déi nächst ass den ongeschriwwene Logeintrag (wann et een ass).

Format Applikatioun

Menger Meenung no huet et sech als e gutt Format erausgestallt fir all méi oder manner kompriméierbar Informatiounsstroum (Klengtext, JSON, MessagePack, CBOR, eventuell Protobuf) am NOR Flash ze späicheren.

Natierlech ass d'Format "geschnidde" fir SLC NOR Flash.

Et sollt net mat héije BER Medien wéi NAND oder MLC NOR benotzt ginn (ass esou Erënnerung iwwerhaapt ze verkafen? Ech hunn et nëmmen a Wierker iwwer Korrekturcodes ernimmt gesinn).

Ausserdeem sollt et net mat Apparater benotzt ginn déi hiren eegene FTL hunn: USB Flash, SD, MicroSD, etc (fir sou Erënnerung hunn ech e Format mat enger Säitgréisst vun 512 Bytes erstallt, eng Ënnerschrëft um Ufank vun all Säit an eenzegaarteg Rekordnummeren - heiansdo war et méiglech all d'Donnéeën vun engem "glitched" Flash Drive duerch einfach sequenziell Liesen ze recuperéieren).

Ofhängeg vun den Aufgaben, kann de Format ouni Ännerungen op Flash Drive vun 128Kbit (16Kb) op 1Gbit (128MB) benotzt ginn. Wann Dir wëllt, kënnt Dir et op méi grouss Chips benotzen, awer Dir musst wahrscheinlech d'Säitgréisst upassen (Awer hei stellt sech d'Fro vun der wirtschaftlecher Machbarkeet schonn op; de Präis fir Groussvolumen NOR Flash ass net encouragéierend).

Wann iergendeen d'Format interessant fënnt an et an engem oppene Projet benotze wëllt, schreift, ech probéieren d'Zäit ze fannen, de Code poléieren an et op github posten.

Konklusioun

Wéi Dir gesitt, ass um Enn d'Format einfach erausgestallt an esouguer langweileg.

Et ass schwéier d'Evolutioun vu menger Siicht an engem Artikel ze reflektéieren, awer gleeft mir: am Ufank wollt ech eppes raffinéiert kreéieren, onverständlech, kapabel souguer eng nuklear Explosioun an der Noperschaft ze iwwerliewen. Wéi och ëmmer, de Grond (hoffen ech) huet nach ëmmer gewonnen a lues a lues hu Prioritéite sech a Richtung Einfachheet a Kompaktheet verréckelt.

Kann et sinn datt ech falsch war? Jo, sécher. Et kann zum Beispill erausstellen datt mir eng Partie vu niddereg-Qualitéit Mikrokreesser kaaft hunn. Oder aus engem anere Grond wäert d'Ausrüstung net Zouverlässegkeet Erwaardungen treffen.

Hunn ech e Plang fir dëst? Ech mengen, nodeems Dir den Artikel gelies hutt, hutt Dir keen Zweiwel datt et e Plang ass. An och net eleng.

Op e bësse méi sérieux Notiz gouf de Format souwuel als Aarbechtsoptioun an als "Testballon" entwéckelt.

Am Moment leeft alles op den Dësch gutt, wuertwiertlech den aneren Dag gëtt d'Léisung agesat (ongeféier) op Honnerte vun Apparater, loosst eis kucken wat an der "Kampf" Operatioun geschitt (glécklecherweis, ech hoffen, datt d'Format Iech erlaabt Iech zouverlässeg Feeler z'entdecken; sou datt Dir voll Statistike sammele kënnt). An e puer Méint wäert et méiglech sinn Conclusiounen ze zéien (a wann Dir Pech hutt, nach méi fréi).

Wann, baséiert op d'Resultater vum Gebrauch, sérieux Probleemer entdeckt ginn a Verbesserungen erfuerderlech sinn, da wäert ech definitiv doriwwer schreiwen.

Literatur

Ech wollt net eng laang langweileg Lëscht vu benotzte Wierker maachen; schliisslech huet jiddereen Google.

Hei hunn ech décidéiert eng Lëscht vun Erkenntnisser ze verloossen, déi fir mech besonnesch interessant ausgesinn hunn, awer no an no sinn se direkt an den Text vum Artikel migréiert, an een Element ass op der Lëscht bliwwen:

  1. Utility infgen vum Auteur zlib. Kann den Inhalt vun deflate / zlib / gzip Archiven kloer weisen. Wann Dir mat der interner Struktur vum Deflate (oder gzip) Format ze këmmeren muss, ech recommandéieren et héich.

Source: will.com

Setzt e Commentaire