You are browsing the unmaintained documentation for old Nette 2.3. See documentation for current Nette.

SafeStream: atomické operace‎

Nette\Utils\SafeStream garantuje, že každá operace se soubory proběhne atomicky a izolovaně.

Instalace:

composer require nette/safe-stream

K čemu jsou atomické operace vlastně dobré? Začněme jednoduchým příkladem, který opakovaně zapisuje do souboru a následně z něj čte tentýž řetězec:

$s = str_repeat('Long String', 10000);

$counter = 1000;
while ($counter--) {
	file_put_contents('soubor', $s); // write it
	$readed = file_get_contents('soubor'); // read it
	if ($s !== $readed) { // check it
		echo 'řetězce se liší!';
	}
}

Může se zdát, že volání echo 'řetězce se liší!' nikdy nemůže nastat. Opak je pravdou. Schválně si zkuste tento skript spustit ve dvou tabech prohlížeče zároveň. Chyba se dostaví prakticky okamžitě.

Jeden tab totiž přečte soubor v okamžiku, kde jej druhý ještě nestihl celý zapsat.

Uvedený kód tedy není bezpečný, pokud se v jednu chvíli provádí vícekrát (tedy ve více vláknech). Což na internetu není nic neobvyklého, často se v tentýž okamžik připojuje více lidí k jednomu webu. Takže starat se o to, aby vaše aplikace fungovala spolehlivě i při provádění ve více vláknech (thread-safe), je velmi důležité. Jak totiž vidíte, nativní PHP funkce atomické nejsou. Jinak musíme počítat se ztrátou dat a vznikem těžko odhalitelných chyb.

Řešení nabízí SafeStream a jeho bezpečný protokol, pomocí něhož můžeme atomicky manipulovat se soubory prostřednictvím standardních PHP funkcí. Stačí jen uvést nette.safe:// před jménem souboru:

file_put_contents('nette.safe://soubor', $s);

Pokud bychom bezpečný protokol použili v úvodním příkladu, nedošlo by nikdy k chybě.

S protokolem lze používat všechny známé funkce, například:

$handle = fopen('nette.safe://file.txt', 'x');

$ini = parse_ini_file('nette.safe://autoload.ini');

Jak to funguje?

SafeStream vám garantuje:

  • atomicitu: soubor se zapíše buď celý, nebo vůbec
  • isolaci: nikdo nezačne číst soubor, který ještě není celý zapsán

K zajištění obého se použivají souborové zámky a dočasné soubory.

Zápis se provádí do dočasných souborů a teprve po úspěšném zapsání se přejmenuje. Pokud z jakéhokoliv důvodu zápis selže, třeba kvůli chybě skriptu nebo nedostatku volného místa na disku, bude zahozen a nevznikne neúplný soubor.

Pokud zapisujete do existujícího souboru v režimu a (append), SafeStream vytvoří jeho kopii. Zapisovat v tomto režimu má tedy vyšší režii, než zápis v ostatních módech.

Vylepšit tuto stránku