HotPDF RenderCacheFolder spremeni predpomnilnik izrisanih strani v pomnilniku komponente HotPDF Delphi v obstojen diskovni predpomnilnik strani: izrisane strani se zapisujejo kot datoteke PNG pod mapo po vaši izbiri, ob naslednjem odprtju istega vira PDF pa RenderLoadedPageToBitmapCached prebere nazaj, namesto da bi rasteriziral znova. Vrstni red iskanja je pomnilnik, nato disk, nato izrisovalnik
Diskovna plast je v API-ju od v2.416.0, do v2.770.140 pa nikoli ni dejansko postregla strani za navaden klic LoadFromFile ali LoadFromStream. Popravek je vsilil vprašanje, na katerega mora odgovoriti vsak obstoječ predpomnilnik: kako veste, da je datoteka, ki ste jo odprli danes, dokument, ki ste ga izrisali včeraj, in kaj se zgodi s predpomnjenimi stranmi, kadar ni? Spodaj so odgovori, na katere se je odločil HotPDF, vključno z mesti, kjer se namenoma odkloni od predpomnjenja
Kako deluje diskovni izrisovalni predpomnilnik HotPDF?
Diskovni izrisovalni predpomnilnik HotPDF je druga plast za rastrskim predpomnilnikom v pomnilniku in sodeluje samo, kadar je RenderCacheFolder neprazna pot. Klic RenderLoadedPageToBitmapCached(PageIndex, DPI) najprej preišče vnose v pomnilniku, indeksirane po indeksu strani, DPI in različici nastavitev izrisovanja. Ob zgrešitvi vpraša diskovno plast; diskovni zadetek dekodira PNG, ga povrne v pomnilnik in vrne kopijo v lasti klicalca. Šele, ko zgrešita obe plasti, gre stran skozi interpretator tokov vsebine, opisan v izrisovanju naložene strani PDF v TBitmap, sveža bitna slika pa se nato zapiše tudi na disk
Na disku je postavitev namenoma dolgočasna. Vsak dokument dobi podmapo, poimenovano iz 16-hex-znakovnega dokumentnega ključa plus 16-hex-znakovne različice izrisovanja, vsaka stran se shrani kot <page>@<dpi>.png, index.txt pri korenu pa hrani dokumente v vrstnem redu najbolj nazadnje uporabljenih za oznako sheme. Neujemanje sheme počisti mapo ob prvi uporabi. Zapisi gredo najprej v začasno datoteko in se na svoje mesto zamenjajo z atomsko zamenjavo, tako da sesutje med pisanjem pusti ali staro stran ali nič, nikoli pol PNG. PNG, ki se ne da dekodirati, je izbrisan in šteje kot zgrešitev
Mapo omejujejo tri meje:
RenderCacheMaxDocuments(privzeto 20) omeji število podmap dokumentov; najdlje neuporabljena mapa je izpodrinjena prvaRenderCacheMaxBytes(privzeto 524288000, kar je 500 MB) omeji skupno velikost vseh datotek PNG pod korenom- Vsaka mapa dokumenta hrani največ 200 slik strani; ta omejitev na dokument je fiksirana v THotPDF in ni objavljena lastnost
RenderCacheCapacity (privzeto 8) je ločen regulator: določa, koliko izrisanih strani hrani plast v pomnilniku, z diskovnim odtisom pa nima ničesar
uses
SysUtils, Graphics, HPDFDoc;
procedure WarmThumbnails(const FileName: string);
var
Pdf: THotPDF;
Bmp: TBitmap;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
// Nastavite diskovno plast pred prvim predpomnjenim izrisom:
// mapa in obe omejitvi sta prebrani, ko se plast prvič uporabi
Pdf.RenderCacheFolder := IncludeTrailingPathDelimiter(
GetEnvironmentVariable('LOCALAPPDATA')) + 'MyViewer\PageCache';
Pdf.RenderCacheMaxDocuments := 50;
Pdf.RenderCacheMaxBytes := Int64(1024) * 1024 * 1024; // 1 GiB
Pdf.RenderCacheCapacity := 16; // strani v pomnilniku
if Pdf.LoadFromFile(FileName) > 0 then
for I := 0 to Pdf.LoadedPageCount - 1 do
begin
Bmp := Pdf.RenderLoadedPageToBitmapCached(I, 96);
if Bmp <> nil then
try
// Kopijo tu izročite vrstici sličic
finally
Bmp.Free; // predpomnjen klic vedno vrne kopijo v lasti klicalca
end;
end;
finally
Pdf.Free; // od v2.770.140 to ne izbriše več diskovnih vnosov
end;
end;
Pognajte isto proceduro dvakrat in drugi pogon ne rasterizira strani, ki je spravila v predpomnilnik. Objekt diskovnega predpomnilnika se ustvari lenobno ob prvem predpomnjenem izrisu in živi, dokler se instanca THotPDF ne sprosti, tako da sprememba RenderCacheFolder, RenderCacheMaxDocuments ali RenderCacheMaxBytes po tej točki ne premakne ali predimenzionira že odprtega predpomnilnika. Strani, prevelike za politiko sprejemanja v pomnilnik (privzeto posamezen vnos ne sme presegati 64 MiB 32-bitnih pikslov), se prav tako ne obstojijo, diskovna plast pa se obravnava samo, dokler RenderFallbackPolicy obdrži privzeti rfpIgnore, ker rezervna diagnostika ni shranjena ob strani PNG
Zakaj RenderCacheFolder pred v2.770.140 nikoli ni deloval?
RenderCacheFolder je pred v2.770.140 brez učinka, ker je diskovna plast indeksirala dokumente po hashu izvornih bajtov, ki ga navadna nalaganja nikoli ni hranila. Dokumentni ključ je prišel iz SHA-256 nad notranjo kopijo surovih bajtov PDF, LoadFromFile in LoadFromStream pa razčlenita vir na mestu in take kopije ne obdržita; polje je bilo zapolnjeno samo začasno na poti šifrirane obnove in ponovno počiščeno takoj zatem. Brez bajtov je bil ključ vedno prazen, prazen ključ pa pomeni, da se diskovna plast obide. Nobene napake, nobenega opozorila, samo mapa, ki je ostala prazna
Narediti ključ neprazen je razkrilo drugi hrošč, skritega za prvim. Stari InvalidateRenderedPageCache je izbrisal diskovno mapo dokumenta, InvalidateRenderedPageCache pa teče na začetku vsakega nalaganja, ob vsakem urejanju in znotraj Free. Torej bi v trenutku, ko bi ključ deloval, vsaka seja pregledovalnika uničila svoj predpomnilnik ob izhodu, naslednja seja pa bi vseeno začela hladna. Še huje, ključ bi bil po urejanju ponovno izračunan iz istega vira, tako da bi bili izrisi urejenega dokumenta shranjeni pod ključem izvirne datoteke in postreženi naslednji seji, ki odpre nespremenjeni PDF. v2.770.140 popravi identiteto in razveljavitev skupaj; popravek samo enega od njiju bi poslal ali mrtv ali lažnivec predpomnilnik
Kako HotPDF prepozna PDF, ne da bi prebral celo datoteko
HotPDF prepozna PDF, naložen iz lokalne datoteke, po prstnem odtisu njene velikosti, časa zadnjega zapisa ter prvih in zadnjih 64 KiB, vir tok ali naključno-dostopni vir pa po SHA-256 celotne vsebine. Oboje se zajame enkrat, ko nalaganje uspe, prvih 16 hex znakov povzetka SHA-256 (64 bitov) pa postane dokumentni ključ
| Vir | Identiteta | Cena | Zajeto kdaj |
|---|---|---|---|
LoadFromFile | Size + LastWriteTime + vodilnih in končnih 64 KiB, hashirano s SHA-256 | Največ 128 KiB branja, neodvisno od velikosti datoteke | Vsako uspešno nalaganje, tudi če je RenderCacheFolder nastavljen kasneje |
LoadFromStream | SHA-256 celega toka | En poln prehod čez vir | Samo, kadar je bil RenderCacheFolder nastavljen pred nalaganjem |
LoadFromRandomAccessSource | SHA-256 celega vira | En poln prehod čez vir | Samo, kadar je bila mapa nastavljena najprej in je celoten obseg na voljo |
Kateri koli vir z vnosom /Encrypt | Brez | Brez | Nikoli; diskovna plast se obide |
Prstni odtis datoteke je namerno trgovanje. Poln hash 400 MB skeniranega arhiva ob vsakem odprtju lahko stane več kot izris dveh strani, ki si ju uporabnik dejansko ogleda. Vzorčeni območja niso poljubna: glava leži na začetku datoteke, priklopnik in zadnji odsek navzkrižnih sklicev pa na koncu (ISO 32000-1 §7.5). Inkrementalna posodobitev doda novo telo, odsek navzkrižnih sklicev in priklopnik (§7.5.6), tako da hkrati spremeni velikost in rep. Poln prepis s katerim koli navadnim orodjem spremeni čas zadnjega zapisa. Za datoteke do 128 KiB vzorca pokrijeta vsak bajt, tako da so majhni dokumenti učinkovito hashirani v celoti
Preostalo tveganje je sprememba enake velikosti na mestu sredi velike datoteke, katere zapisovalec nato povrne izvirni časovni žig. To potrebuje orodje, ki namenoma ohranja čase sprememb med urejanjem vsebine — redko, a ne nemogoče — in v tem primeru predpomnilnik postreže zastarele strani. Nasprotna stran je neÅ¡kodljiva: kopiranje datoteke na Windows običajno ohrani čas zadnjega zapisa, tako da kopija dokumenta, ki je že v predpomnilniku, zadene iste vnose — kar je prav, ker so bajti identični
Tokovi nimajo časa spremembe sploh, zato je edina poštena identiteta vsebina. HotPDF plača ta poln prehod SHA-256 samo, kadar ste diskovni predpomnilnik zahtevali pred nalaganjem; vsak drug klicalec LoadFromStream ne vidi dodatne cene. Vrstni red dodeljevanja lastnosti je zato kljuÄen:
procedure OpenDownloadedPdf(Pdf: THotPDF; Data: TStream;
const CacheRoot: string);
begin
// Napačen vrstni red za tokove: vsebinski hash se izračuna samo, kadar je
// mapa že nastavljena, tako da bi ta dokument obšel diskovno plast
// Pdf.LoadFromStream(Data);
// Pdf.RenderCacheFolder := CacheRoot;
Pdf.RenderCacheFolder := CacheRoot; // nastavite najprej
Data.Position := 0;
if Pdf.LoadFromStream(Data) <= 0 then
raise Exception.Create('The stream is not a loadable PDF');
end;
Naključno-dostopni vir, ki se še prenaša (nekateri obsegi še niso na voljo), ne dobi identitete, namesto hasha delne vsebine, in če izračun identitete iz kakršnega koli razloga odpove, nalaganje še vedno uspe; dokument preprosto izrisuje brez diskovne plasti
Kaj razveljavi vnos diskovnega predpomnilnika HotPDF?
Vnos diskovnega predpomnilnika HotPDF ni nikoli razveljavljen z brisanjem ob urejanju; namesto tega urejanje naloženega dokumenta spusti identiteto dokumenta, tako da se diskovna plast obide za preostanek tega nalaganja, shranjene strani pa ostanejo veljavne za nespremenjeni vir. Vnosi zapustijo disk samo skozi LRU in bajtne meje, pokvarjen PNG ali spremembo sheme
Ključ opisuje vir na disku, ne grafa objektov v pomnilniku. Ko žigosate stran ali spremenite anotacijo, se dokument ne ujema več s tem virom, tako da ne bi bilo prav niti brati niti pisati pod njegovim ključem. Od v2.770.140 razveljavitev na ravni dokumenta in na ravni strani počistita identiteto, namesto da bi se dotaknili mape, in obstaja druga straža za urejanja, ki niso klicala InvalidateRenderedPageCache: pred uporabo diskovne plasti THotPDF preveri, ali je kateri koli naloženi objekt umazan, in umazan dokument obravnava kot brez identitete
Nastavitve izrisovanja delujejo obratno. Preklop PageRenderBackend (ali klic UseNativeGDIRenderBackend) ter klic ConfigureRenderICCWorkflow ali ClearRenderICCWorkflow spraznijo strani v pomnilniku, a obdržijo identiteto, ker se dokument še vedno ujema s svojim virom. Te nastavitve spremenijo piksle, ne da bi bile del različice v pomnilniku, zato diskovni ključ zvije noter ime zaledja, zastavico kompenzacije črne točke in povzetke SHA-256 ICC profilov dokaza in izhoda. Različica sama že pokriva barvni namen, rastriranje izhoda, predogled pretiske, način maske svetlosti, rezervno politiko in vidnost vsake skupine neobvezne vsebine, tako da preklop plasti izrisuje v drugačno mapo, namesto da bi prepisal privzeti pogled
Da urejeni dokument spet pridete na diskovno plast, mu dajte novo identiteto vira tako, da ga shranite in naložite rezultat:
procedure CommitEditsAndRekey(Pdf: THotPDF; const EditedFile: string);
begin
// Po urejanju naloženega dokumenta: osvežite strani v pomnilniku.
// Identiteta vira je že izgubljena, tako da se iz izvornega dokumenta
// nič ne bere in nič ne zapisuje v njegovo diskovno mapo
Pdf.InvalidateRenderedPageCache;
// Shranjena datoteka ima novo velikost in čas zadnjega zapisa, torej novo
// identiteto; izrisi po tem nalaganju so predpomnjeni pod novim ključem
Pdf.SaveLoadedDocument(EditedFile);
if Pdf.LoadFromFile(EditedFile) <= 0 then
raise Exception.Create('Could not reload the edited document');
end;
Mapa izvornega dokumenta je puščena pri miru in stari skozi RenderCacheMaxDocuments in RenderCacheMaxBytes kot kateri koli drug vnos. Če uporabnik znova odpre neurejeni izvirnik, so njegove strani še vedno tam
Varnostne meje: šifrirani viri in povezane mape
Diskovni izrisovalni predpomnilnik HotPDF se namenoma odkloni od dveh vrst vnosa: nikoli ne zapisuje strani šifriranega PDF-ja na disk in nikoli ne sledi podmani dokumenta, ki je junction ali druga točka ponovne razčlenitve. Obe pravili trgujeta zadetke predpomnilnika za to, da ne puščata podatkov ali ne izbrišeta napačnih datotek
Šifrirani PDF-ji se nikoli ne predpomnijo na disk
Izrisana stran je dešifrirana vsebina. Njen zapis kot navaden PNG v mapo predpomnilnika bi pustil berljivo kopijo dokumenta, zaščitenega z geslom, na disku, izven zaščite, ki jo je izbral avtor (ISO 32000-1 §7.6). HotPDF zato ne zajame identitete za noben vir, katerega priklopnik nosi vnos /Encrypt, vključno z datotekami, odprtimi z geslom ali s praznim uporabniškim geslom. Ti dokumenti še vedno uporabljajo plast v pomnilniku, ki pogine s procesom
Podmane junction so zavrnjene od v2.770.173
Koren predpomnilnika je vaša izbira in kazati ga na junction je dovoljeno. Podmane dokumentov pod njim pa so druga zadeva: predpomnilnik jih sam ustvarja, bere, se jih dotika in jih briše — med zagonom obnove (ki odstrani preostale začasne datoteke), iskanja (ki posodablja časovne žige), shranjevanja, razveljavitve in treh mej izpodrivanja. Če bi nekdo z dostopom za pisanje do korena predpomnilnika zamenjal mapo dokumenta z junction na drug imenik, bi ji sledila vsaka od teh poti in izpodrivanje bi brisalo datoteke nekje, kjer jih predpomnilnik nikoli ni imel v lasti. Od v2.770.173 vsak od teh vstopnih točk preveri atribut točke ponovne razčlenitve in preskoči povezano mapo dokumenta: iskanje šteje zgrešitev, shranjevanje neuspel zapis, izpodrivanje pa jo pusti pri miru
Poti Unicode in deljeni koreni
Dva povezana popravka štejeta, kadar nameščate v uporabniške profile. Pred v2.770.135 je bil RenderCacheFolder AnsiString, tako da je bila mapa izven sistemske kodne strani (kitajsko uporabniško ime na angleški namestitvi Windows, na primer) pretvorjena z izgubo, preden jo je videl predpomnilnik; lastnost je zdaj Unicode string in atomska zamenjava uporablja široki Windows API. Od v2.770.52 si več instanc THotPDF v enem procesu, ki kažejo na isti koren (po razširitvi poti, primerjano neobčutljivo na velike črke), delijo en sam indeks in zaklep, štet po sklicih. Prej je vsaka instanca prepisala index.txt s svojo kopijo in uveljavljala meje proti svojemu delnemu pogledu, tako da je lahko mapa zrasla nekajkrat čez svoj proračun
To deljenje se ustavi na meji procesa. Dva ločena procesa na istem korenu še vedno držita ločena indeksa v pomnilniku, zato dajte vsaki sočasno tekoči aplikaciji svoj koren predpomnilnika. Pregledovalniki, ki izrisujejo na delovnih nitih, so znotraj enega procesa v redu: PrefetchLoadedPages in čakalna vrsta, pokrita v izrisovanju v ozadju s čakalno vrsto zahtev, oba greta skozi isto predpomnjeno pot in isti zaklep
Hiter pregled: kontrolni seznam RenderCacheFolder
- Nastavite
RenderCacheFolder,RenderCacheMaxDocumentsinRenderCacheMaxBytespred prvim klicemRenderLoadedPageToBitmapCached; za nalaganja tok in naključnega dostopa nastavite mapo pred nalaganjem - Nadgradite na v2.770.140 ali novejši, kadar se zanašate na diskovno plast; starejše različice sprejmejo lastnost, a nikoli ne postrežejo strani z diska za navadna nalaganja
- Pričakujte brez diskovnega predpomnjenja za šifrirane PDF-je, za dokumente, urejene po nalaganju, ali medtem ko
RenderFallbackPolicynirfpIgnore - Sprostite instanco THotPDF navadno; od v2.770.140 ne
FreeneInvalidateRenderedPageCachene briše diskovnih vnosov - Sprememba
PageRenderBackendali ICC delovnega toka obdrži dokument na diskovni plasti pod drugačnim ključem - Uporabite en koren predpomnilnika na tekočo aplikacijo; instance znotraj enega procesa si delijo indeks od v2.770.52
- Držite koren predpomnilnika na mestu na uporabnika; podmane dokumentov, ki so junction, so preskočene od v2.770.173
Obstoječ predpomnilnik strani se najbolj izplača v pregledovalniku, ki ves dan znova odpira iste dokumente — točno to je oblika arhitekture pregledovalnika PDF po meri v Delphiju, opisane drugje na tem blogu. RenderCacheFolder, rastrski predpomnilnik v pomnilniku in izrisovalnik strani prihajajo s komponento HotPDF Delphi PDF za Delphi in C++Builder