Техническа статия

Кеширане на подмножествата от шрифтове на диск с HotPDF в Delphi

HotPDF може да държи подмножествата на TrueType и OpenType шрифтове на диск и да ги преизползва между документи и между стартирания на процеса, така че партида, която рендерира десет хиляди извлечения със същите три шрифта, подмножава тези шрифтове веднъж вместо десет хиляди пъти. Кешът се конфигурира с две свойства, инспектира се с един запис и е безопасно да се остави включен: отказ на кеша пада обратно към обикновено подмножаване в памет и никога не спира документ да бъде произведен

Подмножаването е скъпо по причина. Изграждането на подмножество означава обхождане на затварянето на глифове, презаписване на loca и glyf, прездравяване на cmap и hmtx, и излъчване на CID съпоставяне, което PDF може да адресира. За един документ тази цена изчезва в шума. За сървър за отчети, произвеждащ документи в цикъл, това често е най-големият единичен блок CPU време в стартирането

Какво прави кеш попадението възможно

Четири неща трябва да съвпаднат: съдържанието на шрифта, множеството от използвани глифове, режимът на подмножаване и схемата на кеша. Пропуснете което и да е и HotPDF подмножава от нулата, защото подмножество е преизполваемо само когато би било байт-идентично така или иначе

Множеството от глифове е условието, което изненадва хората. Две фактури, различаващи се по единствено име на клиент, използват различни множества от глифове и затова произвеждат различни подмножества и различни кеш записи. Кешът се отплаща, когато документи споделят глифов репертоар — извлечения от фиксиран шаблон, формуляри, чиито променливи данни са числови, каталози, изчертани от една продуктова база данни — и не се отплаща, когато всеки документ изчертава различна извадка от голям CJK шрифт. Измервайте, преди да приемате в кой от двата случая сте

var
  Pdf: THotPDF;
  Info: THPDFFontSubsetCacheInfo;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.EnableFontSubsetting := True;
    Pdf.FontSubsetCacheFolder := 'C:\ProgramData\Reports\fontcache';
    Pdf.FontSubsetCacheMaxBytes := 64 * 1024 * 1024;   // 64 MiB, default is 256
    // ... generate the batch ...
    Info := Pdf.GetFontSubsetCacheInfo;
    LogFmt('subset cache: %d hits, %d misses, %d bytes in %d files',
      [Info.HitCount, Info.MissCount, Info.CurrentBytes, Info.FileCount]);
  finally
    Pdf.Free;
  end;
end;

Как разбирате, че кешът изобщо прави нещо?

GetFontSubsetCacheInfo връща девет брояча, а съотношението между първите два отговаря на въпроса директно. HitCount и MissCount дават степента на попадение. WriteCount и EvictionCount показват дали записите оцеляват достатъчно дълго, за да бъдат преизползвани, или биват избутани от твърде малък бюджет. CurrentBytes и FileCount отчитат какво е на диска в момента

Останалите три са тези, за които си струва да се алармира. CorruptCount отчита записи, провалили валидация и премахнати — няколко след нечисто изключване са нормални, постоянен поток означава, че хранилището е ненадеждно. RejectedCount отчита записи, отказани преди използване. WriteFailureCount отчита записи, които не са могли да бъдат записани изобщо, което обикновено означава проблем с права върху папката, а не нещо за шрифтове. Нито едно от тези три не спира генерирането на документи, което е точно причината да ги погледнете: кеш, който мълчаливо никога не записва, изглежда отвън като кеш, който работи, освен по сметката за CPU

Изтласкване, бюджети и моментът, в който свивате едно от тях

FontSubsetCacheMaxBytes е 268435456 байта по подразбиране, тоест 256 MiB, и може да се понижи по време на изпълнение. Понижаването му задейства незабавно изтласкване по най-отдавна използван, вместо да чака следващия запис, така че услуга, реагираща на дисково натиск, може да освободи пространство в момента, в който реши, а не в някаква по-късна точка, която не контролира

Задаването на FontSubsetCacheFolder на празен низ изключва дисковото ниво, без да изчиства каквото и да е вече съхранено, и без да промени нито един байт от шрифтовия изход. Това е свойството, за което да посегнете, когато искате да изолирате кеша по време на отстраняване на проблеми: изключете го, пуснете същата партида и сравнете произведените PDF-и. Те трябва да са идентични, защото кешът съхранява резултат, а не политика

Какво прави кешът, когато запис е повреден

Премахва го и подмножава нормално. Повредени или отрязани записи се отхвърлят, преди подмножеството да може да достигне PDF поток, което е частта от дизайна, която има най-голямо значение: повреден кеш запис, който би попаднал в документ, би произвел PDF със счупен шрифтов програма, и този отказ би се появил далеч от причината си — в четец, на машина на клиент, седмици по-късно

Записите са атомарни, така че четец никога не наблюдава полузаписан запис, а срив по време на запис оставя кеша консистентен вместо отровен. Компактните записи на подмножества запазват данните за CID преразпределение, които шрифтовите речници на PDF/A изискват, така че кеширано подмножество все още е съответстващо подмножество — архивният изход не трябва да заобикаля кеша, за да остане валиден

// Reset the disk tier after a font upgrade or a schema change
Pdf.ClearFontSubsetCache;

// Or move it somewhere writable and let the budget apply immediately
Pdf.SetFontSubsetCacheFolder('D:\cache\fonts');

Къде да поставите папката в реално разгръщане

Три свойства решават това: папката трябва да бъде записваема от профила, под който услугата се изпълнява, трябва да седи на локално хранилище, а не на мрежово споделяне, и не трябва да е вътре в директория, която стъпка на разгръщане изтрива. Кеш на споделяне превръща всеки пропуск в обаждане от типа round trip, а всяко попадение в две; кеш под папка на приложение, която инсталаторът пресъздава, е кеш, който стартира студен след всяко обновление

За услуги с много инстанции, дайте на всяка инстанция собствена папка, освен ако не сте потвърдили, че хранилището обработва конкурентно атомарно заместване така, както очаквате. Цената на дублиран запис е едно допълнително подмножаващо преминаване; цената на отстраняване на състезание в споделен кеш е един следобед

Кога да посегнете към нещо друго

Кешът намалява повтаряща се работа. Той не намалява работата за първия документ и не помага на натоварване, чиито множества от глифове никога не се повтарят. Ако вашият изход се доминира от един огромен CJK шрифт, използван върху непредсказуем текст, по-ефективният лост е самото затваряне на подмножаването — кои глифове биват въвличани и защо — разгледано в записките за затваряне на подмножество на шрифт и оформяне на глифове. Ако партидата ви е бавна по причини, които се оказват да не са шрифтове изобщо, ръководството за изход на отчети със шрифтове и изображения показва къде другаде обикновено отива времето, а случайното проучване за бъга в подредбата на подмножествата при EndDoc е напомняне, че коректност на подмножаване и скорост на подмножаване са отделни проблеми

HotPDF е нативен VCL PDF компонент за Delphi и C++Builder, а кешът за подмножества е част от библиотеката, а не добавена услуга, така че сървър за отчети го получава, задавайки един път до папка — вижте страницата на HotPDF компонент за пълния списък с функции за шрифтове и производителност