
Každá aplikace vytvořená pomocí desktopové aplikace WebCatalog dříve na macOS zabírala přibližně 320 MB místa na disku. U aplikace založené na Electronu to není nic neobvyklého, WebCatalog je však určen lidem, kteří jako desktopové aplikace používají mnoho webových aplikací. Deset takových aplikací mohlo zabrat přes 3 GB, přestože většina dat v nich byla naprosto stejná.
Nedávno jsme změnili způsob, jakým desktopová aplikace WebCatalog vytváří aplikace na macOS. První aplikace nyní zabere přibližně 340 MB fyzického místa na disku, včetně místně uložené připravené kopie aplikačního enginu. Každá další aplikace pak obvykle přidá jen 1–2 MB skutečně využitého místa na disku. Při našem testování klesla spotřeba místa u deseti aplikací z více než 3 GB na přibližně 360 MB.
Dosáhli jsme toho pomocí funkce, kterou macOS už obsahuje: klonování v APFS. Nešlo jen o samotné klonování souborů. Důležité bylo zajistit, aby klonování fungovalo a zároveň každá aplikace zůstala nezávislá, měla platný podpis kódu a fungovala stejně jako aplikace vytvořená původním postupem.
Proč každá aplikace zabírala dalších 320 MB
Desktopová aplikace WebCatalog mění webové stránky na samostatné desktopové aplikace. Každá vytvořená aplikace běží na Photonu, našem aplikačním enginu postaveném na Electronu. Na macOS má každá podobu běžného balíčku .app, který obsahuje Electron (Chromium a Node.js), Photon a soubory konkrétní aplikace.
Vezměme si například dvě aplikace, Slack a Discord. Liší se názvem, ikonou, identifikátorem balíčku a konfigurací, ale rozsáhlý framework Electron a většina Photonu jsou totožné.
Dosud se každá aplikace vytvářela jako zcela samostatná kopie.
Slack.app
Electron
Photon
Soubory specifické pro Slack
Discord.app
Electron
Photon
Soubory specifické pro Discord
Framework Electron a Photon mohly být v obou aplikacích totožné do posledního bajtu, macOS však přesto pro každou aplikaci ukládal další fyzickou kopii. Deset aplikací tak znamenalo přibližně deset kopií téměř stejného aplikačního balíčku o velikosti 320 MB.
Tato architektura měla jednu vlastnost, kterou jsme chtěli zachovat: každá aplikace byla plně nezávislá. Smazání jedné nemohlo ovlivnit jinou a nainstalované aplikace nezávisely na tom, zda desktopová aplikace WebCatalog zůstane v systému.
Chtěli jsme odstranit zbytečnou duplicitu dat, která se pod tím skrývala.
APFS už obsahovalo mechanismus, který jsme potřebovali
Moderní Macy používají souborový systém APFS od Applu. APFS podporuje klonování, mechanismus kopírování při zápisu, který dvěma nezávislým souborům umožňuje sdílet stejná fyzická data, dokud se jeden z nich nezmění.
Představte si kopírování souboru o velikosti 300 MB. Při běžném kopírování macOS zapíše na disk dalších 300 MB, takže oba soubory dohromady zaberou přibližně 600 MB.
Při klonování v APFS nový soubor stále vypadá a chová se jako úplný soubor o velikosti 300 MB, zpočátku však odkazuje na stejné fyzické bloky jako originál.
Soubor A ────┐
├── sdílené fyzické bloky
Soubor B ────┘
Pokud se později část souboru B změní, APFS zapíše nové bloky pouze pro změněná data. Všechno, co zůstane totožné, může dál sdílet původní bloky.
Soubor A ─────── sdílené bloky
Soubor B ─────── sdílené bloky
└────── změněné bloky
Z pohledu aplikace jsou soubory A a B oddělené. Z pohledu SSD stačí totožná data uložit jen jednou.
To je téměř přesně chování, které jsme potřebovali.
Vytváření aplikací ze společného základu
Desktopová aplikace WebCatalog nyní připravuje základ pro každou kombinaci verzí Electronu a Photonu. Základní aplikace Photon obsahuje části totožné napříč aplikacemi, včetně Electronu, Photonu, struktury frameworku a společných podpisů.
Když desktopová aplikace vytváří další aplikaci se stejnými verzemi, už znovu nerozbaluje a nevytváří celou kopii od začátku. Místo toho vytvoří klon základní aplikace Photon v APFS a upraví pouze části, které se musí lišit.
Patří mezi ně název aplikace, ikona, identifikátor balíčku, nastavení, názvy spustitelných souborů, identifikátor sestavení a další metadata specifická pro danou aplikaci.
Protože většina balíčku zůstává beze změny, APFS nadále sdílí fyzické bloky obsahující Electron a Photon. Nové místo zabírá jen poměrně malé množství dat specifických pro aplikaci.
Proč nesdílet prostě Electron?
Nabízelo by se nainstalovat Electron jen jednou a nechat na něj odkazovat všechny aplikace.
Tuto možnost jsme zvažovali, ale zásadně by změnila spolehlivost řešení. Kdyby sdílená instalace Electronu zmizela, mohly by přestat fungovat všechny aplikace, které na ní závisí. Mohl by ji odstranit nástroj na čištění mezipaměti nebo odinstalování desktopové aplikace WebCatalog. Také přesun či obnovení jednotlivé aplikace by byly složitější.
Navíc by bylo nutné sledovat, které nainstalované aplikace závisejí na kterých verzích běhového prostředí, aby bylo možné starší verze bezpečně odstranit.
Další problém představuje podepisování kódu v macOS. Přísné ověřování podpisu odmítá symbolické odkazy mířící mimo aplikační balíček.
Klonování v APFS nám přináší výhody sdílení, aniž by vznikla taková závislost. Nainstalované aplikace mohou sdílet fyzické bloky na disku a přitom zůstat úplnými, nezávislými aplikačními balíčky.
Smazání základní aplikace Photon nepoškodí aplikace z ní vytvořené. Smazání jedné nainstalované aplikace neovlivní jinou. Sdílení zajišťuje souborový systém, zatímco architektura aplikací zůstává nezávislá.
Podepisování kódu úsporu téměř zrušilo
Klonování aplikace bylo jen částí problému. Aplikace pro macOS musí mít také podepsaný kód.
Náš původní postup sestavení po úpravách znovu důkladně podepisoval celý aplikační balíček. U běžné kopie to nevadí. Při ukládání metodou kopírování při zápisu však úprava velkého binárního souboru může způsobit, že pro něj APFS vyhradí nové fyzické bloky.
Během vývoje jsme naměřili, že opětovné podepsání frameworku Electron přidalo přibližně 194 MB fyzického úložiště na aplikaci. Při vytváření aplikace jsme se sice vyhnuli kopírování Electronu, ale při podepisování jsme velkou část dat znovu zdvojili.
Museli jsme tedy změnit i postup podepisování.
Velký společný framework se nyní podepisuje jako součást základní aplikace Photon. Když desktopová aplikace tento základ klonuje, neupravujeme velké sdílené binární soubory a znovu podepisujeme jen menší části, které se mezi aplikacemi skutečně musí lišit.
Po dokončení aplikace spustíme přísné ověření podpisu celého výsledného balíčku, abychom měli jistotu, že je vše platné.
Díky tomu zachováváme jak záruky, které poskytuje podepisování kódu v macOS, tak úsporu místa díky APFS.
Když požadavek na klonování v Node.js ve skutečnosti neklonoval
Narazili jsme ještě na jeden nečekaný problém: samotné provedení klonování.
Node.js nabízí příznaky kopírování určené k vyžádání kopírování při zápisu, včetně COPYFILE_FICLONE a COPYFILE_FICLONE_FORCE. Podle popisu vypadaly jako přesně ta rozhraní API, která jsme potřebovali.
Při testování na Node.js 24 jsme stejnou aplikaci využívající Electron o velikosti 288 MB zkopírovali několika způsoby a měřili, kolik fyzického místa na disku každá operace navíc zabrala:
fs.cpSync +288 MB
fs.cpSync + COPYFILE_FICLONE +288 MB
fs.cpSync + COPYFILE_FICLONE_FORCE +288 MB
/bin/cp -c -R ~0 MB
Oba režimy klonování v Node.js při našem testu přesto vytvořily plnou fyzickou kopii. Ani varianta FORCE neohlásila chybu, přestože k očekávanému klonování nedošlo.
Nativní příkaz macOS cp -c se choval podle očekávání, proto desktopová aplikace WebCatalog používá přímo tento mechanismus.
Připomnělo nám to také, že optimalizace souborového systému je potřeba ověřovat měřením samotného souborového systému. Volání API, které požaduje kopírování při zápisu, ještě nutně neznamená, že výsledné soubory skutečně sdílejí fyzické úložiště.
Aby selhání optimalizace nevadilo
Úspora místa na disku je optimalizace. Úspěšná instalace aplikace nikoli.
Nový postup jsme navrhli tak, aby selhání klonování nebránilo instalaci aplikace. Pokud selže příprava základní aplikace Photon, základ uložený v mezipaměti je poškozený, klonování se nezdaří nebo neprojde ověření podpisu, desktopová aplikace se vrátí k původnímu postupu s úplným rozbalením a úplným podepsáním.
V nejhorším případě tedy aplikace zabere stejně místa jako dříve, místo aby se ji nepodařilo nainstalovat.
Museli jsme počítat i se souběžným zpracováním. Základní aplikace Photon se nejprve připraví v dočasném adresáři a do konečného umístění se přesune, až když je hotová. Dvě současně probíhající sestavení aplikací tak nemohou omylem použít nedokončený základ.
Starší základy lze také bezpečně odstranit. Nainstalovaný klon v APFS není závislý na tom, zda původní základ dál existuje. Pokud se základ smaže, klon si zachová fyzické bloky, které stále používá.
Funguje to na APFS, výchozím souborovém systému všech moderních Maců. Pokud máte aplikace na disku, který klonování nepodporuje, například na externím disku s HFS+ nebo exFAT, desktopová aplikace WebCatalog použije běžné kopírování. Aplikace tak fungují jako dřív, ale místo nešetří. Ve Windows a Linuxu se zatím nic nemění.
Logická a fyzická velikost nejsou totéž
Jedním poněkud matoucím vedlejším efektem je, že Finder může u každé aplikace stále uvádět velikost přibližně 320 MB.
Toto číslo představuje logickou velikost aplikace. Aplikace skutečně obsahuje soubory o celkové velikosti zhruba 320 MB. Pokud by se tyto soubory někam zkopírovaly bez klonování, přibližně tolik dat by bylo nutné zapsat.
Změnila se fyzická velikost, tedy počet jedinečných bloků, které tyto soubory na disku skutečně zabírají.
Pokud dvě aplikace obsahují stejný framework o velikosti 300 MB a APFS jim umožní sdílet stejné fyzické bloky, může každá aplikace logicky obsahovat 300 MB, zatímco druhá přidá téměř nulové množství nových fyzických dat.
Okno Informace ve Finderu ani nástroje jako du toto sdílení nutně nezobrazují. Úspora je nejlépe patrná na množství volného místa, které na disku skutečně zbývá.
Ověřili jsme to na sedmi skutečných aplikacích: Discordu, Facebooku, Instagramu, Messengeru, TikToku a dvou vlastních aplikacích. Při sestavení novým způsobem ušetřily oproti původnímu postupu přibližně 1,9 GB místa na disku.
Zkontrolovali jsme také umístění podkladových dat na fyzickém disku a potvrdili, že aplikace sdílejí společná data Electronu a Photonu na úrovni bloků. Aplikace vytvořená původním postupem žádné z těchto bloků nesdílela, což nám poskytlo užitečné srovnání.
Výsledek
Pro někoho, kdo si pomocí desktopové aplikace WebCatalog vytvoří jen jednu aplikaci, je rozdíl malý. První aplikace ve skutečnosti zabere o něco více místa než dříve, protože desktopová aplikace uchovává také základní aplikaci Photon pro vytváření dalších klonů.
S každou další aplikací ale přínos rychle roste.
Dříve
1 aplikace ~320 MB
10 aplikací >3 GB
S klonováním v APFS:
Nyní
1 aplikace ~340 MB
10 aplikací ~360 MB
Po vytvoření počátečního základu každá další aplikace obvykle zvýší fyzické využití disku jen o 1–2 MB.
Podstatné je, že jsme toho dosáhli bez zavedení závislosti na sdíleném běhovém prostředí. Každá aplikace zůstává běžnou, samostatnou aplikací pro macOS, zatímco APFS ukládá totožná data Electronu a Photonu jen jednou. Při zhruba deseti nainstalovaných aplikacích tak může skutečné využití disku klesnout na méně než osminu.
Tato funkce je dostupná v nejnovější verzi desktopové aplikace WebCatalog pro macOS. Nemusíte nic zapínat: nové aplikace ji používají automaticky a aplikace, které už máte, začnou zabírat méně místa při příští aktualizaci.