{"id":53751,"date":"2019-12-09T00:00:00","date_gmt":"2019-12-08T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash"},"modified":"2020-02-18T14:01:41","modified_gmt":"2020-02-18T11:01:41","slug":"moya-realizatsiya-koltsevogo-bufera-v-nor-flash","status":"publish","type":"post","link":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash","title":{"rendered":"Minu NOR flash'i ringbuferi rakendus","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h1 id=\"predystoriya\">Eelalugu<\/h1>\n<p><\/p>\n<p>Meil on oma arendatud automaadid. Sees on Raspberry Pi ja m\u00f5ningane lisaseade eraldi plaadil. \u00dchendatud on m\u00fcntide vastuv\u00f5tja, pangakaarditud, pangaterminal jne. K\u00f5ike juhib omak\u00e4eliselt kirjutatud programm. K\u00f5ik t\u00f6\u00f6ajalugu salvestatakse USB-m\u00e4lupulgale (MicroSD), mis edastatakse seej\u00e4rel interneti kaudu (kasutades USB-modem) serverisse, kus see salvestatakse andmebaasi. M\u00fc\u00fcgiteave laaditakse 1C-sse, samuti on olemas lihtne veebiliides j\u00e4lgimiseks jne. <\/p>\n<p><\/p>\n<p>Seega on ajakiri h\u00e4davajalik \u2013 arvestuseks (seal on tulu, m\u00fc\u00fcgid jne), j\u00e4lgimiseks (k\u00f5ikv\u00f5imalikud t\u00f5rked ja muud ootamatud olukorrad); see on, v\u00f5ib \u00f6elda, kogu teave, mis meil selle automaadi kohta on. <\/p>\n<p><\/p>\n<h1 id=\"problema\">Probleem<\/h1>\n<p><\/p>\n<p>M\u00e4lupulgad on n\u00e4idanud end v\u00e4ga ebastabiilsete seadmetena. Need riknevad \u00fcllataval m\u00e4\u00e4ral. See p\u00f5hjustab nii automaatide seiskumisi kui ka (kui mingil p\u00f5hjusel ajakirja ei suudetud veebis edastada) andmete kaotust.<\/p>\n<p><\/p>\n<p><em>See on juba mitte esimene kogemus m\u00e4lupulkade kasutamisel; eelmisel projektis oli \u00fcle saja seadme, kus ajalugu salvestati USB-m\u00e4lupulkadel. Seal olid samuti usaldusprobleemid ja m\u00f5nikord tuli kuus v\u00e4lja vahetada k\u00fcmneid. Proovisime erinevaid m\u00e4lupulkasid, sealhulgas br\u00e4ndipulki SLC m\u00e4luga; jah, m\u00f5ned mudelid on usaldusv\u00e4\u00e4rsemad kui teised, kuid m\u00e4lupulkade vahetamine ei lahendanud probleemi kardinaalselt.<\/em><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <\/p>\n<p><strong>T\u00e4helepanu!<\/strong> Pikklugu! Kui teid ei huvi &#171;miks&#187;, vaid ainult &#171;kuidas&#187;, v\u00f5ite kohe minna. <noindex><a rel=\"nofollow\" href=\"#format\">l\u00f5ppu<\/a><\/noindex> artiklist.<\/p>\n<p><\/p>\n<h1 id=\"reshenie\">Lahendus<\/h1>\n<p><\/p>\n<p>Esimene m\u00f5te: loobuda MicroSD-st, paigaldada n\u00e4iteks SSD ja bootida sellest. Teoorias on see v\u00f5imalik, v\u00f5ib-olla, kuid suhteliselt kallis ja mitte eriti usaldusv\u00e4\u00e4rne (lisandub USB-SATA adapter; ka odavate SSD-de rike on statistiliselt murettekitav).<\/p>\n<p><\/p>\n<p>USB HDD ei tundu samuti eriti atraktiivne lahendus.<\/p>\n<p><\/p>\n<p>Seet\u00f5ttu j\u00f5udsime sellise lahenduseni: j\u00e4tta bootimine MicroSD-st, kuid kasutada neid kirjutamisest koosnevas re\u017eiimis ja salvestada t\u00f6\u00f6ajalugu (ja muu konkreetse seadme jaoks unikaalne teave \u2014 seerianumber, sensorite kalibreerimine jne) kuskile mujale. <\/p>\n<p><\/p>\n<p>Read-only fail-safe teema Raspberry Pi jaoks on juba p\u00f5hjalikult uuritud, ma ei hakka selles artiklis rakenduse \u00fcksikasjadele peatuma. <em>(kuid kui huvi on \u2014 ehk kirjutan sellel teemal mini-artikli).<\/em>. \u00dcks asi, mida sooviksin m\u00e4rkida: nii isikliku kogemuse kui ka nende tagasiside p\u00f5hjal, kes on juba rakendanud, on usaldusv\u00e4\u00e4rsuse kasu olemas. Jah, t\u00e4ielikult rikkeid v\u00e4ltida ei saa, kuid nende tekkimise sagedust on t\u00e4iesti v\u00f5imalik oluliselt v\u00e4hendada. Ja ka kaardid muutuvad \u00fchtseks, mis lihtsustab hooldust\u00f6\u00f6tajate vahetust oluliselt.<\/p>\n<p><\/p>\n<h2 id=\"apparatnaya-chast\">Riistvara osa<\/h2>\n<p><\/p>\n<p>M\u00e4lu t\u00fc\u00fcbi valikuga ei olnud erilisi kahtlusi \u2014 NOR Flash.<br \/>\nArgumentide loetelu: <\/p>\n<p><\/p>\n<ul>\n<li>Lihtne \u00fchendamine (enamasti SPI buss, mille kasutamise kogemus on juba olemas, seega &#171;rauda&#187; probleeme ei ootata);<\/li>\n<li>naljakas hind;<\/li>\n<li>standardne t\u00f6\u00f6protokoll (rakendus on juba Linuxi tuumas olemas, soovi korral saab kasutada ka kolmanda osapoole lahendusi, mida samuti leidub, v\u00f5i isegi kirjutada enda, sest k\u00f5ik on lihtne);<\/li>\n<li>usaldusv\u00e4\u00e4rsus ja ressursid:<br \/>\nt\u00fc\u00fcpilisest andmelehtest: andmed s\u00e4ilivad 20 aastat, 100000 kustutust iga ploki jaoks;<br \/>\nkolmandatest allikatest: \u00e4\u00e4rmiselt madal BER, v\u00e4idetakse, et vigade paranduskoodide vajadust ei ole. <em>(m\u00f5nedes t\u00f6\u00f6des k\u00e4sitletakse ECC-d NOR-i jaoks, kuid enamasti m\u00f5eldakse siiski MLC NOR-i, k\u00fcll aga on see v\u00f5imalik)<\/em>.<\/li>\n<\/ul>\n<p><\/p>\n<p>Vaatame n\u00f5udeid mahu ja ressursi osas.<\/p>\n<p><\/p>\n<p>Tahame, et andmed s\u00e4iliksid soovitud v\u00e4hemalt paariks p\u00e4evaks. See on vajalik selleks, et ajaloolised m\u00fc\u00fcgid ei kaoks, kui tekib mingit t\u00fc\u00fcpi suhtlusprobleeme. Suundume viiele p\u00e4evale, selle ajaga <em>(isegi puhkep\u00e4evade ja p\u00fchade arvestamisel)<\/em> on probleem lahendatav.<\/p>\n<p><\/p>\n<p>Meil koguneb praegu p\u00e4evas umbes 100 kb logi (3-4 tuhat kirjet), kuid see number kasvab j\u00e4rk-j\u00e4rgult \u2013 detailide suurenemise ja uute s\u00fcndmuste lisandumise t\u00f5ttu. Lisaks on aeg-ajalt ka t\u00f5ususid (n\u00e4iteks m\u00f5ni andur hakkab valeh\u00e4ireid genereerima). Arvutame 10 tuhande kirje pealt, 100 baidi kohta - 1 megabait p\u00e4evas.<\/p>\n<p><\/p>\n<p>Kokku tuleb 5 MB puhtaid (h\u00e4sti tihendatavaid) andmeid. Nendele lisandub veel <em>(karm hinnang)<\/em> 1 MB administraatiivandmeid.<\/p>\n<p><\/p>\n<p>See t\u00e4hendab, et vajame 8 MB kiipi, kui tihendamist ei kasutata, v\u00f5i 4 MB, kui kasutatakse. Need numbrid on t\u00e4iesti realistlikud selle t\u00fc\u00fcpi m\u00e4lu jaoks.<\/p>\n<p><\/p>\n<p>Ressursi osas: kui me eeldame, et m\u00e4lu kirjutatakse t\u00e4ielikult \u00fcle mitte sagedamini kui iga 5 p\u00e4eva tagant, siis 10-aastase kasutuse jooksul saame v\u00e4hem kui tuhat \u00fcle kirjutamise ts\u00fcklit.<br \/>\nTuletan meelde, et tootja lubab sada tuhat.<\/p>\n<p>\n<b class=\"spoiler_title\">Veidi NOR vs NAND kohta<\/b><\/p>\n<p>Praegu on kindlasti palju populaarsem NAND-m\u00e4lu, kuid selle projekti puhul ei soovita ma seda kasutada: NAND, erinevalt NOR-ist, n\u00f5uab tingimata vigade paranduse koode, vigaste plokkide tabelit jne, ja NAND-kiipide jalgade arv on tavaliselt palju suurem.<\/p>\n<p><\/p>\n<p>NOR-i puudustena v\u00f5ib v\u00e4lja tuua:<\/p>\n<p><\/p>\n<ul>\n<li>v\u00e4ike maht (ja seega k\u00f5rge hind megabaidi kohta);<\/li>\n<li>keskmine edastuskiirus (suures osas t\u00e4nu sellele, et kasutatakse j\u00e4rjestikulist liidest, tavaliselt SPI v\u00f5i I2C);<\/li>\n<li>aeglane kustutamine (s\u00f5ltuvalt ploki suurusest v\u00f5ib see v\u00f5tta osah\u00e4\u00e4lte sekunditest kuni mitme sekundini).<\/li>\n<\/ul>\n<p><\/p>\n<p>Dramatiseerimata, j\u00e4tkame.<\/p>\n<p><\/p>\n<p>Kui \u00fcksikasjad huvitavad, on valitud kiip <noindex><a rel=\"nofollow\" href=\"https:\/\/www.adestotech.com\/wp-content\/uploads\/doc3686.pdf\">at25df321a<\/a><\/noindex> <em>(kuid siiski on see ebaoluline, turul on hulk analooge, mis on \u00fchenduskaabli ja k\u00e4sus\u00fcsteemiga \u00fchilduvad; isegi kui soovime paigaldada kiibi teiselt tootjalt ja\/v\u00f5i teises mahus, t\u00f6\u00f6tab k\u00f5ik ilma koodi muutmiseta)<\/em>.<\/p>\n<p><\/p>\n<p>Kasutame Linuxi tuuma sisse ehitatud draiverit, Raspberryl on seadme puu katte toe t\u00f5ttu k\u00f5ik v\u00e4ga lihtne \u2014 piisab, kui panna \/boot\/overlaysse kompileeritud overlay ja veidi muuta \/boot\/config.txt faili.<\/p>\n<p>\n<b class=\"spoiler_title\">DTS faili n\u00e4idis<\/b><\/p>\n<p>Olles aus, pole ma kindel, et see on kirjutatud ilma vigadeta, aga see t\u00f6\u00f6tab.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">\/*\n * Device tree overlay for at25 at spi0.1\n *\/\n\n\/dts-v1\/;\n\/plugin\/;\n\n\/ {\n    compatible = \"brcm,bcm2835\", \"brcm,bcm2836\", \"brcm,bcm2708\", \"brcm,bcm2709\"; \n\n    \/* disable spi-dev for spi0.1 *\/\n    fragment@0 {\n        target = &lt;&amp;spi0&gt;;\n        __overlay__ {\n            status = \"okay\";\n            spidev@1{\n                status = \"disabled\";\n            };\n        };\n    };\n\n    \/* the spi config of the at25 *\/\n    fragment@1 {\n        target = &lt;&amp;spi0&gt;;\n        __overlay__ {\n            #address-cells = &lt;1&gt;;\n            #size-cells = &lt;0&gt;;\n            flash: m25p80@1 {\n                    compatible = \"atmel,at25df321a\";\n                    reg = &lt;1&gt;;\n                    spi-max-frequency = &lt;50000000&gt;;\n\n                    \/* default to false:\n                    m25p,fast-read ;\n                    *\/\n            };\n        };\n    };\n\n    __overrides__ {\n        spimaxfrequency = &lt;&amp;flash&gt;,\"spi-max-frequency:0\";\n        fastread = &lt;&amp;flash&gt;,\"m25p,fast-read?\";\n    };\n};<\/code><\/pre>\n<p>\n<b class=\"spoiler_title\">Ja veel \u00fcks rida config.txt failis<\/b><\/p>\n<pre><code class=\"plaintext\">dtoverlay=at25:spimaxfrequency=50000000<\/code><\/pre>\n<p><\/p>\n<p>Kiibi \u00fchendamise kirjeldust Raspberry Pi-le j\u00e4tan vahele. \u00dchest k\u00fcljest pole ma elektroonika spetsialist, teisest k\u00fcljest on see isegi minu jaoks elementaarne: kiibil on ainult 8 jalga, millest me vajame vaid maapinda, toidet, SPI (CS, SI, SO, SCK); tasemed sobivad Raspberry Pi omadega, t\u00e4iendavat sidumist ei ole vaja \u2014 lihtsalt \u00fchendage kuus kontaktpunkti.<\/p>\n<p><\/p>\n<h2 id=\"postanovka-zadachi\">\u00dclesande seadmine<\/h2>\n<p><\/p>\n<p>Nagu tavaliselt, l\u00e4bib \u00fclesande seadmine mitmeid iteratsioone, mulle tundub, et on aeg j\u00e4rgmise jaoks. Nii et l\u00f5petame, koondame selle, mis on juba kirjutatud, ja selgitame v\u00e4lja varjatud \u00fcksikasjad.<\/p>\n<p><\/p>\n<p>Nii et, oleme otsustanud, et ajakiri salvestatakse SPI NOR Flash'i.<\/p>\n<p>\n<b class=\"spoiler_title\">Mis on NOR Flash, kui keegi ei tea<\/b><\/p>\n<p>See on energiat mittevajav m\u00e4lu, millega saab teha kolme toimingut:<\/p>\n<p><\/p>\n<ol>\n<li>Lugemine:<br \/>\nTavaline lugemine: edastame aadressi ja loeme nii palju baitide, kui vajame;<\/li>\n<li>Salvestamine:<br \/>\nKirjutamine NOR flash'i n\u00e4eb v\u00e4lja nagu tavaline, kuid sellel on \u00fcks omadus: saab muuta ainult 1-ks 0, mitte vastupidi. N\u00e4iteks, kui meil on m\u00e4lu lahtris 0x55, siis p\u00e4rast 0x0f kirjutamist sinna, j\u00e4\u00e4b seal hoitavaks 0x05 <em>(vt tabelit allpool)<\/em>;<\/li>\n<li>Kustutamine:<br \/>\nMuidugi, peame suutma teha ka vastupidist operatsiooni \u2014 muuta 0-ks 1, selle jaoks ongi olemas kustutamise toiming. Erinevalt esimestest kahest toimingust, p\u00f5hineb see blokki, mitte baitidel (valitud mikroskeemi minimaalne kustutus blokk on 4kb). Kustutamine h\u00e4vitab kogu blokki tervikuna ja see on ainus viis, kuidas muuta 0-ks 1. Seet\u00f5ttu tuleb flash-m\u00e4luga t\u00f6\u00f6tades sageli andmestruktuure joondada kustutusplokkide piirile.<br \/>\nKirjutamine NOR Flash'i:<\/li>\n<\/ol>\n<p><\/p>\n<p>Binaarsed andmed<\/p>\n<p><strong>Oli<\/strong><br \/>\n<code>01010101<\/code><\/p>\n<p><strong>Oleme kirjutanud<\/strong><br \/>\n<code>00001111<\/code><\/p>\n<p><strong>Kohandatud<\/strong><br \/>\n<code>00000101<\/code><\/p>\n<p><\/p>\n<p>Ajakiri ise on muutuva pikkusega kirjeid j\u00e4rjestus. T\u00fc\u00fcpiline kirje pikkus on umbes 30 baiti (kuigi m\u00f5nikord juhtub, et kirjed on mitu kilobaiti pikad). <em>Antud juhul t\u00f6\u00f6tame nendega lihtsalt kui baitide kogumiga, kuid kui huvitab, siis salvestustes kasutatakse CBOR-i.<\/em><\/p>\n<p><\/p>\n<p>Lisaks ajakirjale peame hoidma mingit &#171;seadistuste&#187; teavet, nii uuendatavat kui ka mitte: mingi seadme ID, sensorite kalibreerimine, &#171;seade on ajutiselt v\u00e4lja l\u00fclitatud&#187; lipp jne.<br \/>\nSee teave koosneb key-value \u0437\u0430\u043f\u0438\u0441idest, mis on samuti salvestatud CBOR-i. Meil ei ole seda teavet v\u00e4ga palju (maksimaalselt paar kilobaiti), see uuendatakse harva.<br \/>\nHiljem nimetame seda kontekstiks.<\/p>\n<p><\/p>\n<p>Kui meenutada, kust see artikkel algas, on v\u00e4ga oluline tagada andmete s\u00e4ilitamise usaldusv\u00e4\u00e4rsus ja, kui v\u00f5imalik, katkematu t\u00f6\u00f6 isegi riistvaraharvikute\/debiitide korral.<\/p>\n<p><\/p>\n<p>Milliseid probleemiallikasid saaks kaaluda?<\/p>\n<p><\/p>\n<ul>\n<li>Toite v\u00e4ljal\u00fclitamine kirjutamise\/kustutamise operatsioonide ajal. See kuulub &#171;vastu t\u00f5de pole lutti&#187; kategooriasse.<br \/>\nTeave p\u00e4rit <noindex><a rel=\"nofollow\" href=\"https:\/\/electronics.stackexchange.com\/questions\/225956\/what-would-happen-in-case-of-power-outage-during-nor-flash-erase-or-programming\">esitati<\/a><\/noindex> stackexchange'is: toite v\u00e4ljal\u00fclitamine flashi t\u00f6\u00f6tamise ajal, nii erase (seadmine 1) kui write (seadmine 0) viib m\u00e4\u00e4ramatute tagaj\u00e4rgedeni: andmed v\u00f5ivad salvestuda, salvestuda osaliselt (\u00fctleme, me edastasime 10 baiti\/80 bitti, aga olime suutnud salvestada vaid 45 bitti), ei ole v\u00e4listatud, et osa bitte on &#171;vahepealses&#187; olekus (lugemine v\u00f5ib anda nii 0 kui 1);<\/li>\n<li>Flash-m\u00e4lu enda vead.<br \/>\nBER ehk v\u00e4ga madal, aga ei saa olla null;<\/li>\n<li>Vead bussil<br \/>\nAndmed, mis edastatakse SPI kaudu, ei ole kuidagi kaitstud, v\u00f5ivad esineda nii \u00fcksikud bitti vead kui ka s\u00fcnkroonimisvead \u2014 bitide kadumine v\u00f5i lisamine (mis viib massiliste andmete moonutusteni);<\/li>\n<li>Muud vead\/t\u00f5rked<br \/>\nVead koodis, &#171;glitchid&#187; Raspberry, tulnukate sekkumine&#8230;<\/li>\n<\/ul>\n<p><\/p>\n<p>Olen s\u00f5nastanud n\u00f5udmised, mille t\u00e4itmine on minu arvates vajalik usaldusv\u00e4\u00e4rsuse tagamiseks:<\/p>\n<p><\/p>\n<ul>\n<li>kirjutised peavad j\u00f5udma flash-m\u00e4llu kohe, viivitusega kirjutamist ei arvestata; - kui viga tekib, peab see tuvastama ja t\u00f6\u00f6tlema v\u00f5imalikult vara; - s\u00fcsteem peab v\u00f5imaluse korral taastama t\u00f6\u00f6 p\u00e4rast vigade ilmnemist.<br \/>\n<em>(elust n\u00e4ide &#171;kuidas ei tohiks olla&#187;, millega, arvan, iga\u00fchel on kokku puutunud: p\u00e4rast h\u00e4daseisundi taask\u00e4ivitamist &#171;purunes&#187; failis\u00fcsteem ja operatsioonis\u00fcsteem ei k\u00e4ivitu)<\/em><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"idei-podhody-razmyshleniya\">Ideed, l\u00e4henemised, m\u00f5tisklused<\/h2>\n<p><\/p>\n<p>Kui hakkasin sellele probleemile m\u00f5tlema, jooksid peast l\u00e4bi hulgaliselt ideid, n\u00e4iteks:<\/p>\n<p><\/p>\n<ul>\n<li>kasutada andmete tihendamist;<\/li>\n<li>kasutada nutikaid andmestruktuure, n\u00e4iteks hoida kirjepealkirjad eraldi kirjetest, et vigastuse korral m\u00f5nes kirjes saaks \u00fclej\u00e4\u00e4nud probleemideta lugeda;<\/li>\n<li>kasutada bitiv\u00e4lju kirje l\u00f5petatuse kontrollimiseks toite katkestamise ajal;<\/li>\n<li>hoida kontrollsummasid k\u00f5ikjal;<\/li>\n<li>kasutada m\u00f5nda sorti vigade parandamise kodeerimist.<\/li>\n<\/ul>\n<p><\/p>\n<p>Osa neist ideedest rakendati, osa otsustati k\u00f5rvale j\u00e4tta. Alustame j\u00e4rjekorras.<\/p>\n<p><\/p>\n<h3 id=\"szhatie-dannyh\">Andmete tihendamine<\/h3>\n<p><\/p>\n<p>S\u00fcndmused, mida me ajakirjas registreerime, on piisavalt \u00fchetaolised ja korduvad (&#171;viskas m\u00fcndi 5 rubla&#187;, &#171;vajutas v\u00e4ljundkliendi nuppu&#187; jne). Seet\u00f5ttu peaks kokkusurumine olema piisavalt t\u00f5hus.<\/p>\n<p><\/p>\n<p>Surve kulud kokkusurumise puhul on ebaolulised (meil on piisavalt v\u00f5imas protsessor, isegi esimesel Pi-l oli \u00fcks 700 MHz tuum, t\u00e4nap\u00e4evastes mudelites on mitu tuuma \u00fcle \u00fche gigaherti), andmete vahetamise kiirus salvestusega ei ole k\u00f5rge (m\u00f5ned megabaitides sekundis), kirjete suurus on v\u00e4ike. Kokkuv\u00f5ttes, kui kokkusurumine m\u00f5jutab j\u00f5udlust, siis ainult positiivselt. <em>(absoluutselt mitte kriitiline, lihtsalt konstateerin)<\/em>. Pluss, meil ei ole ju tegelikult embedded, vaid tavaline Linux \u2014 seega ei tohiks rakendamine palju vaeva n\u00f5uda (piisab lihtsalt raamatukogu liitmisest ja m\u00f5ne funktsiooni kasutamisest sealt).<\/p>\n<p><\/p>\n<p>V\u00f5eti proov logifailist t\u00f6\u00f6tavast seadmest (1,7 MB, 70 tuhat kirjet) ja alguses kontrolliti seda kokkusurumise osas olemasolevate gzipi, lz4, lzop, bzip2, xz ja zstd abil.<\/p>\n<p><\/p>\n<ul>\n<li>gzip, xz, zstd n\u00e4itasid sarnaseid tulemusi (40 KB).<br \/>\n\u00dcllatusena n\u00e4itas moes xz end siin gzipi v\u00f5i zstd tasemel;<\/li>\n<li>lzip vaikeseadetega andis veidi halvemad tulemused;<\/li>\n<li>lz4 ja lzop n\u00e4itasid mitte eriti h\u00e4id tulemusi (150 KB);<\/li>\n<li>bzip2 n\u00e4itas \u00fcllatavalt h\u00e4id tulemusi (18 KB).<\/li>\n<\/ul>\n<p><\/p>\n<p>Seega andmed kokku surutakse v\u00e4ga h\u00e4sti.<br \/>\nSeega (kui me ei leia t\u00f5siseid vigu) on tihendamine v\u00e4ltimatu! Lihtsalt sellep\u00e4rast, et sama m\u00e4lupulgale mahub rohkem andmeid.<\/p>\n<p><\/p>\n<p>M\u00f5tleme puudustele.<\/p>\n<p><\/p>\n<p>Esimene probleem: me oleme juba kokku leppinud, et iga kirje peab kohe m\u00e4lupulgale minema. Tavaline arhiveerija kogub andmeid sisendvoolust, kuni otsustab, et on aeg kirjutada v\u00e4ljundisse. Meie peame kohe saama tihendatud andmeploki ja salvestama selle mittevolatile m\u00e4llu.<\/p>\n<p><\/p>\n<p>N\u00e4en kolme teed:<\/p>\n<p><\/p>\n<ol>\n<li>Tihendada iga kirje s\u00f5nastiku tihendamise abil, selle asemel et kasutada eelnevalt arutatud algoritme.<br \/>\nT\u00e4idetav variant, kuid mulle see ei meeldi. Tootmise m\u00f5istlikul tasemel kokkusurumise tagamiseks peab s\u00f5nastik olema &#171;suunatud&#187; konkreetsetele andmetele, igasugune muutus toob kaasa h\u00e4vitava kokkusurumise taseme languse. Jah, probleem lahendatakse uue versiooni s\u00f5nastiku loomisega, kuid see on peavalu \u2014 me peame hoidma k\u00f5iki s\u00f5nastiku versioone; iga kirje puhul peame n\u00e4itama, millise s\u00f5nastiku versiooniga see on surutud&#8230;<\/li>\n<li>Iga kirje &#171;klassikaliste&#187; algoritmidega kokku suruda, kuid olenemata teistest.<br \/>\nKasutatavad kokkusurumise algoritmid ei ole ette n\u00e4htud sellise suuruse (k\u00fcmnete baitide) salvestuste t\u00f6\u00f6tlemiseks, kokkusurumise koefitsiendiks j\u00e4\u00e4b selgelt alla 1 (st andmete maht suureneb hoopis, mitte ei v\u00e4hene);<\/li>\n<li>Teha FLUSH p\u00e4rast iga salvestust.<br \/>\nPaljudes kokkusurumisbiblioteekides on FLUSH-i tugi. See on k\u00e4sk (v\u00f5i parameeter kokkusurumisprotseduurile), mille saanud, arhiivija loob kokkusurutud voogu nii, et selle alusel on v\u00f5imalik taastada <strong>k\u00f5ik<\/strong> dekompressitud andmed, mis on juba saadud. Selline analoog <code>sync<\/code> failis\u00fcsteemides v\u00f5i <code>commit<\/code> SQL-is.<br \/>\nOluline on, et hilisemad kokkusurumised saaksid kasutada akumuleeritud s\u00f5nastikku ja kokkusurumise aste ei kannataks nii palju kui eelmises variandis.<\/li>\n<\/ol>\n<p><\/p>\n<p>M\u00f5tlen, et on ilmne, et valisin kolmanda variandi, peatume sellel l\u00e4hemalt.<\/p>\n<p><\/p>\n<p>Leiti <noindex><a rel=\"nofollow\" href=\"https:\/\/www.bolet.org\/~pornin\/deflate-flush.html\">suurep\u00e4rane artikkel<\/a><\/noindex> FLUSH-ist zlib-is.<\/p>\n<p><\/p>\n<p>Tehtud inspiratsioonina artiklist katsetest, v\u00f5tsin 70 tuhat logisaldot reaalsetelt seadmetelt, lehe suuruseks 60Kb <em>(lehe suuruse juurde me veel tagasi tuleme)<\/em> sain:<\/p>\n<p><\/p>\n<p>Algandmed<br \/>\ngzip kokkusurumine -9 (ilma FLUSH-ita)<br \/>\nzlib Z_PARTIAL_FLUSH-iga<br \/>\nzlib Z_SYNC_FLUSH-iga<\/p>\n<p><strong>Maht, Kb<\/strong><br \/>\n1692<br \/>\n40<br \/>\n352<br \/>\n604<\/p>\n<p><\/p>\n<p>Esmapildist n\u00e4ib FLUSH hind \u00fclem\u00e4\u00e4ra k\u00f5rge, kuid tegelikult on meie valik tagasihoidlik \u2013 kas mitte \u00fcldse kokku suruda v\u00f5i suruda (ja v\u00e4ga t\u00f5husalt) FLUSH-iga. Ei tohi unustada, et meil on 70 000 kirjet, Z_PARTIAL_FLUSH toob kaasa vaid 4-5 baiti \u00fcleliigsust iga kirje kohta. Kompressioonikordaja osutus peaaegu 5:1, mis on suurep\u00e4rane tulemus.<\/p>\n<p>\n<b class=\"spoiler_title\">See v\u00f5ib tunduda \u00fcllatav, kuid tegelikult on Z_SYNC_FLUSH \u2014 efektiivsem viis FLUSH teha.<\/b><\/p>\n<p>Kui kasutada Z_SYNC_FLUSH-i, siis iga kirje 4 viimast baiti on alati 0x00, 0x00, 0xff, 0xff. Ja kui need meile teada on \u2013 siis me ei pea neid s\u00e4ilitama, mis t\u00e4hendab, et l\u00f5plik suurus on vaid 324Kb.<\/p>\n<p><\/p>\n<p>Viidatud artiklis on seletus:<\/p>\n<p><\/p>\n<blockquote><p>Lisatakse t\u00fc\u00fcp 0 plokk, mille sisu on t\u00fchi.<\/p>\n<p>T\u00fc\u00fcp 0 plokk t\u00fchi sisu koosneb:<\/p>\n<ul>\n<li>kolmest bitist koosnev plokipealkiri;<\/li>\n<li>0 kuni 7 bitti, mis on v\u00f5rdsed nulliga, et saavutada baitide joondamine;<\/li>\n<li>neli baiti j\u00e4rjestus 00 00 FF FF.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Nagu ei ole raske m\u00e4rgata, eelviimasel plokil enne neid 4 baiti on 3 kuni 10 nullbitid. Kuid praktika on n\u00e4idanud, et nullbitte on tegelikult v\u00e4hemalt 10.<\/p>\n<p><\/p>\n<p>Selgub, et nii l\u00fchikesed andmeplokid kodeeritakse tavaliselt (kas alati?) ploki t\u00fc\u00fcbiga 1 (fiksplokk), mis peab l\u00f5ppema 7 nullbitiga, seega saame kokku 10-17 garanteeritud nullbitti (ja \u00fclej\u00e4\u00e4nud on t\u00f5en\u00e4oliselt nullid umbes 50% t\u00f5en\u00e4osusega).<\/p>\n<p><\/p>\n<p>Seega, testandmete puhul esinevad 100% juhtudest enne 0x00, 0x00, 0xff, 0xff \u00fcks nullbait, ja enam kui kolmandal juhul \u2014 kaks nullbait. <em>(v\u00f5ib-olla on asi selles, et kasutan binaarset CBOR-i, ja teksti JSON-i kasutamisel esineks sagedamini 2. t\u00fc\u00fcpi blokke \u2014 d\u00fcnaamiline plokk, seega esineks blokke ilma lisanduvate nullbaitideta enne 0x00, 0x00, 0xff, 0xff).<\/em>.<\/p>\n<p><\/p>\n<p>Kokkuv\u00f5ttes saab olemasolevate testandmete p\u00f5hjal mahtuda alla 250 KB komprimeeritud andmeid.<\/p>\n<p><\/p>\n<p>Saame veel veidi kokku hoida, tegeledes bittide jongleerimisega: praegu ignoreerime bloki l\u00f5pus mitme nullbiti olemasolu, samuti ei muutu m\u00f5ned bitid bloki alguses\u2026<br \/>\nAga siin tegin ma tahteotsuse l\u00f5petada, muidu v\u00f5iksin sellise tempoga enda arhivaatori arendamiseni j\u00f5uda.<\/p>\n<p><\/p>\n<p>Kokkuv\u00f5ttes sain oma testandmetest 3\u20134 baiti salvestuse kohta, tihendamise suhe oli \u00fcle 6:1. Pean ausalt tunnistama, et ei oodanud sellist tulemust; minu arvates on k\u00f5ik, mis on parem kui 2:1, juba tulemuseks, mis \u00f5igustab tihendamise kasutamist.<\/p>\n<p><\/p>\n<p>K\u00f5ik on suurep\u00e4rane, kuid zlib (deflate) on siiski aegunud, v\u00e4\u00e4rikas ja veidi vanamoodne tihendamisalgoritm. \u00dcksnes see, et s\u00f5nastikuks kasutatakse viimaseid 32 Kb tihendamata andmete voost, tundub t\u00e4nap\u00e4eval kummaline (st kui m\u00f5ni andmeplokk on v\u00e4ga sarnane sellele, mis oli sisendis 40 Kb tagasi, siis hakkab see uuesti arhiveerima, mitte ei viita eelmisele esinemisele). Moodsa arhiveerimise tarkvara puhul m\u00f5\u00f5detakse s\u00f5nastiku suurust tihti megabaitides, mitte kilobaitides.<\/p>\n<p><\/p>\n<p>Nii et j\u00e4tkame meie mini-uuringut arhiveerimiste kohta.<\/p>\n<p><\/p>\n<p>J\u00e4rgmine proovitud oli bzip2 (meenutan, et ilma FLUSHita n\u00e4itas see fantastilist tihendamise taset, peaaegu 100:1). Kahjuks FLUSHiga n\u00e4itas see end v\u00e4ga halvasti, tihendatud andmete suurus osutus suuremaks kui tihendamata andmete suurus.<\/p>\n<p>\n<b class=\"spoiler_title\">Minu oletused ebaedukuse p\u00f5hjustest<\/b><\/p>\n<p>Libbz2 pakub ainult \u00fchte flush varianti, mis n\u00e4ib kustutavat s\u00f5nastiku (sarnane Z_FULL_FLUSH-ile zlib-s), peale selle on raske r\u00e4\u00e4kida mingist t\u00f5husast tihendamisest.<\/p>\n<p><\/p>\n<p>Viimaseks prooviti zstd. S\u00f5ltuvalt seadistustest suudab see tihendada kas gzip tasemel, kuid palju kiiremini, v\u00f5i isegi paremini kui gzip.<\/p>\n<p><\/p>\n<p>Kahjuks ei m\u00f5junud FLUSH h\u00e4sti: kokkusurutud andmete suurus oli umbes 700Kb.<\/p>\n<p><\/p>\n<p>Mina <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/facebook\/zstd\/issues\/900\">esitasin k\u00fcsimuse<\/a><\/noindex> projekti lehelt githubis ja sain vastuseks, et v\u00f5iks arvestada umbes 10 baiti haldusteavet iga tihendatud andmeploki kohta, mis on l\u00e4hedane saadud tulemusele, deflate\u2019i ei suuda kuidagi j\u00f5uda.<\/p>\n<p><\/p>\n<p>Sellega otsustasin arhiivimise katsetega l\u00f5petada (meeldetuletuseks, xz, lzip, lzo, lz4 ei n\u00e4idanud end veel FLUSH-ita testimise etapis h\u00e4sti, ja ma ei hakanud arvestama eksootilisemaid tihendusalgoritme).<\/p>\n<p><\/p>\n<p>Naaseme arhiivimise probleemide juurde.<\/p>\n<p><\/p>\n<p>Teine probleem (nagu \u00f6eldakse, j\u00e4rjekorra m\u00f5ttes, mitte t\u00e4henduses) seisneb selles, et tihendatud andmed kujutavad endast \u00fchtset voogu, kus pidevalt viidatakse varasematele osadele. Seega, kui mingi osa tihendatud andmetest saab kahjustada, kaotame mitte ainult sellega seotud mittetihendatud andmepaki, vaid ka k\u00f5ik j\u00e4rgnevad.<\/p>\n<p><\/p>\n<p>Selle probleemi lahendamiseks on mitmeid l\u00e4henemisviise:<\/p>\n<p><\/p>\n<ol>\n<li>Probleemi ilmnemise ennetamine \u2014 lisada tihendatud andmetesse \u00fcleliigset teavet, mis v\u00f5imaldab vigu tuvastada ja parandada; sellest r\u00e4\u00e4gime hiljem;<\/li>\n<li>Minimeerida tagaj\u00e4rgi, kui probleem siiski tekib.<br \/>\nOleme varem r\u00e4\u00e4kinud, et iga andmepaki saab tihendada iseseisvalt, sel juhul probleem ise kaob (\u00fche paketi andmete kahjustamine toob kaasa andmete kaotuse ainult selle paketi puhul). Kuid see on \u00e4\u00e4rmuslik juhtum, kus andmete tihendamine on ebaefektiivne. Teine \u00e4\u00e4rmus on kasutada k\u00f5iki 4 MB meie mikroskeemi \u00fcheks arhiiviks, mis annab meile suurep\u00e4rase tihenduse, kuid katastroofilised tagaj\u00e4rjed andmete kahjustumise korral.<br \/>\n<em>Jah, usaldusv\u00e4\u00e4rsuse osas on vajalik kompromiss. Kuid tuleb meeles pidada, et arendame andmete salvestamise formaati energiaefektiivsel m\u00e4lul, millel on \u00e4\u00e4rmiselt madal BER ja deklareeritud andmete s\u00e4ilitamise aeg 20 aastat.<\/em><\/li>\n<\/ol>\n<p><\/p>\n<p>Katsete k\u00e4igus avastasin, et m\u00e4rkimisv\u00e4\u00e4rsemad tihendustaseme kadumised algavad tihendatud andmeplokkide puhul, mille suurus on alla 10 Kb.<br \/>\nVarem mainiti, et kasutatav m\u00e4lu on leheorganisatsiooniga, ei n\u00e4e ma p\u00f5hjuseid, miks ei tohiks kasutada vastavust &#171;\u00fcks leht \u2014 \u00fcks kokkusurutud andmete plokk&#187;.<\/p>\n<p><\/p>\n<p>See t\u00e4hendab, et minimaalne m\u00f5istlik lehe suurus on 16 Kb (koos varuga teenindusteabe jaoks). Kuid nii v\u00e4ike lehe suurus seab olulisi piiranguid maksimaalse kirje suurusele.<\/p>\n<p><\/p>\n<p>Kuigi mul ei ole praegu ette n\u00e4htud kirjeid, mis \u00fcletaksid \u00fchte kilobaiti tihendatud kujul, otsustasin kasutada lehti, mille suurus on 32 Kb (kokku saab 128 lehte kiibi kohta).<\/p>\n<p><\/p>\n<p><strong>Kokkuv\u00f5te:<\/strong><\/p>\n<p><\/p>\n<ul>\n<li>Andmeid salvestame zlib (deflate) abil tihendatuna;<\/li>\n<li>Iga kirje puhul seadistame Z_SYNC_FLUSH;<\/li>\n<li>Iga tihendatud kirje l\u00f5pus k\u00e4rpime viimased baitid <em>(n\u00e4iteks 0x00, 0x00, 0xff, 0xff)<\/em>; pealkirjas n\u00e4itame, kui palju baite me eemaldame;<\/li>\n<li>Andmeid salvestatakse lehtedena, iga\u00fches 32 Kb; lehe sees on pidev surve all olevate andmete voog; iga lehe surumist alustame uuesti.<\/li>\n<\/ul>\n<p><\/p>\n<p>Ja enne, kui l\u00f5petame survet, soovin juhtida t\u00e4helepanu sellele, et meil on surutud andmeid vaid m\u00f5ned bait kirje kohta, seega on \u00e4\u00e4rmiselt oluline mitte paisutada teenindusteavet \u2013 iga bait on arvel.<\/p>\n<p><\/p>\n<h3 id=\"hranenie-zagolovkov-dannyh\">Andmepealkirjade hoidmine<\/h3>\n<p><\/p>\n<p>Kuna meil on muutliku pikkusega kirjed, peame kuidagi m\u00e4\u00e4rama asukoha\/piirid.<\/p>\n<p><\/p>\n<p>Ma tean kolme l\u00e4henemist:<\/p>\n<p><\/p>\n<ol>\n<li>K\u00f5ik kirjed hoitakse pidevas voos, alguses on kirje pealkiri, mis sisaldab pikkust, ja seej\u00e4rel tuleb ise kirje.<br \/>\nSelles variandis v\u00f5ivad nii pealkirjad kui andmed olla muutliku pikkusega.<br \/>\nSisuliselt on meil \u00fchekordne loend, mida kasutatakse laialdaselt;<\/li>\n<li>Pealkirjad ja ise kirjed hoitakse eraldi voogudes.<br \/>\nKasutades p\u00fcsiva pikkusega pealkirju, saavutame selle, et \u00fche pealkirja rike ei m\u00f5juta teisi.<br \/>\nSarnast l\u00e4henemist kasutatakse n\u00e4iteks paljudes failis\u00fcsteemides;<\/li>\n<li>Kirjed s\u00e4ilitatakse pidevas voos, kirje piirid m\u00e4\u00e4ratakse teatud m\u00e4rgise (s\u00fcmboli\/j\u00e4rjestuse, mis on andmeplokkides keelatud) j\u00e4rgi. Kui kirje sees on m\u00e4rk, asendame selle mingi j\u00e4rjestusega (p\u00f5genev).<br \/>\nSarnast l\u00e4henemist kasutatakse n\u00e4iteks PPP protokollis.<\/li>\n<\/ol>\n<p><\/p>\n<p>Illustreerime.<\/p>\n<p><\/p>\n<p>Variant 1:<br \/>\n<img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/e5a9676ca21eaca07e64ddf9fcd9f2eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSiin on k\u00f5ik v\u00e4ga lihtne: teades kirje pikkust, saame arvutada j\u00e4rgmise p\u00e4ise aadressi. Nii liigume p\u00e4iste kaudu, kuni leiame ala, mis on t\u00e4is 0xff (vabat ruumi) v\u00f5i lehe l\u00f5pu.<\/p>\n<p><\/p>\n<p>Variant 2:<br \/>\n<img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/4fed4860fb659ab6042be9aeeb5c041a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMuutuva kirje pikkuse t\u00f5ttu ei saa me eelnevalt \u00f6elda, kui palju kirjeid (ja seega ka pealkirju) lehte vajame. Saame pealkirjad ja andmed jaotada erinevatele lehtedele, kuid mulle meeldib teine l\u00e4henemine: paigutame pealkirjad ja andmed samale lehele, kuid pealkirjad (p\u00fcsiva suurusega) asuvad lehe alguses ja andmed (muutuva pikkusega) lehe l\u00f5pus. Niikaua kui nad 'kohtuvad' (vaba ruumi ei j\u00e4tku uue kirje jaoks) - loeme selle lehe t\u00e4idetuks.<\/p>\n<p><\/p>\n<p>Variant 3:<br \/>\n<img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/dfb64009aa7781fcb8a47423ff4160c6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSiin pole vaja pealkirjas salvestada andmete pikkust v\u00f5i muud asukoha teavet, piisab m\u00e4rkidest, mis t\u00e4histavad kirje piire. Kuid andmeid tuleb t\u00f6\u00f6tleda kirjutamisel \/ lugemisel.<br \/>\nM\u00e4rgina v\u00f5iksin kasutada 0xff (millega leht p\u00e4rast kustutamist t\u00e4idetakse), nii et vaba ala ei t\u00f5lgendataks andmetena.<\/p>\n<p><\/p>\n<p>V\u00f5rdlustabel:<\/p>\n<p><\/p>\n<p>Valik 1<br \/>\nVariant 2<br \/>\nVariant 3<\/p>\n<p><strong>Vigadele vastupidavus<\/strong><br \/>\n&#8212;<br \/>\n+<br \/>\n+<\/p>\n<p><strong>Kompaktsus<\/strong><br \/>\n+<br \/>\n&#8212;<br \/>\n+<\/p>\n<p><strong>Teostamise keerukus<\/strong><br \/>\n*<br \/>\n**<br \/>\n**<\/p>\n<p><\/p>\n<p>Variant 1l on kriitiline puudus: kui m\u00f5ni pealkiri on kahjustatud, h\u00e4vitatakse kogu j\u00e4rgneva ahela. \u00dclej\u00e4\u00e4nud variandid v\u00f5imaldavad taastada osa andmeid isegi massiliste kahjustuste korral.<br \/>\nSiinkohal on paslik meenutada, et otsustasime andmeid hoida kompressitud kujul, nii et me kaotame k\u00f5ik lehe andmed p\u00e4rast 'katki' kirjet, seega, kuigi tabelis on miinus, ei arvestata seda.<\/p>\n<p><\/p>\n<p>Kompaktsus:<\/p>\n<p><\/p>\n<ul>\n<li>esimeses variantis peame pealkirjas salvestama ainult pikkuse, kui kasutada muutuva pikkusega t\u00e4isarve, siis enamikul juhtudel saame hakkama \u00fche baitiga.<\/li>\n<li>teises versioonis peame salvestama algse aadressi ja pikkuse; salvestus peab olema p\u00fcsiva suurusega, hindan seda 4 baitiks salvestuse kohta (kaks baiti nihke jaoks ja kaks baiti pikkuse jaoks);<\/li>\n<li>kolmandale versioonile piisab vaid \u00fchest t\u00e4hest salvestuse alguse t\u00e4histamiseks, pluss ise salvestus kasvab t\u00e4nu eskaleerimisele 1-2%. \u00dcldiselt on see esimesega enam-v\u00e4hem v\u00f5rdsed.<\/li>\n<\/ul>\n<p><\/p>\n<p>Alguses pidasin teist versiooni p\u00f5hiversiooniks (ja isegi kirjutasin rakenduse). L\u00f5petasin selle kasutamise vaid siis, kui otsustasin l\u00f5plikult kasutada kompressiooni.<\/p>\n<p><\/p>\n<p><em>V\u00f5ib-olla \u00fchel p\u00e4eval kasutan ma sedalaadi lahendust. N\u00e4iteks, kui pean tegema andmete salvestamist laeva jaoks, mis s\u00f5idab Maa ja Marsi vahel - n\u00f5uded usaldusv\u00e4\u00e4rsusele on t\u00e4iesti teised, kosmiline kiirgus, ...<\/em><\/p>\n<p><\/p>\n<p>Mis puutub kolmandasse versiooni: andsin sellele kaks t\u00e4rni rakendamise keerukuse t\u00f5ttu, lihtsalt seet\u00f5ttu, et ma ei armasta tegeleda eskaleerimise, pikkuse muutmise jms. Jah, see v\u00f5ib olla kallutatud, kuid koodi pean kirjutama mina \u2014 miks sundida end tegema seda, mis ei meeldiv.<\/p>\n<p><\/p>\n<p><strong>Kokkuv\u00f5te:<\/strong> Valime salvestusvariandi, mis koosneb ahelatest 'pealkiri koos pikkusega - muutuva pikkusega andmed' efektiivsuse ja lihtsa teostuse t\u00f5ttu.<\/p>\n<p><\/p>\n<h3 id=\"ispolzovanie-bitovyh-poley-dlya-kontrolya-uspeshnosti-operaciy-zapisi\">Bitiv\u00e4ljade kasutamine kirjutamise operatsioonide eduka tulemuse j\u00e4lgimiseks<\/h3>\n<p><\/p>\n<p>Ma ei m\u00e4leta enam, kust ma selle idee sain, kuid see n\u00e4eb v\u00e4lja enam-v\u00e4hem nii:<br \/>\nIga kirje jaoks eraldame mitu bitti lipu salvestamiseks.<br \/>\n<em>K\u00e4esoleva r\u00e4\u00e4gitud juhendiga t\u00e4idetakse k\u00f5ik bitid p\u00e4rast erase'it 1'ga, ja me saame muuta 1 0'ks, kuid mitte vastupidi.<\/em> Seega, 'lipp ei ole seadistatud' korral kasutame 1, 'lipp on seadistatud' korral - 0.<\/p>\n<p><\/p>\n<p>Nii v\u00f5ib v\u00e4lja n\u00e4ha muutuva pikkusega kirje salvestamine flash-m\u00e4lus:<\/p>\n<p><\/p>\n<ol>\n<li>Seame lipu \u201ekirje pikkuse salvestamine algas\u201c;<\/li>\n<li>Salvestame pikkuse;<\/li>\n<li>Seame lipu \u201eandmete salvestamine algas\u201c;<\/li>\n<li>Salvestame andmed;<\/li>\n<li>Seame lipu \u201esalvestamine l\u00f5ppes\u201c.<\/li>\n<\/ol>\n<p><\/p>\n<p>Lisaks on meil lipp \u201et\u00f5rge toimus\u201c, kokku 4 bitilippu.<\/p>\n<p><\/p>\n<p>Sel juhul on meil kaks stabiilset olekut \u201e1111\u201c \u2014 kirjutamine ei ole alanud ja \u201e1000\u201c \u2014 kirjutamine l\u00e4ks edukalt; etten\u00e4gematu katkestuse korral saame vahepealsed olekud, mida saame hiljem tuvastada ja t\u00f6\u00f6delda.<\/p>\n<p><\/p>\n<p>L\u00e4htekoht on huvitav, kuid see kaitseb ainult ootamatute toitekatkestuste ja sarnaste rike eest, mis on loomulikult oluline, kuid see ei ole sugugi ainus (ja isegi mitte peamine) v\u00f5imalike rikke p\u00f5hjuste r\u00fchm.<\/p>\n<p><\/p>\n<p><strong>Kokkuv\u00f5te:<\/strong> Liigume edasi head lahendust otsides.<\/p>\n<p><\/p>\n<h3 id=\"kontrolnye-summy\">Kontrollsummad<\/h3>\n<p><\/p>\n<p>Kontrollsummad annavad samuti v\u00f5imaluse veenduda (piisava t\u00f5en\u00e4osusega) selles, et loeme t\u00e4pselt seda, mis oli kirjutatud. Ja erinevalt eespool k\u00e4sitletud bitiv\u00e4ljadest t\u00f6\u00f6tavad need alati.<\/p>\n<p><\/p>\n<p>Kui vaatlen eeltoodud v\u00f5imalike probleemiallikate loetelu, siis kontrollsummad suudavad t\u00f5deda viga, s\u00f5ltumata selle allikast. <em>(v.a. v\u00f5ib-olla pahatahtlikud tulnukad \u2014 nemad v\u00f5ivad ka kontrollsummasid v\u00f5ltsida)<\/em>.<\/p>\n<p><\/p>\n<p>Nii et kui meie eesm\u00e4rk on kontrollida, et andmed on terved, on kontrollsummad suurep\u00e4rane idee.<\/p>\n<p><\/p>\n<p>Kontrollsummade arvutamise algoritmi valik ei tekitanud k\u00fcsimusi \u2014 CRC. \u00dchelt poolt v\u00f5imaldavad matemaatilised omadused 100%-liselt tuvastada teatud t\u00fc\u00fcpi vigu, teisest k\u00fcljest n\u00e4itab see algoritm juhuslike andmete puhul tavaliselt kokkulangevuste t\u00f5en\u00e4osust, mis ei ole oluliselt k\u00f5rgem teoreetilisest piirist. <img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/bf9cca3564db7d9d03d3ce49642d3a71.jpg\" style=\"display:block;margin: 0 auto;\" \/>. Kuigi see ei ole k\u00f5ige kiirem algoritm ega alati minimaalne kokkulangevuste arvu poolest, on sellel \u00fcks v\u00e4ga oluline omadus: testides, millega ma olen kokku puutunud, ei ole olnud mustreid, kus see selgelt eba\u00f5nnestuks. Stabiilsus on antud juhul k\u00f5ige olulisem omadus.<\/p>\n<p><\/p>\n<p>Mahuka uuringu n\u00e4ide: <noindex><a rel=\"nofollow\" href=\"http:\/\/amsoftware.narod.ru\/algo.html\">osa 1<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"http:\/\/amsoftware.narod.ru\/algo2.html\">osa 2<\/a><\/noindex> <em>(linkid narod.ru, vabandust)<\/em>.<\/p>\n<p><\/p>\n<p>Siiski ei ole kontrollsumma valimise \u00fclesanne veel lahendatud, CRC on terve kontrollsummade perekond. Tuleb otsustada pikkuse \u00fcle ja seej\u00e4rel valida pol\u00fc\u00fcm.<\/p>\n<p><\/p>\n<p>Kontrollsumma pikkuse valik ei ole nii lihtne k\u00fcsimus, nagu see esmapilgul paistab.<\/p>\n<p><\/p>\n<p>Ilustreerin:<br \/>\nOletame, et meil on vigade t\u00f5en\u00e4osus igas baitis <img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/89a9be2edf2a43cc9115eba37fa02fc8.jpg\" style=\"display:block;margin: 0 auto;\" \/> ja ideaalne kontrollsumma, arvutame keskmise vigade arvu miljoni kirje kohta:<\/p>\n<p><\/p>\n<p>Andmed, bait<br \/>\nKontrollsumma, bait<br \/>\nUnustatud vead<br \/>\nValevea tuvastamised<br \/>\nVale valeiduste kogus<\/p>\n<p>1<br \/>\n0<br \/>\n1000<br \/>\n0<br \/>\n1000<\/p>\n<p>1<br \/>\n1<br \/>\n4<br \/>\n999<br \/>\n1003<\/p>\n<p>1<br \/>\n2<br \/>\n\u22480<br \/>\n1997<br \/>\n1997<\/p>\n<p>1<br \/>\n4<br \/>\n\u22480<br \/>\n3990<br \/>\n3990<\/p>\n<p>10<br \/>\n0<br \/>\n9955<br \/>\n0<br \/>\n9955<\/p>\n<p>10<br \/>\n1<br \/>\n39<br \/>\n990<br \/>\n1029<\/p>\n<p>10<br \/>\n2<br \/>\n\u22480<br \/>\n1979<br \/>\n1979<\/p>\n<p>10<br \/>\n4<br \/>\n\u22480<br \/>\n3954<br \/>\n3954<\/p>\n<p>1000<br \/>\n0<br \/>\n632305<br \/>\n0<br \/>\n632305<\/p>\n<p>1000<br \/>\n1<br \/>\n2470<br \/>\n368<br \/>\n2838<\/p>\n<p>1000<br \/>\n2<br \/>\n10<br \/>\n735<br \/>\n745<\/p>\n<p>1000<br \/>\n4<br \/>\n\u22480<br \/>\n1469<br \/>\n1469<\/p>\n<p><\/p>\n<p>Tundub lihtne \u2013 vali kontrollsummade pikkus vastavalt kaitstava teabe pikkusele, hoides valeandmete arvu miinimumis, ja asi on klaar.<\/p>\n<p><\/p>\n<p>Kuid l\u00fchikeste kontrollsummadega on probleem: need tuvastavad k\u00fcll \u00fcksikuid bitivigu h\u00e4sti, kuid v\u00f5ivad suure t\u00f5en\u00e4osusega aktsepteerida t\u00e4iesti suvalisi andmeid \u00f5igetena. Habr\u00e9 oli juba artikel, mis k\u00e4sitles <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/428746\/\">probleemi reaalses elus<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Seet\u00f5ttu, et kontrollsummade juhuslikku kokkulangemist praktiliselt v\u00e4ltida, tuleb kasutada v\u00e4hemalt 32-bitiseid kontrollsummasid <em>(pikkuste jaoks \u00fcle 64 bitti kasutatakse tavaliselt kr\u00fcptograafilisi r\u00e4sifunktsioone)<\/em>.<\/p>\n<p><\/p>\n<p>Kuigi olen varem \u00f6elnud, et ruumi tuleb hoida igas v\u00f5imalikus viisis, kasutame siiski 32-bitist kontrollsummat (16 biti on liiga v\u00e4he, kokkulanguse t\u00f5en\u00e4osus on \u00fcle 0,01%; ja 24 bitti, nagu \u00f6eldakse, ei ole ei siia ega sinna).<\/p>\n<p><\/p>\n<p>Siin v\u00f5ib tekkida vastuv\u00e4ide: kas me ikka s\u00e4\u00e4stsime iga bait kompresseerimise valimisel, et n\u00fc\u00fcd kohe 4 baidi jagu andmeid anda? Kas ei oleks parem mitte kompresseerida ja mitte lisada kontrollsummat? Loomulikult mitte, kompressiooni puudumine <em>ei t\u00e4henda<\/em>, et me ei vaja terviklikkuse kontrolli.<\/p>\n<p><\/p>\n<p>Pol\u00fcnoomi valikul ei hakka me ratast uuesti leiutama, vaid v\u00f5tame praegu populaarse CRC-32C.<br \/>\nSee kood tuvastab 6 bitiviga pakettide puhul, mille pikkus on kuni 22 baiti (ilmselt k\u00f5ige levinum juhtum meie jaoks), 4 bitiviga pakettide puhul pikkusega kuni 655 baiti (ka \u00fcsna tavaline meie seas), 2 v\u00f5i mis tahes paaritu arvu bitiviga pakettide puhul suvalise m\u00f5istliku pikkusega.<\/p>\n<p>\n<b class=\"spoiler_title\">Kui kedagi huvitavad \u00fcksikasjad<\/b><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cyclic_redundancy_check\">Wikipediast leiate<\/a><\/noindex> artikkli CRC-st.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/users.ece.cmu.edu\/~koopman\/crc\/c32\/0x8f6e37a0_len.txt\">CRC-32C koodiparameetrid<\/a><\/noindex> j\u00e4rgnevaga <noindex><a rel=\"nofollow\" href=\"http:\/\/users.ece.cmu.edu\/~koopman\/crc\/notes.html\">Kopmani saidil<\/a><\/noindex> \u2013 ilmselt maailma juhtiv ekspert CRC alal.<\/p>\n<p><\/p>\n<p>V <noindex><a rel=\"nofollow\" href=\"http:\/\/users.ece.cmu.edu\/~koopman\/networks\/dsn02\/dsn02_koopman.pdf\">tema artiklis<\/a><\/noindex> has <noindex><a rel=\"nofollow\" href=\"https:\/\/users.ece.cmu.edu\/~koopman\/crc\/c32\/0xfa567d89_len.txt\">veel \u00fcks huvitav kood<\/a><\/noindex>, mis tagab pisut paremad parameetrid meie jaoks asjakohaste pikkade pakettide jaoks, kuid ma ei pea vahet t\u00e4htsaks ja arvan end piisavalt p\u00e4devaks, et valida kohandatud kood standardse ja h\u00e4sti uuritud koodi asemel.<\/p>\n<p><\/p>\n<p>Veelgi enam, kuna meie andmed on kokku pressitud, tekib k\u00fcsimus: arvutada kontrollsumma pressitud v\u00f5i dekompressitud andmete p\u00f5hjal?<\/p>\n<p><\/p>\n<p>Argumente 'poolt' kontrollsummade arvestamise kohta kompressimata andmete osas:<\/p>\n<p><\/p>\n<ul>\n<li>me peame l\u00f5puks kontrollima andmete s\u00e4ilitamise korrektsust \u2014 just seda me otse kontrollime (samuti kontrollitakse v\u00f5imalikke vigu tihendamise\/dekompressiooni teostuses, kahjustusi, mis on p\u00f5hjustatud samuti m\u00e4lu vigadest jne);<\/li>\n<li>algoritm deflate zlib'is on piisavalt k\u00fcps ja <em>ei tohiks<\/em> kukub 'k\u00f5verate' sisendandmete korral, peale selle suudab ta tihti iseseisvalt tuvastada vigu sisendvoos, v\u00e4hendades seel\u00e4bi vea avastamise t\u00f5en\u00e4osust (tegin testi \u00fche bitivahetuse korral l\u00fchikeses kirjes, zlib tuvastas vea umbes kolmandal juhul).<\/li>\n<\/ul>\n<p><\/p>\n<p>Argumente 'vastu' kontrollsummade arvestamise kohta kompressimata andmete osas:<\/p>\n<p><\/p>\n<ul>\n<li>CRC on 'teravdatud' t\u00e4pselt v\u00e4ikeste bitivigade jaoks, mis on iseloomulikud flash-m\u00e4lule (bitiviga kompressitud voos v\u00f5ib p\u00f5hjustada massilist v\u00e4ljundvoo muutust, mille puhul, teoreetiliselt, v\u00f5ime 'p\u00fc\u00fcdma' kolisiooni);<\/li>\n<li>mulle ei meeldi see m\u00f5te, et anda dekompressorile potentsiaalselt vigaseid andmeid, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.cvedetails.com\/vulnerability-list\/vendor_id-72\/product_id-1820\/GNU-Zlib.html\">kes teab<\/a><\/noindex>, kuidas ta reageerib.<\/li>\n<\/ul>\n<p><\/p>\n<p>Selles projektis otsustasin ma k\u00f5rvale hiilida \u00fcldiselt aktsepteeritud praktikast, mille kohaselt s\u00e4ilitatakse kontrollsummad kokku surutud andmete suhtes.<\/p>\n<p><\/p>\n<p><strong>Kokkuv\u00f5te:<\/strong> kasutame CRC-32C, kontrollsummat arvutame andmete p\u00f5hjal sellises vormis, nagu need kirjutatakse flash-m\u00e4ele (p\u00e4rast tihendamist).<\/p>\n<p><\/p>\n<h3 id=\"izbytochnost\">\u00dcksikasjalikkus<\/h3>\n<p><\/p>\n<p>Liigne kodeerimine ei suuda muidugi t\u00e4ielikult v\u00e4listada andmete kadumise, kuid see v\u00f5ib oluliselt (tihti palju korda) v\u00e4hendada taastamatute andmekao t\u00f5en\u00e4osust.<\/p>\n<p><\/p>\n<p>Saame kasutada erinevaid liigsuse vorme, et vigu parandada.<br \/>\nHammingi koodid suudavad parandada \u00fcksikute bitivigu, Reed-Solomoni koodid on s\u00fcmboolsed, mitmed andmekoopiad koos kontrollsummadega v\u00f5i sellised kodeerimised nagu RAID-6 v\u00f5ivad aidata andmeid taastada isegi massiliste kahjustuste korral.<br \/>\nAlguses olin ma kaldunud kasutama laialdaselt vigadele vastupanuvates kodeeringutes, kuid siis sain aru, et k\u00f5igepealt tuleb m\u00f5ista, milliste vigade eest me tahame end kaitsta, ja seej\u00e4rel valida kodeerimine.<\/p>\n<p><\/p>\n<p>Oleme varem r\u00e4\u00e4kinud, et vigu tuleb tuvastada v\u00f5imalikult kiiresti. Millistel hetkedel v\u00f5ime vigadega silmitsi seista?<\/p>\n<p><\/p>\n<ol>\n<li>L\u00f5petamata kirje (m\u00f5nel p\u00f5hjusel, n\u00e4iteks kui salvestamise hetkel l\u00e4ks vool \u00e4ra, Raspberry hangus, ...)<br \/>\nKahjuks ei j\u00e4\u00e4 sellise vea korral muud \u00fcle, kui eirata mittesobivaid salvestusi ja pidada andmeid kadunuks;<\/li>\n<li>Salvestusvead (mingil p\u00f5hjusel salvestati v\u00e4lkm\u00e4lusse mitte see, mis oli salvestatud)<br \/>\nSelliseid vigu saame kohe tuvastada, kui teeme p\u00e4rast salvestamist kontrollimise;<\/li>\n<li>Andmete moonutamine m\u00e4lus s\u00e4ilitamise k\u00e4igus;<\/li>\n<li>Lugemisvead<br \/>\nVea parandamiseks piisab juhtumite korral, kus kontrollsummad ei kattu, lugemise kordamisest mitu korda.<\/li>\n<\/ol>\n<p><\/p>\n<p>See t\u00e4hendab, et ainult kolmanda t\u00fc\u00fcbi vead (andmete juhuslik riknemine s\u00e4ilitamise ajal) ei saa olla parandatud ilma vigadele vastupidava kodeerimiseta. Tundub, et sellised vead on siiski \u00e4\u00e4rmiselt ebat\u00f5en\u00e4olised.<\/p>\n<p><\/p>\n<p><strong>Kokkuv\u00f5te:<\/strong> Otsustati loobuda liigsest kodeerimisest, kuid kui kasutus t\u00f5estab, et see otsus on vale, naeratame selle k\u00fcsimuse juurde tagasi (koos juba kogutud statistika rikkumistest, mis v\u00f5imaldab valida parima kodeerimise variandi).<\/p>\n<p><\/p>\n<h3 id=\"prochee\">Muud<\/h3>\n<p><\/p>\n<p>Muidugi ei v\u00f5imalda artikli formaat p\u00f5hjendada iga bitti formaadis. <em>(ja mul on juba j\u00f5ud otsas)<\/em>, seega l\u00e4hen kiiresti \u00fcle m\u00f5ningatele punktidele, millest varem ei r\u00e4\u00e4gitud.<\/p>\n<p><\/p>\n<ul>\n<li>Otsustatud on teha k\u00f5ik lehed 'v\u00f5rdseteks'<br \/>\nSee t\u00e4hendab, et ei tule mingisuguseid spetsiaalseid lehti metaandmete, eraldiseisvate voogude jne jaoks; selle asemel on \u00fcksainus voog, mis kirjutab k\u00f5ik lehed j\u00e4rjest.<br \/>\nSee tagab lehtede \u00fchtlase kulumise, puudumise ainsast rikkepunktist ning lihtsalt meeldib;<\/li>\n<li>Kindlasti tuleb arvestada formaadi versioonidega.<br \/>\nFormaadi versiooninumbrita p\u00e4ises on kurjast!<br \/>\nPiisab, kui lisada lehe p\u00e4isesse v\u00e4li koos mingi Magic Number'iga (signatuur), mis n\u00e4itab kasutatavat formaadi versiooni <em>(ma ei arva, et neid praktiliselt rohkem kui tosin oleks)<\/em>;<\/li>\n<li>Kasutada kirjete jaoks (mida on v\u00e4ga palju) muutliku pikkusega pealkirju, p\u00fc\u00fcdes enamikus juhtudest hoida nende pikkus 1 bait;<\/li>\n<li>Pealkirja pikkuse ja k\u00e4rpimise osa pikkuse kodeerimiseks kasutada muutliku pikkusega binaarkoodisid.<\/li>\n<\/ul>\n<p><\/p>\n<p>Oli v\u00e4ga abiks <noindex><a rel=\"nofollow\" href=\"https:\/\/planetcalc.com\/2481\/\">veebigeneraator<\/a><\/noindex> Huffman\u2019i koode. Ainus minutitega suutsime leida vajalikud muutliku pikkusega koodid.<\/p>\n<p><\/p>\n<h1 id=\"anchorformatanchoropisanie-formata-hraneniya-dannyh\"><noindex><a rel=\"nofollow\" name=\"format\"><\/a><\/noindex>Andmete salvestamise formaadi kirjeldus<\/h1>\n<p><\/p>\n<h2 id=\"byte-order\">Baiti j\u00e4rjekord<\/h2>\n<p><\/p>\n<p>V\u00e4ljad, mille suurus \u00fcletab \u00fche bait, salvestatakse big-endian formaadis (v\u00f5rgubaiti j\u00e4rjekord), st 0x1234 salvestatakse kui 0x12, 0x34.<\/p>\n<p><\/p>\n<h2 id=\"delenie-na-stranicy\">Lehek\u00fclgede jagamine<\/h2>\n<p><\/p>\n<p>K\u00f5ik v\u00e4lkm\u00e4lu on jagatud v\u00f5rdse suurusega lehekesteks.<\/p>\n<p><\/p>\n<p>Lehekese vaikimisi suurus on 32KB, kuid mitte rohkem kui 1\/4 kogu m\u00e4lukiibi suurusest (4MB kiibi puhul on see 128 lehekest).<\/p>\n<p><\/p>\n<p>Iga lehek\u00fclg salvestab andmeid s\u00f5ltumatult teistest (t\u00fchikud \u00fche lehek\u00fclje andmed ei viita teistele lehek\u00fclgede andmetele).<\/p>\n<p><\/p>\n<p>K\u00f5ik lehek\u00fcljed on nummerdatud loomulikus j\u00e4rjekorras (aadresside t\u00f5usvas j\u00e4rjekorras), alustades numbrist 0 (null lehek\u00fclg algab aadressilt 0, esimene 32KB-lt, teine 64KB-lt jne).<\/p>\n<p><\/p>\n<p>M\u00e4lu kiip kasutatakse ts\u00fcklilise puhvrina (ring buffer), st k\u00f5igepealt kirjutatakse lehek\u00fcljele number 0, siis lehek\u00fcljele number 1, ..., kui t\u00e4idame viimast lehte, algab uus ts\u00fckkel ja kirjutamine j\u00e4tkub nulllehelt.<\/p>\n<p><\/p>\n<h2 id=\"vnutri-stranicy\">Lehek\u00fclje sees<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/39b45f83dc46bb2fd7081ed2a0b638c9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLehe alguses hoitakse 4-baidist lehe pealkirja, seej\u00e4rel pealkirja kontrollsummat (CRC-32C), seej\u00e4rel hoitakse kirjeid formaadis \u00abpealkiri, andmed, kontrollsumma\u00bb.<\/p>\n<p><\/p>\n<p>Lehe pealkiri (roheline-baar) koosneb:<\/p>\n<p><\/p>\n<ul>\n<li>kahebytesest Magic Number (see on ka formaadi versiooni t\u00e4his)<br \/>\npraeguse formaadi versioon on defineeritud kui <code>0xed00 \u2295 lehe number<\/code>;<\/li>\n<li>kahebaidist arvestist \u00abLehe versioon\u00bb (m\u00e4lus \u00fcmberkirjutamise ts\u00fckli number).<\/li>\n<\/ul>\n<p><\/p>\n<p>Lehe kirjeldused on salvestatud kompressioonivormingus (kasutatakse deflate algoritmi). K\u00f5ik kirjeldused \u00fchel lehel kompressitakse \u00fches voos (kasutatakse \u00fchte \u00fcldist s\u00f5nastikku), iga uue lehe puhul algab kompressioon uuesti. Seega, et dekompressida mistahes kirje, on vajalikud k\u00f5ik varasemad kirjed sellest lehelt (ja ainult sellest).<\/p>\n<p><\/p>\n<p>Iga kirje kompressitakse Z_SYNC_FLUSH lipuga, mille tulemusena kompressioonivoo l\u00f5ppu satub 4 baiti 0x00, 0x00, 0xff, 0xff, millele v\u00f5ivad eelnevalt j\u00e4rgneb \u00fche v\u00f5i kahe null-bait.<br \/>\nSee j\u00e4rjekord (pikkusega 4, 5 v\u00f5i 6 bitti) eemaldatakse meeldej\u00e4tmise ajal.<\/p>\n<p><\/p>\n<p>Kirje pealkiri koosneb 1, 2 v\u00f5i 3 baitist, mis sisaldavad:<\/p>\n<p><\/p>\n<ul>\n<li>\u00fcht bitti (T), mis n\u00e4itab kirje t\u00fc\u00fcpi: 0 \u2014 kontekst, 1 \u2014 ajakiri;<\/li>\n<li>muutuva pikkusega v\u00e4li (S) vahemikus 1 kuni 7 bitti, mis m\u00e4\u00e4rab pealkirja ja \u00absabade\u00bb pikkuse, mida tuleb kirjele lisada dekompressimiseks;<\/li>\n<li>kirje pikkus (L).<\/li>\n<\/ul>\n<p><\/p>\n<p>S v\u00e4\u00e4rtuste tabel:<\/p>\n<p><\/p>\n<p>S<br \/>\nPealkirja pikkus, baitides<br \/>\nKirjutamisel j\u00e4etakse k\u00f5rvale, baitides<\/p>\n<p><code>0<\/code><br \/>\n1<br \/>\n5 (<code>00 00 00 ff ff<\/code>)<\/p>\n<p><code>10<\/code><br \/>\n1<br \/>\n6 (<code>00 00 00 00 ff ff<\/code>)<\/p>\n<p><code>110<\/code><br \/>\n2<br \/>\n4 (<code>00 00 ff ff<\/code>)<\/p>\n<p><code>1110<\/code><br \/>\n2<br \/>\n5 (<code>00 00 00 ff ff<\/code>)<\/p>\n<p><code>11110<\/code><br \/>\n2<br \/>\n6 (<code>00 00 00 00 ff ff<\/code>)<\/p>\n<p><code>1111100<\/code><br \/>\n3<br \/>\n4 (<code>00 00 ff ff<\/code>)<\/p>\n<p><code>1111101<\/code><br \/>\n3<br \/>\n5 (<code>00 00 00 ff ff<\/code>)<\/p>\n<p><code>1111110<\/code><br \/>\n3<br \/>\n6 (<code>00 00 00 00 ff ff<\/code>)<\/p>\n<p><\/p>\n<p>P\u00fc\u00fcdsin illustreerida, ei tea, kui selgelt see v\u00e4lja tuli:<br \/>\n<img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/8c9b739eec5af4429395c32b4ba4044a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nKollasega on t\u00e4histatud T v\u00e4li, valgega S v\u00e4li, rohelisega L (kompressitud andmete pikkus baitides), sinisega kompressitud andmed, punasega l\u00f5ppbaitide kompressitud andmetest, mida ei kirjutata v\u00e4lkm\u00e4llu.<\/p>\n<p><\/p>\n<p>Seega saame enim levinud pikkusega kirjeid (kuni 63+5 baiti kompressitud kujul) kirjutada \u00fche baitiga.<\/p>\n<p><\/p>\n<p>Iga kirje j\u00e4rel hoitakse CRC-32C kontrollsummat, mille algv\u00e4\u00e4rtusena (init) kasutatakse eelneva kontrollsummat p\u00f6\u00f6rdv\u00e4\u00e4rtust.<\/p>\n<p><\/p>\n<p><em>CRC-l on \u00abkestvuse\u00bb omadus, toimib (pluss-miinus bittide p\u00f6\u00f6ramine protsessi k\u00e4igus) selline valem: <img decoding=\"async\" alt=\"Minu NOR flash&#039;i ringbuferi rakendus\" src=\"\/wp-content\/uploads\/2019\/12\/b194d6a3d18ae2f4ae5d4054a93c0ea3.jpg\" style=\"display:block;margin: 0 auto;\" \/>.<br \/>\nEhk tegelikult arvutame CRC k\u00f5igist eelnevatest baitidest pealkirjades ja andmetes sellel lehel.<\/em><\/p>\n<p><\/p>\n<p>Otse kontrollsummast j\u00e4rgneb j\u00e4rgmise kirje pealkiri.<\/p>\n<p><\/p>\n<p>Pealkiri on konstrueeritud nii, et selle esimene bait oleks alati erinev 0x00-st ja 0xff-st (kui pealkirja esimene bait on 0xff, t\u00e4hendab see, et see on praegu kasutamata ala; 0x00 signaalib viga).<\/p>\n<p><\/p>\n<h2 id=\"primernye-algoritmy\">Umbes algoritmid<\/h2>\n<p><\/p>\n<h3 id=\"chtenie-iz-flesh-pamyati\">Lugemine flash-m\u00e4lust<\/h3>\n<p><\/p>\n<p>Iga lugemine toimub kontrollsummaga.<br \/>\nKui kontrollsumma ei \u00fchti \u2013 loetakse andmeid mitu korda, lootes siiski \u00f5igeid andmeid lugeda.<\/p>\n<p><\/p>\n<p><em>(see on m\u00f5ttekas, Linux ei m\u00e4\u00e4ra NOR Flash'i lugemise vahem\u00e4lu, on t\u00f5estatud)<\/em><\/p>\n<p><\/p>\n<h3 id=\"zapis-v-flesh-pamyat\">Kirjutamine flash-m\u00e4llu<\/h3>\n<p><\/p>\n<p>Kirjutame andmed.<br \/>\nLugeme need.<\/p>\n<p><\/p>\n<p>Kui loetud andmed ei \u00fchti kirjutatud andmetega \u2013 t\u00e4idame ala nullidega ja signaalime vea.<\/p>\n<p><\/p>\n<h3 id=\"podgotovka-novoy-mikroshemy-k-rabote\">Uue mikroskeemi t\u00f6\u00f6ks ettevalmistamine<\/h3>\n<p><\/p>\n<p>Initsialiseerimiseks kirjutatakse esimese (tegelikult nullenda) lehek\u00fclje algusse pealkiri versiooniga 1.<br \/>\nP\u00e4rast seda kirjutatakse sellesse lehek\u00fclge algne kontekst (sisaldab automaadi UUID-d ja vaikeseadeid). <\/p>\n<p><\/p>\n<p>K\u00f5ik, flash-m\u00e4lu on t\u00f6\u00f6ks valmis.<\/p>\n<p><\/p>\n<h3 id=\"zagruzka-avtomata\">Automaatlaadimine<\/h3>\n<p><\/p>\n<p>Laadimise ajal loetakse iga lehe esimesed 8 baiti (pealkiri + CRC), lehek\u00fcljed, millel on tundmatu Magic Number v\u00f5i vale CRC, j\u00e4etakse t\u00e4helepanuta.<br \/>\n\u00ab\u00f5igete\u00bb lehtede seast valitakse lehed maksimaalse versiooniga, neist v\u00f5etakse leht, millel on k\u00f5ige suurem number.<br \/>\nKantakse esimest kirjet, kontrollitakse CRC korrektsust, olemasolu flagi \u00abkonkreetne\u00bb. Kui k\u00f5ik on korras \u2014 see leht peetakse aktiivseks. Kui ei \u2014 p\u00f6\u00f6rdume tagasi eelmise juurde, kuni leiame \u00abelava\u00bb lehe.<br \/>\nleitud lehelt loeme k\u00f5ik kirjed, need, millel on \u00abkonkreetne\u00bb lipp, rakendame.<br \/>\nSalvestame zlib s\u00f5nastiku (see on vajalik selle lehe t\u00e4iendamiseks).<\/p>\n<p><\/p>\n<p>K\u00f5ik, laadimine on l\u00f5petatud, kontekst on taastatud, n\u00fc\u00fcd saab t\u00f6\u00f6tada.<\/p>\n<p><\/p>\n<h3 id=\"dobavlenie-zapisi-v-zhurnal\">Kirje lisamine ajakirja<\/h3>\n<p><\/p>\n<p>Surume kirje kokku \u00f5igete s\u00f5nastikuga, kasutades Z_SYNC_FLUSH. Kontrollime, kas kokkusurutud kirje mahub\u5f53\u524d\u9801.<br \/>\nKui see ei mahutu (v\u00f5i lehel olid CRC vead), alustame uut lehte (vt allpool).<br \/>\nKandke kirje ja CRC. Kui juhtub viga, alustame uut lehte.<\/p>\n<p><\/p>\n<h3 id=\"novaya-stranica\">Uus leht<\/h3>\n<p><\/p>\n<p>Valime vabade lehtede hulgast v\u00e4ikseima numbri (vaba leht on see, mille pealkirjas on vale kontrollsumm ja mille versioon on v\u00e4iksem kui praegune). Kui selliseid lehti pole, valime lehe, mille number on v\u00e4ikseim nendest, mille versioon on sama mis praegune.<br \/>\nTeeme valitud lehe erase. Kontrollime sisu 0xff-ga. Kui midagi on valesti, v\u00f5tame j\u00e4rgmise vaba lehe jne.<br \/>\nKustutatud lehe peale kirjutame pealkirja, esimeseks kirje on praegune konteksti seisund ja j\u00e4rgmiseks - kui see olemas, siis kirjutamata logikiri.<\/p>\n<p><\/p>\n<h1 id=\"primenimost-formata\">Formaatide rakendatavus<\/h1>\n<p><\/p>\n<p>Minu arvates on see hea formaat igasuguste rohkem-v\u00e4hem kokkut\u00f5mmatavate info voogude (lihtne tekst, JSON, MessagePack, CBOR, v\u00f5ib-olla protobuf) talletamiseks NOR Flashis.<\/p>\n<p><\/p>\n<p>Muidugi on formaat \u00abkohandatud\u00bb SLC NOR Flashi jaoks.<\/p>\n<p><\/p>\n<p>Seda ei tasu kasutada k\u00f5rge BER-iga meediate peal, nagu NAND v\u00f5i MLC NOR. <em>(Kas selline m\u00e4lu on \u00fcldse m\u00fc\u00fcgil? Olen kohanud viiteid ainult paranduskoode k\u00e4sitlevates t\u00f6\u00f6des.)<\/em>.<\/p>\n<p><\/p>\n<p>Veel enam, seda ei tasu kasutada seadmete puhul, millel on oma FTL: USB flash, SD, MicroSD jne. <em>(selle m\u00e4lu jaoks tegin formati lehe suurusega 512 bitti, iga lehe algusesse allkiri ja unikaalsed kirje numbrid \u2014 m\u00f5nikord \u00f5nnestus \u00abh\u00e4das\u00bb flashist lihtsa j\u00e4rjestikulise lugemisega k\u00f5ik andmed taastada)<\/em>.<\/p>\n<p><\/p>\n<p>S\u00f5ltuvalt \u00fclesannetest saab formaati ilma muudatusteta kasutada m\u00e4lupulkadel alates 128 Kb (16 Kb) kuni 1 Gb (128 Mb). Soovi korral saab seda kasutada ka suuremate mahutavustega kiipidel, kuid t\u00f5en\u00e4oliselt tuleb kohandada lehe suurust. <em>(Aga siin tuleb juba m\u00e4ngu majanduslik otstarbekus, NOR Flash suure mahutavusega hind ei r\u00f5\u00f5musta)<\/em>.<\/p>\n<p><\/p>\n<p>Kui keegi leiab formaadi huvitavaks ja soovib seda kasutada avatud projektis \u2014 kirjutage, p\u00fc\u00fcan leida aega koodi korrastamiseks ja githubi \u00fcleslaadimiseks.<\/p>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Kokkuv\u00f5te<\/h1>\n<p><\/p>\n<p>Nagu n\u00e4ha, on formaadist l\u00f5puks saanud lihtne <em>ja isegi igav<\/em>.<\/p>\n<p><\/p>\n<p>Artiklis on keeruline peegeldada oma vaatepunkti evolutsiooni, kuid uskuge: algselt tahtsin luua midagi keerulist, purunematut, mis suudaks ellu j\u00e4\u00e4da isegi tuumaplahvatuse l\u00e4heduses. Kuid m\u00f5istus (loodan) v\u00f5itis ja j\u00e4rk-j\u00e4rgult nihkusid prioriteedid lihtsuse ja kompaktsuse suunas.<\/p>\n<p><\/p>\n<p>Kas on v\u00f5imalik, et ma eksisin? Jah, muidugi. On t\u00e4iesti v\u00f5imalik, et oleme ostnud partiid ebakvaliteetseid mikroskeeme. V\u00f5i m\u00f5nel muul p\u00f5hjusel ei vasta seadmed usaldusv\u00e4\u00e4rsuse ootustele.<\/p>\n<p><\/p>\n<p>Kas mul on selleks juhtumiks plaan? Ma arvan, et artiklit lugedes ei kahtle sa, et plaan on olemas. Ja isegi mitte \u00fcks.<\/p>\n<p><\/p>\n<p>Kui olla veidi t\u00f5sisem, on formaat v\u00e4lja t\u00f6\u00f6tatud samal ajal nii t\u00f6\u00f6korras kui ka \u00abkatse\u00bb versioonina.<\/p>\n<p><\/p>\n<p>Praegu t\u00f6\u00f6tab laual k\u00f5ik normaalselt, s\u00f5na otseses m\u00f5ttes paar p\u00e4eva tagasi alustatakse lahenduse rakendamist. <em>(umbes)<\/em> sada seadet, vaatame, mis juhtub \u00abp\u00e4ris\u00bb kasutuses (lootuses, et formaat v\u00f5imaldab usaldusv\u00e4\u00e4rselt tuvastada rikkeid; nii et saab koguda p\u00f5hjalikku statistikat). M\u00f5ne kuu p\u00e4rast saab teha j\u00e4reldusi. <em>(ja kui ei vea, siis ka varem)<\/em>.<\/p>\n<p><\/p>\n<p>Kui kasutamise tulemusena tuvastatakse t\u00f5sised probleemid ja on vaja t\u00e4iendusi, siis kindlasti kirjutan sellest.<\/p>\n<p><\/p>\n<h1 id=\"literatura\">Kirjandus<\/h1>\n<p><\/p>\n<p>Ei tahtnud koostada pikka t\u00fc\u00fctut loetelu kasutatud t\u00f6\u00f6dest, l\u00f5puks on k\u00f5igil ju Google olemas.<\/p>\n<p><\/p>\n<p>Siin otsustasin j\u00e4tta nimekirja leidudest, mis tundusid mulle eriti huvitavad, kuid j\u00e4rk-j\u00e4rgult on need otseselt artikli teksti \u00fcle kandunud ning nimekirjas on j\u00e4\u00e4nud vaid \u00fcks punkt:<\/p>\n<p><\/p>\n<ol>\n<li>T\u00f6\u00f6riist <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/madler\/infgen\/\">infgen<\/a><\/noindex> autorilt zlib. Suudab selgelt kuvada deflate\/zlib\/gzip arhiivide sisu. Kui peate tegelema deflate (v\u00f5i gzip) formaadi sisemise struktuuri m\u00f5istmisega, siis soovitan tungivalt.<\/li>\n<\/ol>\n<p>Allikas: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/479044\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0415\u0441\u0442\u044c \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043d\u0443\u0442\u0440\u0438 Raspberry Pi \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0432\u044f\u0437\u043a\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0435. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043c\u043e\u043d\u0435\u0442\u043e\u043f\u0440\u0438\u0451\u043c\u043d\u0438\u043a, \u043a\u0443\u043f\u044e\u0440\u043e\u043f\u0440\u0438\u0451\u043c\u043d\u0438\u043a, \u0431\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0438\u0439 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u2026 \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435\u043c \u0441\u0430\u043c\u043e\u043f\u0438\u0441\u043d\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430. \u0412\u0441\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0432 \u0436\u0443\u0440\u043d\u0430\u043b \u043d\u0430 \u0444\u043b\u0435\u0448\u043a\u0435 (MicroSD), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e USB-\u043c\u043e\u0434\u0435\u043c\u0430) \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0442\u0430\u043c \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0411\u0414. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u0440\u043e\u0434\u0430\u0436\u0430\u0445 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 1\u0441, \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-53751","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0415\u0441\u0442\u044c \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043d\u0443\u0442\u0440\u0438 Raspberry Pi \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0432\u044f\u0437\u043a\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430 \u0432 NOR flash | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0415\u0441\u0442\u044c \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043d\u0443\u0442\u0440\u0438 Raspberry Pi \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0432\u044f\u0437\u043a\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-12-08T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:01:41+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Minu ringbufri rakendus NOR flashis | ProHoster","description":"Eelhistory. On oma arenduskujul kauplusautomaadid. Sees on Raspberry Pi ja natuke sidet eraldi plaadil.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430 \u0432 NOR flash | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0415\u0441\u0442\u044c \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043d\u0443\u0442\u0440\u0438 Raspberry Pi \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0432\u044f\u0437\u043a\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0435.","og:url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/moya-realizatsiya-koltsevogo-bufera-v-nor-flash","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-12-08T21:00:00+00:00","article:modified_time":"2020-02-18T11:01:41+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"53751","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 08:36:23","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:18:30","updated":"2026-01-24 08:36:23","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/53751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=53751"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/53751\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=53751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=53751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=53751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}