Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: exkalibr 12. 10. 2019, 15:34:39

Název: PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 15:34:39
Zajímalo mě jak je to s bezpečností funkcí file_get_contents/file_put_content vs flock/fread/fwrite/flush při hromadném přístupu k téže souboru. Jelikož jsem nikde na netu nenašel žádné informace, které by mi jednoznačně a definitivně vyloučili možnost selhání (např. vzniku vadného souboru, ztráty dat apod.) při čtení/zápisu pomocí prvních dvou zmíněných funkcí, tak jsem se újmul toho, že jsem udělal testy. Test jsem nahrál na vzdálený server a otestoval jsem stránku (skript): spustil jsem stejný požadavek 4x paralelně, abych zjistil jak rychle dokáže vzdálený server načítat a zapisovat data na pevný disk.

Kompletní popis testu a výsledků je v angličtině zde:

https://stackoverflow.com/questions/58351839/is-file-get-contents-file-put-contents-reliable-or-can-lead-to-loss-of-data-b

graf zde:
(https://i.stack.imgur.com/fDp7V.png)

První tři testy T2, T3, T4 probíhaly s file_read_contents/file_write_contents, z toho jen T2 vykazuje takovou rychlost, která svědčí o faktickém čtení z disku (nikoliv z bufferu). T3 a T4 měly tak malé časy, že na grafu téměř nejsou vidět.

Pak je tam T5, T6 a T7 což je použití flock, fread, fflush + ověření správnosti zadaných dat, občas se selháním a následným obnovením souboru pomocí copy(). Všechny funkce měly smyčku s 50 cykly a prodlevu smyčky 50 microsekund. V posledním testu se to zdálo jako překážka, tak jsem to usleep v T7 odstranil.

Z výsledku mi vyplývá, že první dvě zmíněné funkce používají buffering a není na ně spoleh pokud jde o konkurenční zápis do spouboru. Při paralelním přístupu je třeba použít metodu flock, ffread, fflush, fwrite.

Zajímá mě, jestli mi tu můžete potvrdit správnost závěrů ke kterým jsem došel. Případně, pokud by byl zájem o zdrojáky testů, mohu poskytnout. Ale zajímá mě hlavně váš pohled na to, zda ten test má nějakou vypovýdající hodnotu. Jelikož jsem měl k dispozici 4 sady dat z každého testu, celkem 7*50*4 čísel, měl jsem dostatek čísel ke zhodnocení průměrů časů, odchylek, minimum a maxim, vytvoření grafů. Dělat další testy v oblasti prvních zmíněných funkcí mi už dál nepřipadalo užitečné, protože jsem nepřišel na to jak je donutit aby zapsaly celý obsah zásobníku do souboru (nebo aby si ten soubor skutečně přečetly z disku a ne z bufferu).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 15:50:11
Jako třetí parametr file_put_contents() zkus uvést konstantu LOCK_EX

Používám téměř výhradně tyto dvě funkce, ostatní jsem odstavil jako nepotřebné. Výsledky po úpravě volání mě zajímají.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 16:05:06
Ještě bych k tomu dodal, že pokud ty funkce používají buffering na úrovni souborového systému, což předpokládám, není nutné se obávat nespolehlivosti a nekonzistence. Ukaž příklad, kdy k něčemu takovému došlo a rozebereme příčiny. Bez zámků se to stává jen u souborů >8 KiB.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 16:34:00
Jako třetí parametr file_put_contents() zkus uvést konstantu LOCK_EX

Používám téměř výhradně tyto dvě funkce, ostatní jsem odstavil jako nepotřebné. Výsledky po úpravě volání mě zajímají.

Ale to tam mám.

test 2 obsahuje toto:
Kód: [Vybrat]
file_put_contents("523.txt",$s,LOCK_EX);
Díky za připomínku.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 16:39:07
Ještě bych k tomu dodal, že pokud ty funkce používají buffering na úrovni souborového systému, což předpokládám, není nutné se obávat nespolehlivosti a nekonzistence. Ukaž příklad, kdy k něčemu takovému došlo a rozebereme příčiny. Bez zámků se to stává jen u souborů >8 KiB.

Já ty data nekontroloval, velikost odpovídá, jenže jak vysvětlíš rozdíl v časech mezi T2 a T3, T4?

T2 bylo načítání z originálního souboru a zápis do jiného souboru (tedy dva různé soubory) a má výrazně vyšší časy, než když jsem použil T3, T4 se čtením ze stejného souboru do kterého jsem provedl zápis.

Kód T2:

Kód: [Vybrat]
echo "file_get_contents/file_put_contents test ".time()."<br>";
die;
while ( time()<1570604800 )
{
usleep(500);
}

$file = "temp.jpg";

echo "<h4>523 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("523");
 file_put_contents("523.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>948 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("948");
 file_put_contents("948.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1371 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("1371");
 file_put_contents("1371.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>1913 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("1913");
 usleep( 50 );
 file_put_contents("1913.txt",$s,LOCK_EX);
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>2701 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("2701");
 file_put_contents("2701.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>4495 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("4495");
 file_put_contents("4495.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>6758 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("6758");
 usleep( 50 );
 file_put_contents("6758.txt",$s,LOCK_EX);
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

T3:
Kód: [Vybrat]
echo "flock test ".time()."<br>";
die;
while ( time()<1570612500 )
{
usleep(500);
}

$file = "temp.jpg";

echo "<h4>523 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("523.txt");
 file_put_contents("523.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>948 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("948.txt");
 file_put_contents("948.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1371 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("1371.txt");
 file_put_contents("1371.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>1913 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("1913.txt");
 usleep( 50 );
 file_put_contents("1913.txt",$s,LOCK_EX);
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>2701 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("2701.txt");
 file_put_contents("2701.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>4495 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("4495.txt");
 file_put_contents("4495.txt",$s,LOCK_EX);
 usleep( 50 );
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

echo "<h4>6758 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
 $start = microtime(true);
 $s = file_get_contents("6758.txt");
 usleep( 50 );
 file_put_contents("6758.txt",$s,LOCK_EX);
 $time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}

To die na začátku tam je jen kvůli tomu, abych si nejdříve opsal čas a zkopíroval do while + 20 vteřin. To proto, aby se všechny 4 "exekuce" spustily ve stejný okamžik.

Kontrolu dat jsem prováděl jen od toho fflush, fwrite
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 16:50:27
Souborové systémy mají vlastní buffery a cache. Zkus z jednoho procesu neustále modifikovat jeden soubor a z druhého ho číst. Uvidíš, že je to spolehlivé.

V T2 máš chybu
Kód: [Vybrat]
$s = file_get_contents("523");Tohle čte ze souboru, který zřejmě neexistuje.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 17:02:53
Souborové systémy mají vlastní buffery a cache. Zkus z jednoho procesu neustále modifikovat jeden soubor a z druhého ho číst. Uvidíš, že je to spolehlivé.

V T2 máš chybu
Kód: [Vybrat]
$s = file_get_contents("523");Tohle čte ze souboru, který zřejmě neexistuje.

Všechny testy byly úspěšně zkontrolovány (kdyby neexistoval, dostal bych chybu).

523 je název originálního zdrojového souboru (obraz) 523 kB.
523.txt je název cílového souboru. Ta koncovka tam je jen pro rozlišení, trochu nelogické, já vím, ale já si tu koncovku oblíbil, protože obvykle pracuju s texťáky a ne s obrazy :)
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 17:06:21
Nevím sice, o co se pokoušíš, ale obávám se, že ses vydal chybnou cestou. Pokud ti dělají starosti kolize, měl bys použít databázi, která se o takové problémy sama postará a k tomu ti nabídne luxusní přístupové metody. PHP v základní výbavě nabízí 5 různých databází, ze kterých si určitě vybereš.

Takže co je účelem zkoumání čtení a zápisu souborů? Konfigurace, blog, diskuzní fórum, ... ?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 17:46:52
Nevím sice, o co se pokoušíš, ale obávám se, že ses vydal chybnou cestou. Pokud ti dělají starosti kolize, měl bys použít databázi, která se o takové problémy sama postará a k tomu ti nabídne luxusní přístupové metody. PHP v základní výbavě nabízí 5 různých databází, ze kterých si určitě vybereš.

Takže co je účelem zkoumání čtení a zápisu souborů? Konfigurace, blog, diskuzní fórum, ... ?

Takže přiznáváš, že u funkcí file_get_contents a file_put_contents existuje riziko kolize. Protože z tvého příspěvku to vyplývá. Se stejným přístupem mlžit a neříct to explicitně jsem se potkal na více místech internetu. To je ten důvod, proč jsem se vydal tou cestou, abych to prozkoumal. Jestliže považuješ file_get_contents a file_put contents za natolik nespolehlivé, že chceš raději používat databázi, nepřímo mi tím potvrzuješ výsledek mého zkoumání. Ale chtěl bych to slyšet explicitně, něco jako "Ano, už to tak asi bude" nebo "Z výsledků to vyplývá" nebo "Nevěřím tomu, jdu si to ověřit"... To je taky možnost.

Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis. Smůla je v tom, že kolizi nemám jak prokázat, protože tak chytrý algoritmus, který by zkontroloval validitu dat nemám. Mohu kontrolovat jen rozměr, ale to ještě nic nedokazuje. Podle mě čas zápisu na disk v rozsahu 22ms až 206 ms dokazuje (T2), že se jedná o čtení z disku a zápis na disk, kdežto časy u T3:

Kód: [Vybrat]
523 0,00251909
948 0,000630766
1371 0,002995359
1913 0,006401292
2701 0,002551624
4495 0,002908468
6758 0,019312313
a T4:
0,001060027
0,002461412
0,003131726
0,003644179
0,002659538
0,001959271
0,001399823
ukazují, že jde o čtení z bufferu. Tím pádem se nepokouší o ověřování skutečných dat a aktuálnost či správnost dat není zaručena. To co dělají ty funkce, že se podívají na jméno souboru a řeknou si "je to jeden a ten samý soubor" a obsahem se nezabývaj, prostě to tam plácnou tu starou kopii dat. Předpokládají, že ke změně nedošlo.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 18:45:07
Nevím sice, o co se pokoušíš, ale obávám se, že ses vydal chybnou cestou. Pokud ti dělají starosti kolize, měl bys použít databázi, která se o takové problémy sama postará a k tomu ti nabídne luxusní přístupové metody. PHP v základní výbavě nabízí 5 různých databází, ze kterých si určitě vybereš.

Takže co je účelem zkoumání čtení a zápisu souborů? Konfigurace, blog, diskuzní fórum, ... ?

Takže přiznáváš, že u funkcí file_get_contents a file_put_contents existuje riziko kolize. Protože z tvého příspěvku to vyplývá. Se stejným přístupem mlžit a neříct to explicitně jsem se potkal na více místech internetu. To je ten důvod, proč jsem se vydal tou cestou, abych to prozkoumal. Jestliže považuješ file_get_contents a file_put contents za natolik nespolehlivé, že chceš raději používat databázi, nepřímo mi tím potvrzuješ výsledek mého zkoumání. Ale chtěl bych to slyšet explicitně, něco jako "Ano, už to tak asi bude" nebo "Z výsledků to vyplývá" nebo "Nevěřím tomu, jdu si to ověřit"... To je taky možnost.

Nejde o kolizi těchto dvou funkcí, obě jsou atomické a spolehlivé. Problém je, pokud soubor přečteš, modifikuješ a uložíš. Tyto tři úkony nejsou v jedné transakci a proto při souběhu můžeš přijít o data. Pokud potřebuješ takový případ užití, použij databázi.

Uvědom si, že se vlastně sám snažíš vytvořit databázový engine, tedy vynalézáš kolo. Mnoho databází vypadá jako obyčejný textový soubor, ale ten engine nad nimi je už hotový a odzkoušený. Proč některý z těch pěti nepoužiješ? Chápu, že třeba nechceš použít MySQL, ale co ty ostatní? Zkusil jsi někdy nějakou databázi? Jsou tady proto, aby nám sloužily.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 18:46:58
Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.

Nedokazuje to vůbec nic.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 19:44:37
Problém je, pokud soubor přečteš, modifikuješ a uložíš. Tyto tři úkony nejsou v jedné transakci a proto při souběhu můžeš přijít o data.

Díky. To mi bohatě stačí. Proč ale tyto informace nejsou uvedeny v manuálu. To je přece důležitá informace. Když do googlu zadám např. "php file_get_contents you can lose data" tak nenajdu nic s tímto výskytem. Takže očividně se tato informace tají. Jak jinak si vysvětlit, že před tímto nezbytným faktem nevarují?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 19:56:30
Zajímavé je ale to, že v manuálu těch funkcí není nic o tom, že data jsou bufferované.

Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.

Nedokazuje to vůbec nic.

Ale jo, dokazuje to přesně to co si říkal. Je totiž z toho patrné, že ty data se nečtou z disku (rozuměj - z plotny), ale z bufferu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 20:10:54
Problém je, pokud soubor přečteš, modifikuješ a uložíš. Tyto tři úkony nejsou v jedné transakci a proto při souběhu můžeš přijít o data.
Díky. To mi bohatě stačí. Proč ale tyto informace nejsou uvedeny v manuálu. To je přece důležitá informace. Když do googlu zadám např. "php file_get_contents you can lose data" tak nenajdu nic s tímto výskytem. Takže očividně se tato informace tají. Jak jinak si vysvětlit, že před tímto nezbytným faktem nevarují?

Toto není nic, co by se tajilo. Je to základní vlastnost souborového systému, kterou by každý programátor měl znát. Týká se to všech programovacích jazyků, nejen PHP.

Kočku do mikrovlnky také nestrkáš, i když to v návodu není.

Doporučil jsem ti databázi proto, že umí zamknout nejen celý soubor, ale třeba jen kousek se záznamem, který chceš modifikovat. Umožní ti to modifikovat data třeba z deseti procesů současně, aniž by se mezi sebou popraly. Můžeš také jednu databázi sdílet třeba s deseti webovými servery. U fyzických souborů jsi bez šance na spolehlivé řešení.

K čemu potřebuješ v PHP práci se soubory?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 20:16:26
Zajímavé je ale to, že v manuálu těch funkcí není nic o tom, že data jsou bufferované.
Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.
Nedokazuje to vůbec nic.
Ale jo, dokazuje to přesně to co si říkal. Je totiž z toho patrné, že ty data se nečtou z disku (rozuměj - z plotny), ale z bufferu.

Buffery jsou záležitostí souborového systému, proto v manuálu PHP nesmí o nich být žádná zmínka. Jsou transparentní. Je úplně jedno, zda se data čtou z plotny nebo ze systémové cache. V obou případech se jedná o čerstvá data.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 20:32:01
Díky moc za odpovědi. Moc jsem se poučil a teď už mám klid. Takže teď už vím, že file_get_contents a file_put_contents jsou vlastně k ničemu. Neumím si představit k čemu bych je využil, když existuje riziko, že dva lidé odešlou do stejného souboru data, ale uloží se jen jeden, ten druhej ne. Je to úleva.

PS: Tys nikdy nedělal kočku v mikrovlnce?  ;D
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 20:37:31
Díky moc za odpovědi. Moc jsem se poučil a teď už mám klid. Takže teď už vím, že file_get_contents a file_put_contents jsou vlastně k ničemu. Neumím si představit k čemu bych je využil, když existuje riziko, že dva lidé odešlou do stejného souboru data, ale uloží se jen jeden, ten druhej ne. Je to úleva.

PS: Tys nikdy nedělal kočku v mikrovlnce?  ;D

Nejsem Alf :D

Ty dvě funkce jsou nejužitečnějsí ze všech funkcí, které pracují se soubory. Nemohou za to, že je používáš špatně pro naprosto nevhodný účel.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 20:41:50
Dej příklad jak by se dali použít. Chci si rozšířit obzory.

Tak jedno použití mě napadlo. Možná na stáhnutí vzdáleného souboru?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 20:57:00
Například načtení konfigurace, šablony, slovníku nebo číselníku; uložení vygenerovaného obrázku, sitemapy, PDF, konfigurace a kdovíčeho ještě. Když ukládáš pod unikátními názvy, tak kolize nehrozí.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 12. 10. 2019, 21:14:39
@exkalibr: Mám dojem, že se zabýváš složitým testem, ze kterého něco dedukuješ, ale přitom to co potřebuješ je zamknout soubor. Pokud to hodíš do googlu, tak najdeš spoustu řešení. Namátkou https://php.vrana.cz/atomicita-operaci.php , http://cubosoft.sweb.cz/Php/php/azphp510.htm , https://locallost.net/?p=1091 . Jak vidíš jsou to hodně letité odkazy, takže není pravda, že by se o tom nevědělo.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 22:05:09
Dík za článek. A proč prostě soubor nepřejmenovat?

Kód: [Vybrat]
if file exists jirka do:
  copy jirka jirka.backup
  rename jirka jirka.2
  open jirka.2
  read jirka.2
  add jirka.2
  save jirka.2
  close  jirka.2
  rename jirka.2 jirka
else:
while (delay) do:
 if file jirka exists do ...
endwhile;
endif;

Vtip je v tom, že pokud se se souborem pracuje, tak k němu žádný jiný program/skript nemůže. Je to geniálně jednoduché a nevyžaduje to zámky.

Dal by se do toho zakomponovat i test if jirka.2 exists do:
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 12. 10. 2019, 22:14:37
Dík za článek. A proč prostě soubor nepřejmenovat?

Přejmenování se pro docílení atomicity skutečně používá. V daném případě musíš ještě ošetřit situaci, kdy proces přejmenuje soubor a následně chcípne. Co teď?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 22:26:17
Dík za článek. A proč prostě soubor nepřejmenovat?

Přejmenování se pro docílení atomicity skutečně používá. V daném případě musíš ještě ošetřit situaci, kdy proces přejmenuje soubor a následně chcípne. Co teď?

Díky za potvrzení :) Jsem perfekcionista, počítal jsem s tím přece. Viz

Citace
Dal by se do toho zakomponovat i test if jirka.2 exists do:
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 12. 10. 2019, 22:29:27
Dík za článek. A proč prostě soubor nepřejmenovat?
Kód: [Vybrat]
if file exists jirka do:
  copy jirka jirka.backup
  rename jirka jirka.2
  open jirka.2
  read jirka.2
  add jirka.2
  save jirka.2
  close  jirka.2
  rename jirka.2 jirka
else:
while (delay) do:
 if file jirka exists do ...
endwhile;
endif;
Vtip je v tom, že pokud se se souborem pracuje, tak k němu žádný jiný program/skript nemůže. Je to geniálně jednoduché a nevyžaduje to zámky.
Dal by se do toho zakomponovat i test if jirka.2 exists do:
To mě nepřijde jako dobré řešení. Více procesů ve stejnou chvíli může vyhodnotit první řádek jako true a budou chtít provádět copy, rename.... Ten co bude o setinku pomalejší vyhodí chybu. Já jsem kdysi používal zámek pomocí vytváření a ověřování adresáře, protože mkdir je atomická a rychlá funkce. Pro permanentní zápisy do souboru je nejlepší databáze, tak jak ti Kid už napsal.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 22:45:56
Dík za článek. A proč prostě soubor nepřejmenovat?
Kód: [Vybrat]
if file exists jirka do:
  copy jirka jirka.backup
  rename jirka jirka.2
  open jirka.2
  read jirka.2
  add jirka.2
  save jirka.2
  close  jirka.2
  rename jirka.2 jirka
else:
while (delay) do:
 if file jirka exists do ...
endwhile;
endif;
Vtip je v tom, že pokud se se souborem pracuje, tak k němu žádný jiný program/skript nemůže. Je to geniálně jednoduché a nevyžaduje to zámky.
Dal by se do toho zakomponovat i test if jirka.2 exists do:
To mě nepřijde jako dobré řešení. Více procesů ve stejnou chvíli může vyhodnotit první řádek jako true a budou chtít provádět copy, rename.... Ten co bude o setinku pomalejší vyhodí chybu. Já jsem kdysi používal zámek pomocí vytváření a ověřování adresáře, protože mkdir je atomická a rychlá funkce. Pro permanentní zápisy do souboru je nejlepší databáze, tak jak ti Kid už napsal.

Máš pravdu, to rename musí následovat hned za if, pak už je pozdě. Copy provést až po přejmenování. Mě připadá že vytváření adresáře je složitější proces než přejmenování. FS si musí kvůli tomu vytvořit nový záznam, kdežto při rename souboru nemusí vytvářet nic... Ale mohu otestovat ten rename a říct ti jestli je to spolehlivější než T7.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Vít Šesták (v6ak) 12. 10. 2019, 23:14:34
1. Minimálně musíte zkontrolovat výsledek rename. K rename může dojít více procesů, jen jeden z nich ale projde.
2. Nerozumím Vašemu řešení, jak ošetříte situaci, kdy aplikace spadne. Ta situace přece vypadá úplně stejně, jako kdyby druhý proces byl aktivní. A když už to detekujete, otázka je, co s tím uděláte…
3. Tomu cyklu na konci asi nerozumím, nicméně  vypadá to jako busy waiting. To zrovna dvakrát elegantní není. Žere to CPU, ačkoli by proces mohl pokojně spát a čekat na I/O.
4. Opravdu nechcete použít databázi, kde za Vás někdo podobné problémy již vyřešil?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 12. 10. 2019, 23:32:48
Tak to nefunguje. Povedlo se otestovat jen dva bloky, ale mají příliš vysoký čas. Možná kvůli té testovací smyčce (i když file_exists asi hledá v bufferu, že?).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 12. 10. 2019, 23:35:03
Mě připadá že vytváření adresáře je složitější proces než přejmenování.
Myslím, že jsem se rozhodl pro mkdir, protože mě to někdo doporučil jako nejrychlejší atomickou funkci vhodnou k zamykání souborů. Předpokládám, že zamykat soubor potřebuješ především kvůli kolizi více procesů při zápisu, ale né při čtení. Pokud použiješ rename, tak si daný soubor zablokuješ i pro procesy, které si chtějí jen číst a nehodlají zapisovat, resp. musel bys i ve čtecích funkcích ošetřit, že se soubor může jmenovat jirka nebo jirka.2.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 07:44:34
Dneska vyzkouším ten mkdir.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 08:55:53
Zatím se mi to nedaří rozjet. Kontrola kódu:

function atomicFuse($n){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
  if ( $start == false )
   usleep($n*16);
  return $start;
}

  for ($i = 0; $i<2; $i++ ){
    $start_time = microtime(true);
      {
      $start = atomicFuse($n);
      // If n*16 used then 6 time repeat:
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) echo "Atomicity failed. ";
      if ( $start )
         {
         .... do této větve se nedostane
         }
     }
     $time_elapsed_secs = microtime(true) - $start_time;
     if ( $time_elapsed_secs === 0 )
       echo " FAILED ";
   }

Pro srozuměnou: n je velikost souboru v kb.
Pro n= 948 tak vychází prodleva 16116 čili 0,016116 mikrosekund.

Výstup:

523 at 1570949057
Atomicity failed. skippedtime: 0.050755023956299 s
Atomicity failed. skippedtime: 0.050696134567261 s
948 at 1570949057
Atomicity failed. skippedtime: 0.091481924057007 s
Atomicity failed. skippedtime: 0.091547012329102 s
1371 at 1570949057
Atomicity failed. skippedtime: 0.13213992118835 s
Atomicity failed. skippedtime: 0.13215684890747 s
1913 at 1570949057
Atomicity failed. skippedtime: 0.18418097496033 s
Atomicity failed. skippedtime: 0.1841561794281 s
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 09:18:23
Ok, tak už to asi mám, ale není to úplně ideální občas tam mám chybu "atomicity failed" (to by mohlo nastat pokud čeká moc dlouho). Občas je tam chyba zápisu do souboru.

Celý kód

clearstatcache();
$_DEBUG_ = false;

echo "Atomicity tester.".time()."
";
die;

while ( time()<1570950820 )
 {
 usleep(500);
 }

function atomicFuse($n, $disableDelay = false){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
  if ( !$disableDelay ){
    if ( $start == false )
     {
     usleep($n*3);
     echo ($n*3)."
";
     }
    }
  return $start;
}
function test($n, $p, $_DEBUG_){
  $fp = null;
  $sname = "$n";    // source
  $tname = "$n.txt";// target
  echo "<h4>$n at ".time()."</h4>";
  for ($i = 0; $i<2; $i++ ){
    $start_time = microtime(true);
      {
      $start = atomicFuse($n);
      // If n*16 used then 6 time repeat:
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n, false);
      if (!$start) echo "Atomicity failed. ";
      if ( $start )
         {
         /////////////////////////////
         // CHECK FILESIZE VALIDITY //
         /////////////////////////////
         clearstatcache(); // needed for filesize and touch   
         $st = stat("$sname");
         $original_size = $st['size'];
         if ( $_DEBUG_ )
           echo "; 1) prevAccess by ".$st['mtime']." fsize ".$st['size']."; ";
         $fsize = filesize($sname);
         if ( $original_size <> $fsize )
           die("; fsize total FAILTURE; ");
         if ($fsize === 0)
          echo "! The fsize is 0: stat(): ".$st['size']." ;";   
         ///////////////////
         // OPEN THE FILE //
         ///////////////////
         $fp = fopen($sname, "r");
         $s = fread($fp, $fsize );
         $success = fclose($fp);
         if ( $success === false  )
           die("; fclose failed; ");
         // 10 - data načtená , $p - prohlížeč
         if ( $success )
           {
           $result = touch("$sname",strlen($s),$p);
           if ( $_DEBUG_ )
              echo "; TOUCH: $result;";
           }
         else
           die("fclose FAIL.");
         if ( strlen($s)<60 )
            echo "*$s LENGTH:".strlen($s)."
";
         } 
      }
    if ( $start )
      {
      clearstatcache();
      $st = stat("$tname");                               
      if ( $_DEBUG_ )
        echo "; 2) prevAccess by ".$st['mtime']." fsize is ".$fsize."; ";
 
      // WRITE OPERATION WITH LOC_EX
      $fp = fopen($tname, "w");
      if ( true ) {  // acquire an exclusive lock
          $success = fwrite($fp, $s);
          if ( $success === false)
            echo "; w FAILED;";
          else
            if ( $_DEBUG_ )
                  echo " $success B written; ";
          $success = fflush($fp);// flush output before releasing the lock
          if ( $success === false )
            echo "; flush FAILED; ";
          if ( $success === false )
            echo "; release FAILED; ";
          $success = fclose($fp);
          if ( $success === false )
            echo "; fclose FAILED; ";
          clearstatcache(); // needed for filesize and touch
          $fsize = filesize($tname);
          if ($original_size>$fsize)
              {
              echo "; WRITE FAILED, restoring;";
              $original_fname = "$n";
              $result = copy($original_fname, $tname);
              if ($result == false )
                die(" TOTAL FAILTURE: copy failed.");
              else
                echo " RESTORED;";
              }
          else
            {
              if ($fsize === 0)
               echo "! THE FILE WAS NOT WRITTEN: data length: ".strlen($s)." fsize: $fsize RESOURCE: $fp
";   
              if ( $success )
                  touch("$tname",$fsize,$p);
            }
          } else {
              echo "Couldn't get the lock!";
             }
      } // start
     else
       echo "skipped";
     $success = rmdir("$n.t"); // remove atomic fuse
       if ( $success )
         echo "<h4>DIR REMOVED</h4>";
       else
         echo "<h4>DIR NOT REMOVED</h4>";
     $time_elapsed_secs = microtime(true) - $start_time;
     if ( $time_elapsed_secs === 0 )
       echo " FAILED ";
     echo "time: $time_elapsed_secs s
";
  } // for
}

switch ( $_SERVER['HTTP_USER_AGENT'] ):
  // FF 1:
  case "":
    $p = 1; break;
  // Chrome:
  case "":
    $p = 2; break;
  // OPERA:
  case "": 
    $p = 3; break;
endswitch;

copy("523","523.txt");
copy("948","948.txt");
copy("1371","1371.txt");
copy("1913","1913.txt");
copy("2701","2701.txt");
copy("4495","4495.txt");
copy("6758","6758.txt");

test("523",$p,$_DEBUG_);
test("948",$p,$_DEBUG_);
test("1371",$p,$_DEBUG_);
test("1913",$p,$_DEBUG_);
test("2701",$p,$_DEBUG_);
test("4495",$p,$_DEBUG_);
test("6758",$p,$_DEBUG_);
die;
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: tecka 13. 10. 2019, 09:35:15
Tak jsme se zasmáli. A co teď?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 09:49:32
Už to jede zatím test jen se dvěma cykly.

Chyba byla rmdir v nesprávné větvi, delay byl trochu malý a je třeba víckrát opakovat test existence souboru. Tady se může opakovat až 15x. Problém je totiž ve velkém rozsahu hodnot (prodlev), které mohou nastat. Původně jsem to totiž nastavoval na průměry a nepodíval jsem se do skutečných hodnot. U půl megabajtového souboru jdou minima a maxima od 0,001 až na 0,2s.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 11:08:04
Kód: [Vybrat]
function atomicFuse($n, $c, $disableDelay = false){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
  if ( !$disableDelay ){
    if ( $start == false )
     {
     $n = $n*30;
     switch($c):      // Delay example increase:
       case 0: break; // 0,01569 total
       case 1: break; // 0,03138 total
       case 2: $n = $n*2; break; // 0,06276 total
       case 3: $n = $n*4; break; // 0,12552 total
       // case 4: You need at least *6 or *8 to get out of problems with extrem times
       case 4: $n = $n*6; break; // 0,21966 t.(upper limit)
       case 5: $n = $n*6; break; // 0,3138 total extrem
       case 6: $n = $n*4; break; // 0,36087  total extrem
       case 7: $n = $n*4; break; // 0,42363 total extrem
       default: break;
     endswitch;
     usleep($n);
     echo ($n)."<br>";
     }
    }
  return $start;
}

implementace.
Kód: [Vybrat]
      $start = atomicFuse($n,0);
      if (!$start) $start = atomicFuse($n,1);
      if (!$start) $start = atomicFuse($n,2);
      if (!$start) $start = atomicFuse($n,3);
      if (!$start) $start = atomicFuse($n,4);
      if (!$start) $start = atomicFuse($n,5);
      if (!$start) $start = atomicFuse($n,6);
      if (!$start) $start = atomicFuse($n,7);
      if (!$start) $start = atomicFuse($n, false);
      if (!$start) echo "<b>Atomicity failed.</b> ";
      if ( $start )
         {
         echo "<b>Atomicity OK.</b> ";
         // perform atomic action
         $success = rmdir("$n.t"); // remove atomic fuse
         }

Zatím testuju se smyčkou 10 cyklů.

Dám příklad ~500kB s aktuálními chybama:
CHROME OK - první dva požadavky na soubor jsou za 0.003s a 0.047s
FF1 OK - za 0,2196s
FF2 OK - 0,45501s
OPERA hned na jednou začátku selže: protože má čas 0,45501 ...

Vysvětlení chyby: Ten požadavek z Opery se začne vyhodnocovat později např. při 0,45500s a v té době se požadavek od FF2 ještě vyřizuje. Takže řešením je jedině zvýšit počet požadavků na čekání nebo prodloužit prodlevu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 11:57:50
Konec testů.

Shrnutí
Hlavním faktorem úspěšnosti testu je délka smyčky neboli počet cyklů. Pokud je počet cyklů větší než 6, tak začne vykazovat pár chyb. Nad deset je chybovost vyšší a s dalšími desítkami se zvyšuje. Nejde zde o velikost souboru, i velký soubor např 6MB se zpracuje rychle. Problém je v tom, že se v jednom okamžiku očekává mnoho úloh. Například skript jedna zpracovává 6 požadavků a druhý skript musí čekat. Chyby se objevují na začátku. Při posledním testu s 50 cykly jsem dostal následující chybovost:

požadavek z Chrome: 6 neprovedených úkonů (4x 523kB a 2x 948kB)
požadavek z FF1: 5 neprovedených úkonů (prvních 5 souborů ~523kB)
požadavek z Opery: 0 neprovedených úkonů (100% OK)
požadavek z FF2:   0 neprovedených úkonů (100% OK)

Aktuální funkce:

Kód: [Vybrat]
function atomicFuse($n, $c, $disableDelay = false){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
  if ( !$disableDelay ){
    if ( $start == false )
     {
     $n = $n*30;
     switch($c):      // Delay example increase:
       case 0: break; // 0,01569 total
       case 1: break; // 0,03138 total
       case 2: $n = $n*2; break; // 0,06276 total
       case 3: $n = $n*4; break; // 0,12552 total
       // case 4: You need at least *6 or *8 to get out of problems with extrem times
       case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
       // In case of heavy traffic:
       case 5: $n = $n*8; break; // 0,36087 total extrem
       case 6: $n = $n*10; break; // 0,51777 total extrem
       case 7: $n = $n*20; break; // 1,03554 total extrem
       default: $n = $n*8; break;
     endswitch;
     usleep($n);
     echo ($n)."<br>";
     }
    }
  return $start;
}
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 13. 10. 2019, 12:20:37
Můžeš mi prosím napovědět k čemu ten výsledek testu je? O čem ty čísla svědčí ve vztahu k tvému úvodnímu příspěvku?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 15:33:44
Ahoj ještě nevím. Data budu za chvíli zpracovávat. Mám na to několik tabulek a grafů. Podle toho pak poznám o čem to svědčí. Co si myslím teď se ještě může změnit. Jisté je jen to, že ty prodlevy, které tam jsou, jsou závislé na tom typu testu - php skript se smyčkou. Kdyby si podnikl jiný druh "útoku" na server například smyčkou v JS odeslal požadavky post() AJAXEM a já bych každý jednotlivý požadavek zpracoval jako načtení a zápis, tak by se to zcela určitě chovalo úplně jinak. Myslím, že tento test co jsem prováděl byl dost vytěžující, ale jinak než běžné přístupy nebo než DOS útoky. Každopádně jsem ti vděčný za poznání druhé metody, která se chová trochu jinak, obě metody mají něco do sebe. Tento test jsem pojmenoval jako T8. Dokonalé to asi nebude nikdy.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 15:50:25
Můžeš mi prosím napovědět k čemu ten výsledek testu je? O čem ty čísla svědčí ve vztahu k tvému úvodnímu příspěvku?

K čemu je procházení slepými uličkami? K ověření, že jsou slepé. Nejspíš to nikde neuplatní, ale během těch testů se toho dost naučí o chování souborových systémů a v budoucnu nebude vyjevený z nějakých kolizí.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 16:22:38
Graf s T8, atomicity tester with directoryFuse.

Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 16:52:20
Selhání

Ještě bych dodal, že u T5-T7 šlo o jiná selhání než u T8. Selhání T8 se týkají atomicity - akce není provedena vůbec. T5-T7 tam jde o problém se zápisem dat - po zapsání fwrite není správná velikost dat, ačkoliv byl použít flock.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 17:07:37
Kód: [Vybrat]
function atomicFuse($n, $c, $disableDelay = false){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
   ...

Zkus ten mkdir použít takhle:
Kód: [Vybrat]
if (@mkdir("$n.t")) {
    // akce
    rmdir("$n.t");
}
Vyloučíš tím kolizi.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 13. 10. 2019, 18:18:24
@exkalibr: Tak teď jsem se v tom tvém testování úplně ztratil. Jak můžeš do toho grafu zahrnout test "mkdir"? Vždyť to je zase nový test, který je napsaný zase trochu jinak a nechápu jeho spojení s těmi předchozími testy. Už před tím když jsi psal "V posledním testu se to zdálo jako překážka, tak jsem to usleep v T7 odstranil" jsem nechápal jak můžeš takový test do grafu výsledků zahrnout, přece když odstraníš prodlevu, tak tím ovlivníš i výsledný počet sekund, které se pak objevily v tom grafu. Asi jsem na grafy už moc starý :)

Zatím jsem si z tvého grafu odnesl jen to, že na nějakém (nevím jakém) filesystému se určité I/O příkazy v PHP buferují. Myslím, že u jiného filesystému se ale buferovat nemusí.

Mně by dávalo smysl udělat test, který by obsahoval několik funkcí a každá by používala jiný způsob zamykání (mkdir, rename, flock, semafory, ...) a vyhodnotil bych jejich rychlost. Ten nejrychlejší bych pak používal. Pokud by bylo zamykání dobře udělané, tak by si 1. funkce zamkla soubor a ostaní funkce (třeba i z jiných procesů) by čekaly a jediná chyba, která by se mohla objevit by bylo překročení "maximum execution time" (u PHP defaultně 30 sekund).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 18:50:23
Máš pravdu, musíš si prostě v hlavě odečíst 50 mikrosekund u každé hodnoty :(
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 19:08:29
Jenže těch 50 mikrosekund nemá na výsledek grafu žádný vliv. My se pohybujeme v řádů setin až desetin. To se zaokrouhlí a průměry se nezmění. Vliv to má na chování programu. Já si už u T7 všiml, že když odstraním delay je to spolehlivější než když ten čas navyšuju. Ta prodleva je zdrojem problémů u T8. Proto bych v praxi raději volil metodiku T7, která je dvakrát rychlejší. V praxi stejně ke kolizi dojde málokdy a když k ní dojde tak ověřením ji mohu obnovit ze zálohy.

Pro mě výsledek testu znamená, že registraci nemusím dělat do db. Nemusím dokonce dělat ani vzkazník do db. Co ale musím udělat do db je anketa, kde budou uživatelé klikat pomocí AJAXu, a tam se obávám, že by ke kolizím mohlo snadno dojít (zápis do toho samého souboru).

Rename jsem ale zavrhl kvůli tomu, že nadělá strašnou paseku, pokud operace selže. Kdo to pak má přejmenovávat všechny ty soubory?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 13. 10. 2019, 20:05:07
Ta prodleva je zdrojem problémů u T8. ... V praxi stejně ke kolizi dojde málokdy a když k ní dojde tak ověřením ji mohu obnovit ze zálohy.
Jestli se bavíme o situaci kdy máš soubor zamknutý, tak dokážeš ty "problémy" a "kolize" ke kterým dojde málokdy nějak jednoduše pojmenovat? Z toho co jsi psal před tím jsem to nepochopil. Jediný "problém" co mě napadá by měl být ten "maximum execution time" o kterém jsem psal. A pokud ti dochází k jiným kolizím při zamknutém souboru, tak bych řekl, že to zamykání máš špatně, např. kvůli tomu file_exists o kterém psal Kid (https://forum.root.cz/index.php?topic=21940.msg318442#msg318442).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 21:33:43
Při T5-T7 je problém při zápisu do souboru fwrite, fflush. To jsem už psal.

Zamknuté to je. Stručně:

Kód: [Vybrat]
$locked = flock($fp, LOCK_SH);
$s = fread($fp, $fsize );
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$fp = fopen($tname, "w");
$locked = flock($fp, LOCK_EX);
$success = fwrite($fp, $s);
$success = fflush($fp);
$success = flock($fp, LOCK_UN);
$success = fclose($fp);

Ale teď se dívám, že jsem tam mohl dát LOCK_EX místo LOCK_SH, to LOCK_SH tam nedává smysl. Ale má to vliv?

Kód: [Vybrat]
$locked = flock($fp, LOCK_SH)
OK, tak jsem to testnul a řekněte mi jestli ten kód je dobře:

Kód: [Vybrat]
function atomicFuse($n, $c, $disableDelay = false){
  $start = false;
 
  if ( @mkdir("$n.t") )
   $start = true;
  if ( !$disableDelay ){
    if ( $start == false )
     {
     $n = $n*30;
  ...
V té funkci je $start = true když je povoleno provádět atomicitní operaci jinak je false.

Výsledek:
FF1 - failed 0x
Chrome - failed 0x
FF2 - failed 2x
Opera - failed 5x
Celkem atomicity failed 7x - což ale nutně neznamená, že je to lepší. Někdy může být selhání více, někdy méně, jak tu bylo řečeno, tohle závisí na OS, který proces si zrovna upřednostní. Závěr ale je, že k porušení atomicity došlo.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 21:46:42
LOCK_EX se dává v případě, že chceš do souboru zapisovat.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 21:57:45
Původně mi šlo o testování rychlosti během čtení/zápisu na server při spuštěných 4 procesech současně. T7 se povedlo otestovat s malým množstvím chyb, ale nyní těch chyb je kopa, to nemá cenu počítat. Nevím co se změnilo. Tak by T8 možná mohl vyjít spolehlivěji, ale ve výsledku ani jedna operace není dokonale spolehlivá.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 23:15:15
Stačí jediná chyba a můžeš tu metodu zahodit.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 13. 10. 2019, 23:29:23
Čím si vysvětluješ, že ani flock nepomůže k zajištění atomicity?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 23:35:52
Nezkoumal jsem to tak podrobně, jen vidím, že proměnná $start je zcela zbytečná a může ty problémy způsobovat.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 23:40:19
Zamknuté to je. Stručně:
Kód: [Vybrat]
$locked = flock($fp, LOCK_SH);
$s = fread($fp, $fsize );
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$fp = fopen($tname, "w");
$locked = flock($fp, LOCK_EX);
$success = fwrite($fp, $s);
$success = fflush($fp);
$success = flock($fp, LOCK_UN);
$success = fclose($fp);

Zamknuté to není, protože to v polovině odemykáš a zase zamykáš. V tu chvíli si ten soubor zamkne jiný proces a máš kolizi.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 13. 10. 2019, 23:58:14
Zkus tuto jednoduchou úpravu, jak bude reagovat na souběhy:
Kód: [Vybrat]
$fp = fopen($tname, "r+");
flock($fp, LOCK_EX);
$s = fread($fp, $fsize);
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, $s);
fclose($fp);
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 01:54:11
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 07:56:46
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)

V podstatě tam píší jen to, že mezi voláním fopen() a flock() si ten soubor může zamknout někdo jiný. Tedy nic, co by se nedalo ošetřit testem návratové hodnoty flock().

Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 08:07:36
Čím si vysvětluješ, že ani flock nepomůže k zajištění atomicity?
Připadá mi, že se snažíte testovat nějaké bufferování nebo co, ale přitom máte zmatek v tom, co je atomicita a jak se používají zámky. Zámky nezajišťují atomicitu – zajistí jenom to, že ze/do souboru může současně číst/zapisovat jenom jeden proces. Nezajistí ale, že ten zápis bude atomický. Navíc vůbec nepředpokládáte, že získání zámku může selhat, ani že může selhat otevření souboru – myslím, že zrovna v těchto případech je to dost odvážný předpoklad.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 08:11:38
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Mohl byste to rozepsat? Atomicita znamená, že se daná funkce provede celá nebo vůbec a že nikdo nemůže vidět nějaký vnitřní mezistav té funkce. V případě zámků atomicita znamená, že na souboru nějaký zámek je nebo není – nemůže nastat stav, že by tam zámek byl tak trochu. Atomicita se ale samozřejmě posuzuje z hlediska jedné funkce – to, že se něco může stát před voláním flock() nemá na atomicitu funkce flock() vliv.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 09:02:03
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.

Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 09:41:45
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.
Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 09:49:28
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.
Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.

V testech je naopak výhodné, pokud se ty procesy co nejvíc potlučou mezi sebou - proto jsou ty časové odstupy zbytečné a kontraproduktivní.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 09:55:24
Správně se to dělá tak, že se proces nejprve pokusí zamknout všechny soubory, které bude potřebovat ke své práci. Pokud některý ze zámků selže, všechny odemkne, počká náhodnou dobu a pokusí se znovu nasadit všechny zámky.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 09:59:55
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Mohl byste to rozepsat? Atomicita znamená, že se daná funkce provede celá nebo vůbec a že nikdo nemůže vidět nějaký vnitřní mezistav té funkce. V případě zámků atomicita znamená, že na souboru nějaký zámek je nebo není – nemůže nastat stav, že by tam zámek byl tak trochu. Atomicita se ale samozřejmě posuzuje z hlediska jedné funkce – to, že se něco může stát před voláním flock() nemá na atomicitu funkce flock() vliv.
Myslel jsem to tak, jak se píše v tom odkazu, tzn. že mezi fopen a flock se může dostat jiný proces. Spolehlivější mně připadá zapisování s file_put_contents, který může mít parametr LOCK_EX. (To samozřejmě v praxi neřeší problém čtení, kde mezi čtením a zápisem může druhý PHP proces zapsat do čteného souboru - tím dojde ke ztrátě dat z tohoto druhé PHP procesu, protože daný soubor v zápětí přepíše ten první PHP proces. Tohle si musí programátor ošetřit ručně.)

Pokud bych to tedy měl říci přesně, tak flock() je atomická funkce, ale ke svému využití potřebuje fopen(), a spojení fopen()+flock() atomické není.

Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 10:10:04
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
V podstatě tam píší jen to, že mezi voláním fopen() a flock() si ten soubor může zamknout někdo jiný. Tedy nic, co by se nedalo ošetřit testem návratové hodnoty flock().
Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?
Ano uklízení po mkdir() musíš ošetřit ručně. Nevím jak je to přesně u flock(), ale předpokládám, že i tam se ti zámek může seknout a pak musíš mít nějakou vlastní funkci, která ji natvrdo odblokuje.

Nevýhodu vidím v tom, že testem návratové hodnoty flock() vytvoříš smyčku mezi flock() a fopen(). Pokud bys pustil vytěžující scripty (o což se Exkalibr snaží), tak by se smyčka nemusela stihnout dokončit do konce běhu PHP scriptu a script by spadl. Pokud si uděláš vlastní funkcí pomocí mkdir(), tak ji zavoláš ještě před fopen().
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 10:14:56
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.
Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.

V testech je naopak výhodné, pokud se ty procesy co nejvíc potlučou mezi sebou - proto jsou ty časové odstupy zbytečné a kontraproduktivní.
Ano souhlasím, jen jsem narážel na to, že tady Exkalibr pořád háže nějaké čísla s počtem chyb, které mají jen tu vypovídací hodnotu, že to má špatně zamknuté. Jestli je tam 1 chyba nebo 30 chyb, tak je to jedno.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 10:17:15
Myslel jsem to tak, jak se píše v tom odkazu, tzn. že mezi fopen a flock se může dostat jiný proces.
To ale neznamená, že flock() není atomický.

Pokud bych to tedy měl říci přesně, tak flock() je atomická funkce, ale ke svému využití potřebuje fopen(), a spojení fopen()+flock() atomické není.
To, že volání dvou funkcí po sobě není atomické, je naprostý základ. Bez pochopení téhle věci je zbytečné pokoušet se programovat cokoli se zámky nebo řešit nějakou atomicitu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 10:23:25
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
V podstatě tam píší jen to, že mezi voláním fopen() a flock() si ten soubor může zamknout někdo jiný. Tedy nic, co by se nedalo ošetřit testem návratové hodnoty flock().
Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?
Ano uklízení po mkdir() musíš ošetřit ručně. Nevím jak je to přesně u flock(), ale předpokládám, že i tam se ti zámek může seknout a pak musíš mít nějakou vlastní funkci, která ji natvrdo odblokuje.

Nevýhodu vidím v tom, že testem návratové hodnoty flock() vytvoříš smyčku mezi flock() a fopen(). Pokud bys pustil vytěžující scripty (o což se Exkalibr snaží), tak by se smyčka nemusela stihnout dokončit do konce běhu PHP scriptu a script by spadl. Pokud si uděláš vlastní funkcí pomocí mkdir(), tak ji zavoláš ještě před fopen().

Proto se do toho zamykacího cyklu vkládá náhodná prodleva, aby se snížilo riziko náhodné kolize.

Flock je automaticky odstraněn zavřením souboru. Není třeba řešit jeho odstranění ručně.

Pokud skript spadne, tak spadne. Obvykle to ničemu nevadí a je to zcela běžné. Klient si ho spustí znovu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 11:02:38
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.
Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.

Ale ty zámky jsou přece nastaveny správně, copak si neviděl kód?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 11:04:56
Pokud skript spadne, tak spadne. Obvykle to ničemu nevadí a je to zcela běžné. Klient si ho spustí znovu.

Pokud spadne tak tam zůstane ten vytvořený adresář, který nikdo nesmazal. Ten script pak nepůjde provést. Musel bych tam spouštět čas od času udržovací script, který by promazal ty staré adresáře - ale to je zase zátěž na víc a navíc to neřeší problém úplně. Protože nějakou dobu to spustit nepůjde.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 11:07:11
Správně se to dělá tak, že se proces nejprve pokusí zamknout všechny soubory, které bude potřebovat ke své práci. Pokud některý ze zámků selže, všechny odemkne, počká náhodnou dobu a pokusí se znovu nasadit všechny zámky.

Já bych ten soubor mohl mít jen jeden, ale pokud použiju rejstříky a indexy - další dva soubory pro urychlení parsování/hledání - tak to budou 3.

Co když ten skript spadne, soubor zůstane zamknut? Jak dlouho?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 11:14:21
Pokud skript spadne, tak spadne. Obvykle to ničemu nevadí a je to zcela běžné. Klient si ho spustí znovu.

Pokud spadne tak tam zůstane ten vytvořený adresář, který nikdo nesmazal. Ten script pak nepůjde provést. Musel bych tam spouštět čas od času udržovací script, který by promazal ty staré adresáře - ale to je zase zátěž na víc a navíc to neřeší problém úplně. Protože nějakou dobu to spustit nepůjde.

Nepoužívám mkdir(), ale flock(), který je spolehlivý a při zavření souboru (i při pádu procesu) se sám odemkne.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 11:19:08
Správně se to dělá tak, že se proces nejprve pokusí zamknout všechny soubory, které bude potřebovat ke své práci. Pokud některý ze zámků selže, všechny odemkne, počká náhodnou dobu a pokusí se znovu nasadit všechny zámky.
Já bych ten soubor mohl mít jen jeden, ale pokud použiju rejstříky a indexy - další dva soubory pro urychlení parsování/hledání - tak to budou 3.

Tak si zamkni jen jeden a říkej mu semafor.

Rejstříky, indexy,... přiznej se, že ty v PHP vyrábíš databázi?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 11:50:43
T8 mkdir, jinak
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 11:54:07
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.  :o
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 12:03:04
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.
Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.

Ale ty zámky jsou přece nastaveny správně, copak si neviděl kód?
Viděl, ale je to pro mě nepřehledné a nechce se mi v tom vrtat, ale jen tak namátkou. V tom T7 co máš na stackoverflow.com vidím zhruba toto:

//read
fopen $sname
flock lock_sh
$s=fread
flock lock_un
fclose $sname
touch $sname

//write
fopen $tname
flock lock_ex
fwrite $s
fflush
flock lock_un
fclose

Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 12:21:55
... pak mám dojem, že příkaz "touch("$tname",$fsize,$p);" používáš ve chvíli kdy jiný proces může mít daný $tname soubor zamklý pomocí lock_ex.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 12:29:46
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.  :o

To vadí? Mně tedy ne.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 12:36:06
Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?

Všechny chyby, které nastaly jsem už popsal, jednalo se tam o selhání zápisu nic víc. Všechny hlášky mám ošetřené. flock neselhal ani jednou, vždy byl výsledek true.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 12:37:03
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.  :o

To vadí? Mně tedy ne.

Nabourává to ten script, takže není atomicitní.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 12:50:38
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.  :o

To vadí? Mně tedy ne.

Nabourává to ten script, takže není atomicitní.

Nenabourá. Jen je třeba výsledek flock() testovat a zachovat se podle toho.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 12:51:51
Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?
Všechny chyby, které nastaly jsem už popsal, jednalo se tam o selhání zápisu nic víc. Všechny hlášky mám ošetřené. flock neselhal ani jednou, vždy byl výsledek true.
Jestli myslíš tím "selhání zápisu" tento blok:
Kód: [Vybrat]
$fsize = filesize($tname);
        if ($original_size>$fsize)
            {
            echo "; <b>WRITE FAILED, restoring</b>;";
            $original_fname = "$n";
            $result = copy($original_fname, $tname);
            if ($result == false )
              die(" <b>TOTAL FAILTURE: copy failed.</b>");
            else
              echo " <b>RESTORED</b>;";
            }
        else
...

tak celý ten blok používáš až po lock_un, takže zjišťuješ velikost souboru ve chvíli kdy do něj zapisuje jiný proces.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 13:02:09
Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?
Všechny chyby, které nastaly jsem už popsal, jednalo se tam o selhání zápisu nic víc. Všechny hlášky mám ošetřené. flock neselhal ani jednou, vždy byl výsledek true.
Jestli myslíš tím "selhání zápisu" tento blok:
Kód: [Vybrat]
$fsize = filesize($tname);
        if ($original_size>$fsize)
            {
            echo "; <b>WRITE FAILED, restoring</b>;";
            $original_fname = "$n";
            $result = copy($original_fname, $tname);
            if ($result == false )
              die(" <b>TOTAL FAILTURE: copy failed.</b>");
            else
              echo " <b>RESTORED</b>;";
            }
        else
...

tak $fsize používáš až po lock_un, takže zjišťuješ velikost souboru ve chvíli kdy do něj zapisuje jiný proces.

A jsi si jistý, že je možné správně zjistit velikost souboru, když je soubor otevřený pro zápis?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 13:26:50
A jsi si jistý, že je možné správně zjistit velikost souboru, když je soubor otevřený pro zápis?

Místo vyptávání by sis měl napsat test. Malá nápověda: fstat()
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 13:29:38
A jsi si jistý, že je možné správně zjistit velikost souboru, když je soubor otevřený pro zápis?
Tím si jistý nejsem, to musíš vědět ty, je to tvůj domácí úkol :). Já jen vím, že zjišťování velikosti souboru, kdy do něj jiný proces zapisuje není správné, takže to vypadá, že nešlo o žádné skutečné chyby při zápisu, ale pouze jsi špatně srovnával velikost source a target souboru.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 13:48:29
A co takhle zkusit vyrobit jiný typ zámku, který by byl spolehlivější. Zkusím dát návrh. V tomto návrhu mi jde o vzkazník, kde každý uživatel má vlastní složku a v ní několik souborů s příchozí a odchozí poštou apod.

Chci přečíst a zapsat data pro příchozí poštu.

Krok 1) Kontrolní krok - zatím vynechám popis

Krok 2)

Zjistím jaký je aktuální mikročas. Zjistím jaké je aktuální číslo, zajímají mě poslední dvě číslice. Např. 99

Do složky data/username/rq si vytvořím nový prázdný soubor 99.

Nastavím hodnotu posledního přístupu podle toho s jakým souborem chci pracovat (prostě číslo souboru označuje určitý soubor v osobní složce).

Pak nastavím časovač něco jako
usleep( rand(1,500) );

Dále zkontroluju jestli v té složce mezitím nevznikly další požadavky na práci se stejným souborem. Pokud ano, mám možnost tu situaci řešit. Napadá mě třeba zapsat (APPEND) do toho souboru prioritu tohoto požadavku něco jako
99 94381315 1500... mikrosekundy + náhodně vygenerované číslo + čas čekání.
Pokud se tam objeví ještě jeden proces ve stejný čas, tak udělá to samé, zapíše svoje číslo něco jako
99 135485
ten kdo má vyšší prioritu, se provede jako první. Ten s nižším číslem bude čekat 1500 mikrosekund (přečte si předem vypočítaný čas).

Celkově ale dost pochybuju, že by se dva procesy spustily ve stejný čas během 99 mikrosekund.

Soubory starší 10 sekund by se smazaly.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 13:56:15
OK kit, tak jsem to udělal, ale ke kolizím stále dochází:

Kód: [Vybrat]
        $success = fflush($fp);// flush output before releasing the lock
        if ( $success === false )
          echo "; flush FAILED; ";
        $st = fstat($fp);
        if ($original_size>$st['size'])
            {
            echo "; <b>WRITE FAILED, restoring</b>;";

Je to tak nějak furt stejné.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 14:06:41
OK kit, tak jsem to udělal, ale ke kolizím stále dochází:

Kód: [Vybrat]
        $success = fflush($fp);// flush output before releasing the lock
        if ( $success === false )
          echo "; flush FAILED; ";
        $st = fstat($fp);
        if ($original_size>$st['size'])
            {
            echo "; <b>WRITE FAILED, restoring</b>;";

Je to tak nějak furt stejné.

Hmm, kde máš zámek?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 14:15:38
Ten je o pár řádků výše, přece:

$locked = flock($fp, LOCK_EX);

Já jsem dával jen ukázku toho fstat, ne zámku
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 14:46:37
Ten je o pár řádků výše, přece:

$locked = flock($fp, LOCK_EX);

Já jsem dával jen ukázku toho fstat, ne zámku

Bylo by lepší, kdybys vypsal obě hodnoty, ať z toho můžeme odvodit nějaké závěry.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 14:51:03
Kód: [Vybrat]
    $locked = flock($fp, LOCK_EX);
    if ( $locked ) {  // acquire an exclusive lock
        $success = fwrite($fp, $s);
        if ( $success === false)
          echo "; w FAILED;";
        else
          if ( $_DEBUG_ )
                echo " $success B written; ";
        $success = fflush($fp);// flush output before releasing the lock
        if ( $success === false )
          echo "; flush FAILED; ";
        $success = flock($fp, LOCK_UN);    // release the lock
        if ( $success === false )
          echo "; release FAILED; ";
        $success = fclose($fp);
        if ( $success === false )
          echo "; fclose FAILED; ";
        clearstatcache(); // needed for filesize and touch
        $fsize = filesize($tname);
        if ($original_size>$fsize)
            {
            echo "; <b>WRITE FAILED, restoring</b>;";
            $original_fname = "$n";
            $result = copy($original_fname, $tname);
            if ($result == false )
              die(" <b>TOTAL FAILTURE: copy failed.</b>");
            else
              echo " <b>RESTORED</b>;";
            }
        else
        {
          if ($fsize === 0)
           echo "! THE FILE WAS NOT WRITTEN: data length: ".strlen($s)." fsize: $fsize RESOURCE: $fp<br>";   
          if ( $success )
              touch("$tname",$fsize,$p);
        }
      } else echo "Couldn't get the lock!";
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 15:01:45
Podle mě flush() nezajistí zápis dat na disk (pořád data mohou být v bufferu filesystému), tudíž ani fstat() nemusí fungovat.

Pokud se ti nepovede spolehlivě zkontrolovat source a target soubor uvnitř PHP, tak to budeš muset vymyslet jinak vně (např. každý target soubor v PHP scriptu očísluješ a až pak je srovnáš nějakým nástrojem v linuxu), určitě na něco příjdeš.

Já se už rozloučím protože ten nový návrh na zámek mě vyděsil :). Čau.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 15:44:22
Jiné řešení pro případ vzkazníku mě napadlo.

Odesílatel odešle zprávu do složky uživateli, ale ta se nezpracuje automaticky. Ta zpráva tam bude čekat jako samostatný soubor, dokud si uživatel nepřečte všechny zprávy (které se mu zařadí do souboru teprve až navštíví svojischránku). Tím pádem jde o stoprocentní atomicitu, protože jediný skript, který bude zapisovat data do souboru je ten jeho. Nevýhoda je že při velkém množství zpráv se může uchovávat velké množství souborů, které na linuxu mohou zabírat nevím kolik.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Jvic V. 14. 10. 2019, 16:08:23
Mimo téma - Aneb jak to v reálu dopadne
10/2019 - Autor otázky vymyslí úžasnou funkci über cool atomickou
12/2019 - Předání zákazníkovi
01/2020 - První uživatelé začínají používat SW
02/2020 - Zákazník si začíná stěžovat na pomalost, "někdy" se stane, že vůbec nic nefunguje
03/2020 - Autor otázky dumá jak to "někdy" nasimulovat
04/2020 - Po neschopnosti nasimulovat SW přebírá jiný programátor... Se zděšením kouká co původní autor vymyslel, přepisuje s prstem v nose na file_put_contents
05/2020 - Zákazník je happy

Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 16:14:15
Mimo téma - Aneb jak to v reálu dopadne
10/2019 - Autor otázky vymyslí úžasnou funkci über cool atomickou
12/2019 - Předání zákazníkovi
01/2020 - První uživatelé začínají používat SW
02/2020 - Zákazník si začíná stěžovat na pomalost, "někdy" se stane, že vůbec nic nefunguje
03/2020 - Autor otázky dumá jak to "někdy" nasimulovat
04/2020 - Po neschopnosti nasimulovat SW přebírá jiný programátor... Se zděšením kouká co původní autor vymyslel, přepisuje s prstem v nose na file_put_contents
05/2020 - Zákazník je happy

Blbost. Nepíšu nic pro žádné klienty, programuju sám pro sebe a ne za peníze. Navíc jsem žádnou funkci nevymyslel, protože očividně žádná vymyslet nejde. Jak jsem už psal, žádná z těch funkcí není spolehlivá, no a pokud by použil file_put_contents na neatomické operace tak to by byl pěkný debil.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 16:20:41
Jiné řešení pro případ vzkazníku mě napadlo.

Odesílatel odešle zprávu do složky uživateli, ale ta se nezpracuje automaticky. Ta zpráva tam bude čekat jako samostatný soubor, dokud si uživatel nepřečte všechny zprávy (které se mu zařadí do souboru teprve až navštíví svojischránku). Tím pádem jde o stoprocentní atomicitu, protože jediný skript, který bude zapisovat data do souboru je ten jeho. Nevýhoda je že při velkém množství zpráv se může uchovávat velké množství souborů, které na linuxu mohou zabírat nevím kolik.

Tohle řešení se jmenuje Maildir a skutečně se používá. Při správné volbě souborového systému to funguje skvěle i pro velké množství souborů. Funkce file_put_contents() zde bude namístě bez rizika kolize, neboť názvy souborů se generují přes UUID.

Alternativní a doporučenou variantou je použití databáze, která ti zajistí nejen atomicitu, ale i eliminuje riziko kolizí a polovičních souborů. Takže až vyřešíš problémy se zamykáním souborů, přejdi na databázi.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 16:53:04
Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.
To je naprosto normální, takhle se budou chovat všechny synchronizační mechanismy. Vždy je to založené na tom, že se pokusíte udělat nějakou exkluzivní akci, vyhodnotíte výsledek a zjistíte, zda se podařila, nebo zda perníček loupe i někdo jiný a musíte chvilku počkat a zkusit to znovu.

flock neselhal ani jednou, vždy byl výsledek true.
Když chcete jako programátor řešit paralelní přístup k datům, tohle nemůžete nikdy napsat. To, že se vám nepodařilo nějaký souběh nasimulovat, vůbec neznamená, že nenastane hned při prvním spuštění na produkci.

A co takhle zkusit vyrobit jiný typ zámku, který by byl spolehlivější.
Dám vám dobrou radu. Nepokoušejte se vymýšlet vlastní zámky, v tuto chvíli na to nemáte znalosti. Použijte nějakou běžně používanou databázi, která už má tyhle nízkoúrovňové věci vyřešené. Tam můžete studovat třeba to, jak fungují ACID transakce, jak jsou od sebe izolované – a na základě toho si začnete pomalu budovat představu o tom, co se může dít, když se stejnými daty pracuje několik programů nebo vláken souběžně.

Takže až vyřešíš problémy se zamykáním souborů, přejdi na databázi.
Takhle to nebude fungovat, jedině opačně – nejprve se naučit používat prostředky databáze, které jsou jednodušší, a teprve pak se případně dostat k souborům.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 17:16:14
Takže až vyřešíš problémy se zamykáním souborů, přejdi na databázi.
Takhle to nebude fungovat, jedině opačně – nejprve se naučit používat prostředky databáze, které jsou jednodušší, a teprve pak se případně dostat k souborům.

To měl být sarkasmus.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 19:23:02
Kit: do databáze by se mi nevešlo všechno to co chci uložit. Ta databáze na freehostingu má jen 20 mB. Teď jsem to počítal, kdybych udělal malou stránečku, seznamku pro úzkou komunitu lidí (nebudu zde veřejně blíže mluvit detaily o jakou komunitu se jedná). Můj nápad je udělat tu komunitu pouze pro určitou oblast, tím se to ještě víc omezí. Tak dejme tomu počet uživatelů 100 lidí jako maximum (odhad). Na souborovém systému, počítám-li na linux 4kb na prázdnou složku/soubor ... na jednoho uživatele tedy 1 složka a 10 souborů dělá dohromady 3,9MB jen na prázdných souborech, 0,4MB na prázdných složkách a 443 MB jen na datech. Na datech jsem při tom počítal: 1MB na příchozí poštu, 1MB na odchozí poštu (za předpokladu, že se to bude např. jednou za 2-3 měsíce mazat). 0,1MB rejstřík (on asi nebude zabírat tolik, ale dal jsem rezervu, no pokud posunu čárku o jedno místo tak 410MB celkem. Vše se musí zálohovat, takže je to tam dvakrát. Tudíž vidíš sám že do 20MB databáze se tohle nemůže vejít. A jednalo by se o nekomerční tedy neziskový projekt, takže proto pojede na hostingu zdarma. No možná mi doporučíš nějaký hosting zdarma kde mají větší databázi nebo prostor na disku, ale celkově je problém v tom, že já nevěřím těmhle hostingům co poskytují velký prostor "zdarma", bylo tu Moxo, co ukradlo uživatelům stránky a osobní data, tedy ne ono, ale nějaký chlap kterého vlastně ani nikdo přesně neznal a nejspíš to byl cizinec, takže jakmile získal co chtěl, tak zbalil kufry a odešel. Nikdy nevíš kdo se vlastně za takovou službou skrývá, zvlášť pokud je zahraniční a nabízí svůj prostor a služby a co se s nimi pak děje, komu je nabízí?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 19:29:30
flock neselhal ani jednou, vždy byl výsledek true.
Když chcete jako programátor řešit paralelní přístup k datům, tohle nemůžete nikdy napsat. To, že se vám nepodařilo nějaký souběh nasimulovat, vůbec neznamená, že nenastane hned při prvním spuštění na produkci.

Na jaké produkci? Já nejsem produkční studio! (Pozn. vykřičníky u mě neznamenají attack, ale překvapení nebo důraz).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 19:35:40
Jak jsem psal, databázi určitě použiju, to jsem si už vyjasnil, ale rozhodně ne na ptákoviny jako je registrace a loginy, to zvládnu přes soubory. Taková databáze musí být mega jednoduchá, takže jedna tabulka na ukládání výsledků ankety a to bude vše. Nechci strávit zbytek život psaním www stránek. Tenhle druh programování pokládám za hrozně omezující, protože člověk musí brát ohled na ty paralalení operace, bezpečnost, možnost uživatelů úmyslně chtít hatit provoz stránky... Když se rozhodnu napsat binární program, který dělá tu samou věc ale bez uživatelů mám to napsané za tři až sedm dnů, podle úrovně detailů... Tady jednu kravinu abych programoval dva tři měsíce. To je hrůza.

Jo k té databázi, styčí když k tomu použiju příkazy mysql_? Učit se za něco nového jako PDO se mi nechce.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 19:45:23
Kit: do databáze by se mi nevešlo všechno to co chci uložit. Ta databáze na freehostingu má jen 20 mB.

Použij SQLite. Budeš omezen jen velikostí diskového prostoru na webhostingu a ušetříš hromadu místa.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 19:50:10
Jo k té databázi, styčí když k tomu použiju příkazy mysql_? Učit se za něco nového jako PDO se mi nechce.

Práce s PDO je jednodušší než s mysql_* a navíc získáš ošetření proti SQL injection - tedy pokud použiješ prepared statemnts.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 20:31:51
Na jaké produkci? Já nejsem produkční studio!
„Produkce“ je v IT slangové označení pro „produkční prostředí“, nebo také „ostré prostředí“ – prostředí, kde aplikace běží „na ostro“, připojují se k ní reální uživatelé, má reálná data atd. Tedy např. i ta vaše aplikace na free webhostingu. Vedle toho pak mohou existovat různá nedůležitá nebo méně důležitá prostředí – vývojová, testovací, integrační, akceptační apod.

Zrovna problémy s konkurenčním přístupem se často vyskytují až od určitého množství současně pracujících uživatelů. Pokud řešíte webhosting zdarma, asi nebudete mít testovací prostředí, kde byste věrohodně simuloval souběžnou práci většího množství uživatelů. Takže na problémy se špatně napsaným konkurenčním přístupem můžete narazit až na ostrém serveru – až se vám začnou ztrácet data nebo se vám datový soubor poškodí.

Jak jsem psal, databázi určitě použiju, to jsem si už vyjasnil, ale rozhodně ne na ptákoviny jako je registrace a loginy, to zvládnu přes soubory […] Tady jednu kravinu abych programoval dva tři měsíce.
Pokud si pro prkotiny jako registrace a loginy budete programovat vlastní databázi, opravdu vám to bude trvat dva tři měsíce, klidně i déle. Pokud se na tom budete metodou pokusu a omylu učit, jak se pracuje se soubory při konkurenčním přístupu a jak se zamykají, bude vám to trvat podstatně déle, než tři měsíce. A možná nakonec zjistíte, že když budete zamykat celé soubory, už s malým množstvím uživatelů na freehostingu narazíte na limity v počtu souběžně otevřených souborů nebo doby zpracování skriptu.

A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 20:46:50
Na jaké produkci? Já nejsem produkční studio!
„Produkce“ je v IT slangové označení pro „produkční prostředí“, nebo také „ostré prostředí“ – prostředí, kde aplikace běží „na ostro“, připojují se k ní reální uživatelé, má reálná data atd. Tedy např. i ta vaše aplikace na free webhostingu. Vedle toho pak mohou existovat různá nedůležitá nebo méně důležitá prostředí – vývojová, testovací, integrační, akceptační apod.

Zrovna problémy s konkurenčním přístupem se často vyskytují až od určitého množství současně pracujících uživatelů. Pokud řešíte webhosting zdarma, asi nebudete mít testovací prostředí, kde byste věrohodně simuloval souběžnou práci většího množství uživatelů. Takže na problémy se špatně napsaným konkurenčním přístupem můžete narazit až na ostrém serveru – až se vám začnou ztrácet data nebo se vám datový soubor poškodí.

Jak jsem psal, databázi určitě použiju, to jsem si už vyjasnil, ale rozhodně ne na ptákoviny jako je registrace a loginy, to zvládnu přes soubory […] Tady jednu kravinu abych programoval dva tři měsíce.
Pokud si pro prkotiny jako registrace a loginy budete programovat vlastní databázi, opravdu vám to bude trvat dva tři měsíce, klidně i déle. Pokud se na tom budete metodou pokusu a omylu učit, jak se pracuje se soubory při konkurenčním přístupu a jak se zamykají, bude vám to trvat podstatně déle, než tři měsíce. A možná nakonec zjistíte, že když budete zamykat celé soubory, už s malým množstvím uživatelů na freehostingu narazíte na limity v počtu souběžně otevřených souborů nebo doby zpracování skriptu.

A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.

To je blbost, registraci si napíšu za týden.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 20:51:11
To je blbost, registraci si napíšu za týden.

Proč ne za hodinu?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 20:55:56
Který freehosting používáš, ať mohu porovnat parametry?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 21:03:17
To je blbost, registraci si napíšu za týden.
Když vás baví psát týden něco, co můžete mít hotové za hodinu… Navíc už se tu dva dny snažíte přijít na to, jak se mají zamykat soubory, řešení stále nikde – a to zatím řešíte jen přidávání záznamů, ale ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 21:50:50
To je blbost, registraci si napíšu za týden.

Proč ne za hodinu?

Blbá otázka. Prostě protože tak dlouho mi to trvá.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 21:51:21
To je blbost, registraci si napíšu za týden.
Když vás baví psát týden něco, co můžete mít hotové za hodinu… Navíc už se tu dva dny snažíte přijít na to, jak se mají zamykat soubory, řešení stále nikde – a to zatím řešíte jen přidávání záznamů, ale ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.

Nechte si ty blbý řeči, jo? Mluvte o sobě. Vám to trvá hodinu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 21:52:35
ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.

To nepotřebuju. Efektivní vyhledávání mám ale už dávno vyřešeno.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 14. 10. 2019, 21:57:24
A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.

Nedám ani korunu za web, který nevydělává, leda že by si za to návštěvníci ten hosting sami zaplatili. Ale u webu který nemá žádnou návštěvnost asi těžko. Navíc mě těmi svými blbými řečmi rozpalujete doběla. Soudíte druhé lidi podle sebe, jenže vy jste profík, můžete si dovolit strávit u počítače kolik času chcete. Vůbec jsem z těch vašich subjektivně laděných soudů znechucen. To je jak bavit se s blbým člověkem, už jsem vám říkal, že hosting placený nechci a ten neplacený má kapacitu jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 22:09:17
... jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.

Jestli je to MySQL na Webzdarma, tak na ni můžeš v klidu zapomenout. Nikdy mi tam pořádně nejela. Zato SQLite tam sviští jako vítr.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 14. 10. 2019, 22:29:39
A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.

Nedám ani korunu za web, který nevydělává, leda že by si za to návštěvníci ten hosting sami zaplatili. Ale u webu který nemá žádnou návštěvnost asi těžko. Navíc mě těmi svými blbými řečmi rozpalujete doběla. Soudíte druhé lidi podle sebe, jenže vy jste profík, můžete si dovolit strávit u počítače kolik času chcete. Vůbec jsem z těch vašich subjektivně laděných soudů znechucen. To je jak bavit se s blbým člověkem, už jsem vám říkal, že hosting placený nechci a ten neplacený má kapacitu jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.
Myslím, že na Filipa útočíš neprávem. Snaží se ti slušně říct, že někdy je levnější za věci zaplatit než je mít zdarma. Až budeš starší příjdeš na to sám. Raději dát pár stovek ročně než přijít o několik víkendů kdy budeš řešit chyby v tom systému. Taky připočti častější výpadky na freehostingu ze kterého návštěvníci taky nebudou nadšeni. Existuje spousta koníčků a projektů co dělá člověk pro radost a nic na nich nevydělává.

Jestli použiješ databáze vs. soubory; freehosting vs. placený; vlastní systém vs. Wordpress; to všechno záleží na tobě, ale zaplatit trochu peněz za něco co ti ušetří hodně práce je obecně správný přístup, vyjímkou snad je pokud jsi hodně mladý a i těch pár korun je pro tebe dost peněz.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 14. 10. 2019, 23:12:30
To nepotřebuju. Efektivní vyhledávání mám ale už dávno vyřešeno.
Efektivní hledání v registrovaných uživatelích, které zapisujete do souboru na disk? To bych chtěl vidět…

Nedám ani korunu za web, který nevydělává, leda že by si za to návštěvníci ten hosting sami zaplatili. Ale u webu který nemá žádnou návštěvnost asi těžko. Navíc mě těmi svými blbými řečmi rozpalujete doběla. Soudíte druhé lidi podle sebe, jenže vy jste profík, můžete si dovolit strávit u počítače kolik času chcete. Vůbec jsem z těch vašich subjektivně laděných soudů znechucen. To je jak bavit se s blbým člověkem, už jsem vám říkal, že hosting placený nechci a ten neplacený má kapacitu jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.
Mně by to trvalo hodinu. Vám by to trvalo den, kdybyste si nechal poradit. Bude vám to trvat měsíce, když to budete dělat způsobem, jak to tady popisujete.

Nehodnotil jsem, jak dlouho na tom pracujete nebo kolik máte času. Pouze se podivuju nad tím, že si svou práci dobrovolně tolik komplikujete. To, že vás dobré rady rozpalují doběla, je váš problém.

Pokud nejste ochoten dát 50 Kč měsíčně, místo toho budete týdny něco programovat s nejistým výsledkem, znamená to, že váš čas nemá žádnou hodnotu. Můj čas hodnotu má a nehodlám ho plýtvat na řešení vašich problémů, které si sám vytváříte svou umíněností. Takže za mne naposledy: pokud je pro vás příliš pracné použít úplně základním způsobem jakoukoli databázi, ukládání dat do souborů v konkurenčním prostředí (tak, aby to alespoň trochu rozumně fungovalo) naprogramovat nedokážete. To není žádné souzení nebo hodnocení, je to prosté konstatování faktu. Buď to můžete vzít na vědomí, zařídit se podle toho a změnit svůj postup tak, abyste naprogramoval to, co naprogramovat chcete. A nebo můžete hlavou dál zkoušet prorazit betonovou zeď.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 23:49:33
Raději dát pár stovek ročně než přijít o několik víkendů kdy budeš řešit chyby v tom systému. Taky připočti častější výpadky na freehostingu ze kterého návštěvníci taky nebudou nadšeni. Existuje spousta koníčků a projektů co dělá člověk pro radost a nic na nich nevydělává.

Jestli použiješ databáze vs. soubory; freehosting vs. placený; vlastní systém vs. Wordpress; to všechno záleží na tobě, ale zaplatit trochu peněz za něco co ti ušetří hodně práce je obecně správný přístup, vyjímkou snad je pokud jsi hodně mladý a i těch pár korun je pro tebe dost peněz.

Tady bych se exkalibra zastal. Mám z minula několik projektíků, které mi běží na freehostinzích a poběží tam, dokud služba bude fungovat. Nemají velkou hodnotu a kdybych za každý z nich platil těch zmíněných 50 Kč měsíčně, tak bych se jich už dávno zbavil. Pokud se učí a zkoumá vlastnosti souborových systémů na hostingu, který neptá peníze, tak ho nechej být. Je to jeho čas, který do toho investuje. Pokud je ti líto tvého času, tak se na tohle vlákno vykašli.

Ty freehostingy mi dělají dobrou službu, i když občas nefungují, jak by měly. Právě na nich se skvěle simulují souběhy, závady, chyby v konfiguraci, chyby při různých upgradech apod. Mohu si na nich vyzkoušet i věci, které si v ostrém provozu nemohu dovolit.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 14. 10. 2019, 23:56:05
Pokud nejste ochoten dát 50 Kč měsíčně, místo toho budete týdny něco programovat s nejistým výsledkem, znamená to, že váš čas nemá žádnou hodnotu.

Pokud by za hosting platil 50 Kč měsíčně, měl by naprosto stejné problémy se zamykáním souborů, jaké tady řeší. Cena za hosting v tom nehraje roli.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 00:05:33
Dík Kite za zastání. A to jsem nezmínil, že by těch projektů klidně časem mohlo být víc. Platit za něco co slouží druhým a mě ne, proč bych to měl platit? Ať si to platí sami. Anebo ať mi to zaplatí ten pán co mi tak doporučuje placený hosting, když má tolik peněz na sponzorování nekomerčních projektů.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 00:55:13
Na druhou stranu bych ti vytkl, že jsi u nějakého freehostingu s tak mizernými parametry. Zkus hledat u konkurence, která je také zdarma a přitom má ty parametry (včetně databází) o jeden či dva řády lepší.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 01:05:40
Na druhou stranu bych ti vytkl, že jsi u nějakého freehostingu s tak mizernými parametry. Zkus hledat u konkurence, která je také zdarma a přitom má ty parametry (včetně databází) o jeden či dva řády lepší.

Nechci se znovu nachytat. Neznám je a bez doporučení se sotva mohu pouštět do experimentů. Nechci zažít druhé Moxo.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 07:18:44
Na druhou stranu bych ti vytkl, že jsi u nějakého freehostingu s tak mizernými parametry. Zkus hledat u konkurence, která je také zdarma a přitom má ty parametry (včetně databází) o jeden či dva řády lepší.
Nechci se znovu nachytat. Neznám je a bez doporučení se sotva mohu pouštět do experimentů. Nechci zažít druhé Moxo.

U Moxo jsem byl také. Zrušili provoz. No a? Přešel jsem jinam a jedu dál. U koho jsi teď?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 15. 10. 2019, 07:25:54
Pokud by za hosting platil 50 Kč měsíčně, měl by naprosto stejné problémy se zamykáním souborů, jaké tady řeší. Cena za hosting v tom nehraje roli.
Nikoli, stejné problémy by neměl. Nebyl by omezený limitem 20 MB na databázi, takže by se nepokoušel bez jakýchkoli znalostí naprogramovat vlastní databázi, ale použil by tu, kterou nabízí webhosting.

Dík Kite za zastání. A to jsem nezmínil, že by těch projektů klidně časem mohlo být víc. Platit za něco co slouží druhým a mě ne, proč bych to měl platit? Ať si to platí sami. Anebo ať mi to zaplatí ten pán co mi tak doporučuje placený hosting, když má tolik peněz na sponzorování nekomerčních projektů.
Jenže vy za to platíte svým časem, a to daleko víc, než kolik byste zaplatil za ten hosting. Navíc to zatím nevypadá, že byste se blížil k cíli – o konkurenčním přístupu k souborům toho nevíte o nic víc, než na začátku. A upřímně řečeno, nemyslím si, že byste se to mohl naučit z komentářů na diskusním fóru a generováním náhodných testů, které se s podstatou zamykání souborů míjí.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 07:53:30
Pokud by za hosting platil 50 Kč měsíčně, měl by naprosto stejné problémy se zamykáním souborů, jaké tady řeší. Cena za hosting v tom nehraje roli.
Nikoli, stejné problémy by neměl. Nebyl by omezený limitem 20 MB na databázi, takže by se nepokoušel bez jakýchkoli znalostí naprogramovat vlastní databázi, ale použil by tu, kterou nabízí webhosting.

Tohle omezení se zřejmě týká MySQL, ale SQLite bývá omezeno jen velikostí přiděleného diskového prostoru. Rozhodně lepší a spolehlivější řešení, než fopen().
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 07:54:16
Jenže vy za to platíte svým časem, a to daleko víc, než kolik byste ...

Jak můžete vědět, kolik stojí můj čas? Vaše logické myšlení postrádá konzistenci. Používáte slovo byste na případ, který by nikdy nenastal.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 08:15:45
https://github.com/php-lock/lock
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 08:42:42
Kit, mám dotaz. Aktuálně mám dva oddělené bloky, jeden čte, druhý zapisuje. To by nejspíš bylo lepší sloučit do jednoho, tak co to otevřít s fopen w+? Tím se vyřeší problém té narušené atomicity scriptu ne? Akorád po načtení pomocí fread musím převinout na začátek souboru ne?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: tecka 15. 10. 2019, 08:55:14
Kit, mám dotaz. Aktuálně mám dva oddělené bloky, jeden čte, druhý zapisuje. To by nejspíš bylo lepší sloučit do jednoho, tak co to otevřít s fopen w+? Tím se vyřeší problém té narušené atomicity scriptu ne? Akorád po načtení pomocí fread musím převinout na začátek souboru ne?
Převiň na začátek téhle diskuze a přečti si ji.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 08:59:08
Kit, mám dotaz. Aktuálně mám dva oddělené bloky, jeden čte, druhý zapisuje. To by nejspíš bylo lepší sloučit do jednoho, tak co to otevřít s fopen w+? Tím se vyřeší problém té narušené atomicity scriptu ne? Akorád po načtení pomocí fread musím převinout na začátek souboru ne?

Tak se koukni kousek zpátky a podívej se na můj příspěvek, kde ti radím "r+". Máš to tam i se zámkem a převinutím.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 09:01:56
takže r+ , ale tím jsem přepsal původní soubor, už to je úplně odlišný algoritmus.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 09:16:19
takže r+ , ale tím jsem přepsal původní soubor, už to je úplně odlišný algoritmus.

Tohle chování jsi přece chtěl.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 09:39:27
Na začátku téhle diskuse jsem pracoval s odlišným souborem, zdroj a cíl byly odlišné soubory. Četl jsem z jednoho a zapisoval do druhého. Teď jsem ten algoritmus změnil, takže čtu z toho, do kterého jsem zapisoval. Což mimochodem znamená, že jsem musel implementovat dva adresářové locky, jeden na zazálohování souboru a druhý na jeho obnovu když dojde k selhání.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 09:44:27
Na začátku téhle diskuse jsem pracoval s odlišným souborem, zdroj a cíl byly odlišné soubory. Četl jsem z jednoho a zapisoval do druhého. Teď jsem ten algoritmus změnil, takže čtu z toho, do kterého jsem zapisoval. Což mimochodem znamená, že jsem musel implementovat dva adresářové locky, jeden na zazálohování souboru a druhý na jeho obnovu když dojde k selhání.

Vyzkoušej SQLite, který tohle všechno dělá za tebe.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 10:15:15
Sqlite nemá administrátorské prostředí ne? Nebo se to změnilo od těch dob co existovalo Moxo?

Doporučíš mi nějaký hosting?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 15. 10. 2019, 10:27:21
Ať si to platí sami.
Ano ať si to platí, ale to jim musíš říct ty a vysvětlit jim, že se s tím nebudeš drbat 10x déle jenom, aby ušetřili pár svých stokorun. Vzpomínám si na jednu reportáž jak "sběrači" kovů týden kopali měděné kabely a dostali za to 1000 Kč, pak se na ten hluboký výkop díval majitel stavební firmy a říká: "Kdyby se ti kopáči u mě nechali zaměstnat, tak si za to kopání vydělají 5000 Kč". Ale jestli tohle vše děláš kvůli učení a zkoumání, pak to beru.

Pokud se učí a zkoumá vlastnosti souborových systémů na hostingu, který neptá peníze, tak ho nechej být.
Pokud jde o zkoumání a učení se, pak proti tomu nic nemám. Ale i při učení platí efektivita, např. raději koupit učebnici za 500 Kč než brouzdat po netu a učením strávit o rok déle. Pokud mu freehosting pro jeho potřeby poskytne to samé co placený, tak ať vezme free, ale podle toho co Exkalibr napsal jsem měl pocit, že ho bude limitovat a výsledkem těch limitů bude o hodně více stráveného času. Ale jak říkám pokud zkoumá a učí se, tak nic proti.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 10:30:53
Sqlite nemá administrátorské prostředí ne? Nebo se to změnilo od těch dob co existovalo Moxo?

Doporučíš mi nějaký hosting?

SQLite se dá dobře spravovat skriptem Adminer.

Zkus endora.cz
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: ByCzech 15. 10. 2019, 10:32:09
Sqlite nemá administrátorské prostředí ne?

https://www.phpliteadmin.org
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 10:35:19
Na endoru jsem se kdysi díval a byla omezená trafikem. Pokud se nepletu. Už jsem se před časem díval ale to bylo mnoho lez zpátky a narážel jsem na samé limity. Například limit odeslaných požadavků na server databáze.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 10:54:32
Na endoru jsem se kdysi díval a byla omezená trafikem. Pokud se nepletu. Už jsem se před časem díval ale to bylo mnoho lez zpátky a narážel jsem na samé limity. Například limit odeslaných požadavků na server databáze.

Tak si najdi nějaké žebříčky freehostingů a vyber si takový, který ti bude vyhovovat.

Narazil jsem na tohle: https://infinityfree.net/
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 11:27:05
Tak asi to zkusím.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 16:09:42
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 16:29:53
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?

Zkus raději podle manuálu
Kód: [Vybrat]
file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 16:33:43
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?

Zkus raději podle manuálu
Kód: [Vybrat]
file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);

To mohu použít jen v případě, že ve scriptu nejedou dva procesy paralelně, já myslel právě pro to použití dvou skriptů. Dám příklad:

Co chci zapsat do logu:
"Byl jsem tady Skript 2 čas 1:00:11.000"
"Byl jsem tady Skript 1 čas 1:00:11.002"
"Byl jsem tady Skript 3 čas 1:00:11.001"

Jestli je zapíše za sebou - jedno v jakém pořadí,
nebo se může stát, že vznikne kolize

např

Kód: [Vybrat]
Byl jsem tady Skript 2 čas 1:00:11.00
Byl jsem tady Skript 1 čas 21:00:11.002
Byl jsem tady Skript 3 čas 1:00:11.001

(Ubral nulu na konci prvního řádku)
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 16:43:30
Dokončil jsem skript a prakticky mi to už nehlásí chyby.

Tento test je blízký testu 7 - vycházel jsem z jeho modifikovaných verzí po opravách, které jste mi doporučili.

Hlavním problémem byl jak už tu psal Lin, zjišťování velikosti souboru. To nemohlo správně fungovat. Když jsem vynechal test velikosti souboru, tak vše jede. Původně jsem ten test přidal proto, že to celé nejelo: velikost souboru se měnila až k nule.

V tomto testu jsem přidal funkci na test existence zámku pro zálohu souboru.


Zámek na atomicitu čtení a zápisu jsem nepřidával. Zřejmě už samotný fakt, že probíhá kopírování, to celé časově nějak rozhodí a nedojde k té kolizi jako před tím. Tím kopírováním je to realističtější, jenže já to paradoxně stejně nemohu obnovit, protože v té části, kde bych to obnovoval není nastaven atomicitní zámek. A kdybych ho tam dal, tak zase může dojít k chybě atomicity fail.

Jediná chyba, která tak občas nastane je "atomicity fail" v prvním zámku, který spravuje zálohování souboru. Ten mě ale fakticky nezajímá.

Přikládám celý kód, protože už mi to fakt moc nemyslí a třeba v něm najdete nějaké věci, které stojí za zmínku.

Kód: [Vybrat]
clearstatcache();
$_DEBUG_ = false;

/*
folder.t1 - directory lock for backup copy
folder.t2 - directory lock for restore copy
*/

echo "Lock and flush tester.".time()."<br>";
$time_constant = 1571149526;
//die; // Remove this line when you set time_constant

while ( time()<$time_constant )
 {
 usleep(500);
 }

/*
Creates directory lock for atomicity or waits
$dirPrefix = "lock"; // dir. lock name
$lockN = 1; // first lock
$lockTimes = 7; test 7 times
*/
function AtomicFuseTestTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
  $start = atomicFuse($dirPrefix, $n,$lockN,0);
  for ($i=1; $i <= $lockTimes; $i++ )
    if (!$start)
      $start = atomicFuse($dirPrefix, $n,$lockN,$i);
    else
      break;
  if (!$start) $start = atomicFuse($dirPrefix, $n, $lockN, null, false);
  if ( $printError==true && !$start) echo "<br><b>Atomicity failed for lock $lockN.</b><br> ";
  return $start;
}
/*
Before or after, you call AtomicityTestLockTimes,
you need to create a directory lock.

$n = file size in kb
$lockN = 1; // first lock
$lockTimes = 7; test 7 times
*/
function AtomicityTestLockTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
  $start = TestAtomicLock($dirPrefix, $n,$lockN,0);
  for ($i=1; $i <= $lockTimes; $i++ )
    if (!$start)
      $start = TestAtomicLock($dirPrefix, $n, $lockN,$i);
    else
      break;
  if (!$start) $start = TestAtomicLock($dirPrefix, $n, $lockN, null);
  if ( $printError==true && !$start) echo "<br><b>Atomicity failed for lock $lockN.</b><br> ";
  return $start;
}
/*
This makes a test of atomic lock but does not
create it.
c is counter for optimalization
first call must have c = 0;
*/
function TestAtomicLock($dirPrefix, $n, $lockNumber, $c){
  if ( $c<0 )
    die("<h3>TestAtomicLock: Error - c is less than 0</h3>");
  $start = true;
 
  echo "<br>'$dirPrefix.t$lockNumber'<br>";
 
  if ( file_exists("$dirPrefix.t$lockNumber") )
   {
   clearstatcache();
   $st = @stat("$dirPrefix.t$lockNumber");
   echo "dir lock time: ".(time()-$st['ctime']);
   if ( time()-$st['ctime'] > 10 )
     {
     @rmdir("$dirPrefix.t$lockNumber"); // remove directory lock
     echo "<h1>Old lock removed</h1>";
     }
   $start = false;
   }
  else echo " not found; ";
  if ( isset($c) ){
    if ( $start == false )
     {
     $n = $n*30;
     switch($c):      // Delay example increase:
       case 0: break; // 0,01569 total
       case 1: break; // 0,03138 total
       case 2: $n = $n*2; break; // 0,06276 total
       case 3: $n = $n*4; break; // 0,12552 total
       // case 4: You need at least *6 or *8 to get out of problems with extrem times
       case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
       // In case of heavy traffic:
       case 5: $n = $n*8; break; // 0,36087 total extrem
       case 6: $n = $n*10; break; // 0,51777 total extrem
       case 7: $n = $n*20; break; // 1,03554 total extrem
       default: $n = $n*8; break;
     endswitch;
     usleep($n);
     echo "($n)<br>";
     }
    }
  return $start;
}
/*
dirPrefix - should be equal to name of the file you're trying to lock
lockNumber for adding more locks */
function atomicFuse($dirPrefix, $n, $lockNumber, $c){
  if ( $c<0 )
    die("<h3>TestAtomicLock: Error - c is less than 0</h3>");
  $start = false; 
  if ( @mkdir("$dirPrefix.t$lockNumber") )
   $start = true;
  if ( isset($c) ){
    if ( $start == false )
     {
     $n = $n*30;
     switch($c):      // Delay example increase:
       case 0: break; // 0,01569 total
       case 1: break; // 0,03138 total
       case 2: $n = $n*2; break; // 0,06276 total
       case 3: $n = $n*4; break; // 0,12552 total
       // case 4: You need at least *6 or *8 to get out of problems with extrem times
       case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
       // In case of heavy traffic:
       case 5: $n = $n*8; break; // 0,36087 total extrem
       case 6: $n = $n*10; break; // 0,51777 total extrem
       case 7: $n = $n*20; break; // 1,03554 total extrem
       default: $n = $n*8; break;
     endswitch;
     usleep($n);
     echo "!($n)<br>";
     }
    }
  return $start;
}

function test($n, $p, $_DEBUG_){
//  $delay_multiplier = $n*2.5;
  $original_fname = "$n";
  $cname = "$n.b";    // copy to restore
  $working_filename = "$n.txt";    // source & target
  echo "<h4>$n at ".time()."</h4>";
  for ($i = 0; $i<50; $i++ ){
    $start_time = microtime(true);
    clearstatcache(); // needed for filesize and touch   
   
    //////////////////////
    // TEST ATOMIC LOCK //
    //////////////////////

    // Test 1 - "backup" lock
    // MAKE BACKUP
    // Test 2 - "restoring" lock
    $start = AtomicityTestLockTimes($n,$n,1,7);
    if ( $start )
      {
      $success = @mkdir("$n.t1");
      if ( $success == false )
         echo "<b>Failed to lock;</b><br>";
      $result = copy($original_fname, $cname);
      if ( $result == false )
        echo "<h4>BACKUP failed.</h4>";
      $result = @rmdir("$n.t1");
      if ( $result == false )
        echo "<h4>Directory lock was not removed</h4>";
      }

    // Test 2 - "restoring" lock
    // $start = AtomicityTestLockTimes($n,$n,2,7);
    if ( true )
    {
    $st = stat("$working_filename");
    $original_size = $st['size'];
    if ( $_DEBUG_ )
      echo "; 1) prevAccess by ".$st['mtime']." fsize ".$st['size']."; ";
    $fsize = filesize($working_filename);
    if ( $original_size <> $fsize )
      die("; fsize total FAILTURE; ");
    if ($fsize === 0)
     die ("! <b>The fsize is 0</b>: fstat(): $original_size <>".$st['size']." ;");   
   
    // READ OPERATION AND LOCK FOR SHARE
    $fp = fopen($working_filename, "r+");
    $locked = flock($fp, LOCK_SH);
    if ( $locked == false)
      die("failed to get LOCK_SH;<br>");
    $s = fread( $fp, $fsize );
    // CHANGE LOCK
    $success = flock($fp, LOCK_UN);
    $locked = flock($fp, LOCK_EX);
    if ( $success === false  )
      die("; r flock release failed; ");
    if ( $locked == false )
        die("failed to get LOCK_EX;<br>");
    clearstatcache();
    $st = stat("$working_filename");                               
    if ( $_DEBUG_ )
      echo "; 2) prevAccess by ".$st['mtime']." fsize is ".$fsize."; ";

    // WRITE OPERATION WITH LOCK_EX
    $locked = flock($fp, LOCK_EX);
    if ( $locked ) {  // acquire an exclusive lock
        $success = rewind($fp);
        if ($success == false)
          echo " rewind failture; ";
        $success = fwrite($fp, $s);
        if ( $success === false)
          echo "; w FAILED;";
        else
          if ( $_DEBUG_ )
                echo " $success B written; ";
        $success = fflush($fp);// flush output before releasing the lock
        if ( $success === false )
          echo "; flush FAILED; ";
        // Test 2 - "restoring" lock
        // $start = AtomicityTestLockTimes($n,$n,2,7);

        $success = flock($fp, LOCK_UN);
        $success = fclose($fp);

        if (false)//$start)
          {
          $original_fname = "$n";
          // Create directory lock
          $success = @mkdir("$n.t2");
          clearstatcache(); // Check file size
          $st = fstat($fp);
          if ($original_size>$st['size'])
              {
              echo "; <b>WRITE FAILED, restoring</b>;";
              if ($success) {
                 $success = flock($fp, LOCK_UN);
                 $success = fclose($fp);
                 $result = copy($cname, $working_filename);
                 if ( $result == false )
                   echo "<h4>Restoring failed.</h4>";
                }
              if ($result == false )
                die(" <b>TOTAL FAILTURE: copy failed.</b>");
              else
                echo " <b>RESTORED</b>;";
              }
          else
            {   // FINISH SUCCESSFUL WRITE OPERATION
            if ( $success )
                touch("$working_filename",$fsize,$p);
            $success = flock($fp, LOCK_UN);    // release the lock
            if ( $success === false )
              echo "; release FAILED; ";
            $success = fclose($fp);
            if ( $success === false )
              echo "; fclose FAILED; ";
            // 10 - data načtená , $p - prohlížeč
            if ( $success )
                {
                $result = touch("$working_filename",strlen($s),$p);
                if ( $_DEBUG_ )
                   echo "; TOUCH: $result;";
                }
            else
              die("fclose FAIL.");
            }
         
         // RELEASE DIRECTORY LOCK: (Test 2)
         /*
         $result = rmdir("$n.t2");
         if ( $result == false )
           echo "<h4>Directory lock was not removed</h4>";
         */
         } // END OF ATOMIC LOCK (mkdir) Test 2         
      } else echo "Couldn't get the lock!";
    }
     
    /////////////////////////
    // END OF TIME MEASURE //
    /////////////////////////

    $time_elapsed_secs = microtime(true) - $start_time;
    //usleep( $delay_multiplier + $n*rand(2,6) );
    if ( $time_elapsed_secs === 0 )
      echo " FAILED ";
    echo "time: $time_elapsed_secs s<br>";
  } // for
}

copy("523","523.txt");
copy("948","948.txt");
copy("1371","1371.txt");
copy("1913","1913.txt");
copy("2701","2701.txt");
copy("4495","4495.txt");
copy("6758","6758.txt");

test("523",$p,$_DEBUG_);
test("948",$p,$_DEBUG_);
test("1371",$p,$_DEBUG_);
test("1913",$p,$_DEBUG_);
test("2701",$p,$_DEBUG_);
test("4495",$p,$_DEBUG_);
test("6758",$p,$_DEBUG_);

Původní blok 7-8 testů a prodlev jsem přesunul do funkce:
AtomicityTestLockTimes

Která vlastně dělá jen
Kód: [Vybrat]
function AtomicityTestLockTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
  $start = TestAtomicLock($dirPrefix, $n,$lockN,0);
  for ($i=1; $i <= $lockTimes; $i++ )
    if (!$start)
      $start = TestAtomicLock($dirPrefix, $n, $lockN,$i);
    else
      break;
...
return $start;
}

Aplikace prvního zámku:
Kód: [Vybrat]
    $start = AtomicityTestLockTimes($n,$n,1,7);
    if ( $start )
      {
      $success = @mkdir("$n.t1");
      if ( $success == false )
         echo "<b>Failed to lock;</b><br>";
      $result = copy($original_fname, $cname);
      if ( $result == false )
        echo "<h4>BACKUP failed.</h4>";
      $result = @rmdir("$n.t1");
      if ( $result == false )
        echo "<h4>Directory lock was not removed</h4>";
      }

A druhý zámek jsem neaplikoval, jak jsem už napsal.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 16:56:31
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?

Zkus raději podle manuálu
Kód: [Vybrat]
file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);

To mohu použít jen v případě, že ve scriptu nejedou dva procesy paralelně, já myslel právě pro to použití dvou skriptů. Dám příklad:

Co chci zapsat do logu:
"Byl jsem tady Skript 2 čas 1:00:11.000"
"Byl jsem tady Skript 1 čas 1:00:11.002"
"Byl jsem tady Skript 3 čas 1:00:11.001"

Jestli je zapíše za sebou - jedno v jakém pořadí,
nebo se může stát, že vznikne kolize

např

Kód: [Vybrat]
Byl jsem tady Skript 2 čas 1:00:11.00
Byl jsem tady Skript 1 čas 21:00:11.002
Byl jsem tady Skript 3 čas 1:00:11.001

(Ubral nulu na konci prvního řádku)

To jsem zkusil už kdysi dávno a fungovalo to spolehlivě, k promíchání dat z osmi procesů nedošlo ani jednou.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 15. 10. 2019, 17:31:21
Aplikace prvního zámku:
Kód: [Vybrat]
    $start = AtomicityTestLockTimes($n,$n,1,7);
    if ( $start )
      {
      $success = @mkdir("$n.t1");
      if ( $success == false )
         echo "<b>Failed to lock;</b><br>";
      $result = copy($original_fname, $cname);
      if ( $result == false )
        echo "<h4>BACKUP failed.</h4>";
      $result = @rmdir("$n.t1");
      if ( $result == false )
        echo "<h4>Directory lock was not removed</h4>";
      }

A druhý zámek jsem neaplikoval, jak jsem už napsal.

Zkusil jsem tuto část kódu přepsat podle sebe, tak jen pro inspiraci:

if (AtomicityTestLockTimes($n,$n,1,7) === false) {
    throw new Exception("Selhalo");
}
if (@mkdir("$n.t1") === false) {
    throw new Exception("Failed to lock;");
}
if (copy($original_fname, $cname) === false) {
    throw new Exception("BACKUP failed.");
}
if (@rmdir("$n.t1") === false) {
    throw new Exception("Directory lock was not removed");
}
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 15. 10. 2019, 17:42:15
A teď už konečně výsledky z posledního testu. A doufám, že tento byl už opravdu poslední.

Jak vidíte, zkopírování 2MB souboru + čtení a zápis v originále už začíná být znát. Nejvyšší čas (v poměru k velikosti souboru) je 2.7 MB.

První časy pro jednotlivé bloky a procesy:
Kód: [Vybrat]
523kB 0,848779202 0,257663012 0,257443905 0,001293182
948kB 0,001987934 1,540060997 0,002835035 1,537259817
1371kB 0,004508018 0,818147898 0,005446196 2,225590944
1913kB 1,965152025 3,108391047 0,008336067 3,122910023
2701kB 0,679250002 4,378324986 0,013814211 0,009026051
4495kB 3,45074296 3,259652853 0,037675858 0,021569967
6758kB 0,275954008 8,090615034 0,042881966 6,911487103

Chybovost považuju za 0, i když je fakt, že na začátku jsou prodlevy kvůli čekání na zámek pro copy().
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 16. 10. 2019, 11:44:23
Návštěvníkům, kteří zde zabloudí se asi nebude chtít vše pročítat, tak mohl bys k tomu grafu stručně napsat jaké z něj plyne tvé doporučení nebo závěr pro ostatní programátory PHP? Podle názvu této diskuze bude návštěvníky hlavně zajímat, kterou funkci (zámek) použít pro čtení/zápis souborů.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 16:25:19
Teď to čtu v manuálu, že append mode pro fopen je atomický.

"If handle was fopen()ed in append mode, fwrite()s are atomic (unless the size of string exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption."
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 16:32:49
Pokud to tu čte někdo kdo má práva k editaci prvního příspěvku, bylo by možné tam editací připojit ten poslední graf a odkaz na příspěvek #140 se závěrečným funkčním kódem?

Návštěvníkům, kteří zde zabloudí se asi nebude chtít vše pročítat, tak mohl bys k tomu grafu stručně napsat jaké z něj plyne tvé doporučení nebo závěr pro ostatní programátory PHP? Podle názvu této diskuze bude návštěvníky hlavně zajímat, kterou funkci (zámek) použít pro čtení/zápis souborů.

Závěr jsem chtěl napsat, ale pak jsem ho na poslední chvíli smazal. Lze použít script co jsem tu vložil - test10 - si upravit. Každý si ale musí doladit jaký chce použít mód. Já teď například píšu univerzální funkci pro zápis, která bude přidávat data. V praxi přece nikdo nechce jen načíst data. Musíš to udělat tak, že načteš data, pak provedeš operace a pak je uložíš. Což znamená znovu zkontrolovat velikost souboru, porovnat jestli velikost sedí nebo případně načíst celý soubor v modu r+, porovnat data, dát rewind a zapsat. Jen tak si člověk může ověřit že mezi zpracováváním dat nedošlo ke změně. Člověk se může rozhodnout jestli tu kontrolu dat chce udělat. Prostě záleží to na tom jak důležitý je ten souboru a jak velký provoz je na stránce. Kdo to porovnávat nechce, tak to dá do modu w (write) nebo a (append).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 16. 10. 2019, 17:18:49
Teď to čtu v manuálu, že append mode pro fopen je atomický.

"If handle was fopen()ed in append mode, fwrite()s are atomic (unless the size of string exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption."

Obvykle je ten block size nastaven na 8 KiB, takže na běžné logování je to vyhovující. Ovšem pokud napíšeš
Kód: [Vybrat]
fwrite($f, "Hello, ");
fwrite($f, "World");
tak musíš počítat s tím, že se ti mezi ta dvě slova může vecpat něco jiného. Na to je však snadný recept: Naskládáš si vše do jednoho stringu a ten atomicky zapíšeš jedním vrzem. Je to i rychlejší.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 16. 10. 2019, 17:28:49
V praxi přece nikdo nechce jen načíst data. Musíš to udělat tak, že načteš data, pak provedeš operace a pak je uložíš. Což znamená znovu zkontrolovat velikost souboru, porovnat jestli velikost sedí nebo případně načíst celý soubor v modu r+, porovnat data, dát rewind a zapsat. Jen tak si člověk může ověřit že mezi zpracováváním dat nedošlo ke změně.

Naopak. Data chci buď jen načítat (konfigurace, šablony, data z cizích webů) anebo je chci zapisovat (výstup, logy, PDF, GIF, ...) Nevzpomínám si, kdy jsem naposledy potřeboval obojí s jedním souborem, navíc s rizikem kolize.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 16. 10. 2019, 17:39:18
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 16. 10. 2019, 18:00:21
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?

Proč by měl řešit, zda je nám ten graf k užitku? Zhodnotit si ho může každý, stejně jako ho každý může ignorovat dle své volby.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 16. 10. 2019, 18:32:14
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?
Proč by měl řešit, zda je nám ten graf k užitku? Zhodnotit si ho může každý, stejně jako ho každý může ignorovat dle své volby.
Ano, může si ho každý z nás zhodnotit tak, že bude 2 dny zkoumat zdrojáky a zjišťovat co v tom grafu vlastně je. Proč by tím měl trávit čas každý z nás když to může pár větami shrnout Exkalibr, který tomu ty 2 dny už věnoval.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 18:58:02
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?

Domnívám se, že ten graf mluví za vše, já jsem ho ale okomentoval slovy:

Citace
Jak vidíte, zkopírování 2MB souboru + čtení a zápis v originále už začíná být znát. Nejvyšší čas (v poměru k velikosti souboru) je 2.7 MB.

Zajimavé pro mě je do kdy je užitečné pracovat s jak velkými soubory. S větším souborem nad 2MB se to už přestává vyplácet časově a hypoteticky by se mohlo zvýšit riziko kolize. Zajimavé je, že i když jsem soubor navíc ještě kopíroval u souborů menších než 2MB se to vleze a vyrovná se to křivce T8. T8 byl ten test kde se uplatnil mkdir na hlavní proces (čtení/zápis). Takže výsledky pod 2MB považuji za skvělé. Přece si pamatujete, že T8 hlásilo chyby atomicity.

T10 je řešením pro mě, protože i když kopírování zabírá čas na víc, povedlo se vyloučit chybu atomicity v hlavním bloku (w/r).

Toto řešení alespoň pro mě představuje větší spolehlivost než @mkdir v hlavním bloku.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 19:02:31
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?
Proč by měl řešit, zda je nám ten graf k užitku? Zhodnotit si ho může každý, stejně jako ho každý může ignorovat dle své volby.
Ano, může si ho každý z nás zhodnotit tak, že bude 2 dny zkoumat zdrojáky a zjišťovat co v tom grafu vlastně je. Proč by tím měl trávit čas každý z nás když to může pár větami shrnout Exkalibr, který tomu ty 2 dny už věnoval.

Jenže bez přečtení diskuse se prostě neobejdeš. Jak jinak se dozvíš co je T8? Proč bych to měl opakovat? Ty si přece u toho byl a sám si navrhl T8 @mkdir jako tu pojistku proti přepisům, vlastně si mi taky poradil jak odstranit tu chybu, že kontrola filesize je zbytečná a nespolehlivá. Mě pak došlo, že nemohu rozdělovat proces čtení a proces zápisu na dva bloky, ale musí se vše udělat v jednom.

Hlavní úspěch
je především v tom, že se mi povedlo vyloučit ty selhání zápisu a selhání atomicity, takže T10 je první test s validními výsledky.

Graf pak slouží hlavně pro orientaci v tom, že vidíš jaké jsou zdržení při zápisu na disk když běží 4 procesy ve smyčce bez prodlevy ... a potom jak se ten čas mění, když tam uměle strčíš prodlevu kvůli čekání na uvolnění directory lock.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 16. 10. 2019, 20:34:50
Ty si přece u toho byl a sám si navrhl T8 @mkdir jako tu pojistku proti přepisům, vlastně si mi taky poradil jak odstranit tu chybu, že kontrola filesize je zbytečná a nespolehlivá.
No právě, byl jsem u toho a ani já se v tom nevyznám. Těch úprav, kódu, grafů a popisů chyb bylo tolik. Každého asi první budou zajímat ty nejrychlejší časy T3-T4 u kterých ses obával nespolehlivosti kvůli bufferování, tak jsem myslel, že to nějak okomentuješ.

Hlavní úspěch je především v tom, že se mi povedlo vyloučit ty selhání zápisu a selhání atomicity, takže T10 je první test s validními výsledky.
Jo i to, že všechny ostatní způsoby kromě T10 jsou špatné jsou výsledek. Pak ale nechápu k čemu jsou ty křivky T2-T8b v grafu když u nich dochází k selhání. K čemu je důležité znát rychlost v sekundách když při tom dochází k selhání?

Graf pak slouží hlavně pro orientaci v tom, že vidíš jaké jsou zdržení při zápisu na disk když běží 4 procesy ve smyčce bez prodlevy ... a potom jak se ten čas mění, když tam uměle strčíš prodlevu kvůli čekání na uvolnění directory lock.
A u kterých T je strčená ta prodleva? Možná jsi to psal na stackoverflow.com a možná je to někde na těch 10 stránách této diskuze. Mám dojem, že u T7 jsi psal o 50 microsekundové prodlevě o které jsi prohlásil, že nemá na měření vliv, ale teď myslíš asi jinou prodlevu.
Už je to jedno, jen jsem myslel, že když jsi tomu věnoval tolik času, že z toho uděláš nějaký výcuc, aby člověk mrkl na graf na popis pod ním a během minuty by pochopil o co jde.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 20:58:59
PRODLEVY

T2-T6 mají 50 mikrosekundové prodlevy, které nemají vliv na výsledný čas, ale mají vliv na to jestli dochází k selháním. Protože čím větší je prodleva smyčky, tím větší je pravděpodobnost kolize.

T7 nemá žádnou prodlevu

T8  nemá žádnou prodlevu přímo v hlavním bloku pro čtení a zápis, ale je tam ta prodleva, která se vytváří čekáním na uvolnění zámku vytvořeného přes @mkdir. Tato prodleva je jasně vidět na grafu, protože prodlužuje čas zpracování asi o 1/3 oproti T2 (žlutá čára) a o max. 25-50ms oproti T7.

T8a - (tmavězelenomodrá čára s černými čtverci) je bez korekce
T8b - (bílá čára) po odečtení toho 50 mikrosekundového zpoždění po každém zápisu.

T10 - tam je taky directory lock jako u T8, ale ještě před hlavním blokem (r/w), takže tento hlavní blok se vykoná úplně vždy.

T3 a T4 - bufferování file_get_contents() a file_put_contents()

Ty testy jsem začal dělat proto, že jsem se chtěl bufferování vyhnout. Chtěl jsem najít způsob jak přečíst a zapsat data bezpečně do souboru, aniž bych se musel bát, že když je pozměním, změny nebudou uloženy. Proto mě ty funkce file_get(put)_contents nezajímají, jsou pro mě nepoužítelné.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 21:17:58
Pak ale nechápu k čemu jsou ty křivky T2-T8b v grafu když u nich dochází k selhání. K čemu je důležité znát rychlost v sekundách když při tom dochází k selhání?

Protože vidíš, jak by trvala operace, kdyby tam nebyl ten @mkdir s prodlevou na uvolnění zámku. Uděláš si představu, jak rychlý je ten algoritmus i když ho pro toto řešení nevyužiješ.

Z předchozích výsledků například vyplynulo, že když zapisuješ přes file_put_contents do toho samého souboru, ze kterého pak zase čteš a furt dokola, je to rychlejší než když to zapisuješ do jiného souboru.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 16. 10. 2019, 22:25:30
T3 a T4 - bufferování file_get_contents() a file_put_contents()

Ty testy jsem začal dělat proto, že jsem se chtěl bufferování vyhnout. Chtěl jsem najít způsob jak přečíst a zapsat data bezpečně do souboru, aniž bych se musel bát, že když je pozměním, změny nebudou uloženy. Proto mě ty funkce file_get(put)_contents nezajímají, jsou pro mě nepoužítelné.
No tohle je třeba jedna z věcí co nechápu. file_put_contents má parametr LOCK_EX, takže pokud to budeš mít dobře nastavené, tak se daný soubor zamkne a nic neselže. To, že se to bufferuje je právě výhoda, protože to je nejrychlejší a jak ti Kid hned na začátku diskuze vysvětlil, tak to buferování si hlídá filesystém a nevídím důvod proč bys tuto funkci neměl používat. Nebo místo parametru LOCK_EX můžeš použít mkdir.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 16. 10. 2019, 22:42:28
Taky jsem počítal odchylky od průměru v testech T2 až T7.

Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 17. 10. 2019, 06:37:00
Odchylky od průměru ještě z jiné strany.

Větší soubory v původní velikosti si můžete zobrazit či stáhnout na mém blogu.

https://it-pomocnik.blogspot.com/2019/10/php-results-of-test-atomicity.html
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 17. 10. 2019, 07:30:53
Na blogu jsem updatoval ten poslední obrázek. Ten připojený je vadný (v tom připojeném stejně je prd vidět).

Z odchylek jsem si uvědomil jednu věc, která přesně reflektuje skutečná čísla. Jelikož ten poslední graf čtu zprava doleva, na rozhraní každého nového bloku je vidět velký nárůst odchylky. Vysvětlení je v tom, že nový soubor trvá déle načíst a zapsat. Člověk by očekával mezi jednotlivými testy podobné odchylky, jenže T2 je trochu jiné - vypadá to, jako by se skoková odchylka oproti T6/T7 opozdila o několik cyklů. Na druhou stranu T7 má odchylku ještě před 4495 a 6758, člověk by očekával, že větší odchylka bude na začátku bloku, tak jako u těch menších bloků...
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 17. 10. 2019, 08:25:31
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 17. 10. 2019, 09:49:54
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 17. 10. 2019, 11:28:57
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.

Blbost. Tady už není co dolaďovat napsal jsem snad jasně, že T10 je dokončený a bez chyb. Není co dolaďovat. K ostatním testům se vracet nebudu, nelze je opravit, když obsahují chyby. Jediné v čem se plácáme dokonala je tvá nechápavost. Psal jsem to už několikrát a nebaví mě to opakovat, že ten graf odráží rychlosti čtení a zápisu a chyby v tom nehrají roli. Když došlo k údajnému selhání fwrite, soubor byl přece načten a zkopírován pomocí copy(). Takže ty časy jsou spolehlivé a věruhodné. Nechápu co to tu furt plácáš.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 17. 10. 2019, 11:30:56
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.

Nic jiného netvrdím. Záleží přece na tom jakým způsobem ty funkce použijete a to jsem psal, že já hledám funkci, která umožňuje přístup k souboru více uživateli, načíst soubor, změnit soubor, zapsat soubor. V mých testech není ta změna.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 17. 10. 2019, 11:44:11
Lin
dík za tvou přechozí pomoc. Psal, si ale že se už do diskuse nebudeš zapojovat, tak nechápu co tu furt rozebíráš - tvoje pocity mě nezajímají. Stálo mě to dost energie a nemám náladu číst, že je to k ničemu. Fakta a grafy jsem zveřejnil a algorytmy taky. Nezajímá tě to? Tak sem už nepiš. Děkuji.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: 🇺🇦LarryLin 17. 10. 2019, 11:50:00
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.

Blbost. Tady už není co dolaďovat napsal jsem snad jasně, že T10 je dokončený a bez chyb. Není co dolaďovat. K ostatním testům se vracet nebudu, nelze je opravit, když obsahují chyby. Jediné v čem se plácáme dokonala je tvá nechápavost. Psal jsem to už několikrát a nebaví mě to opakovat, že ten graf odráží rychlosti čtení a zápisu a chyby v tom nehrají roli. Když došlo k údajnému selhání fwrite, soubor byl přece načten a zkopírován pomocí copy(). Takže ty časy jsou spolehlivé a věruhodné. Nechápu co to tu furt plácáš.
To, že bych se v tom plácal já není nic překvapivého, tenhle test byl jeden velký chaos, jsi hodně zbrklý. Bohužel se v tom plácáš hlavně ty. Jestliže jsi napsal:
Ty testy jsem začal dělat proto, že jsem se chtěl bufferování vyhnout. Chtěl jsem najít způsob jak přečíst a zapsat data bezpečně do souboru, aniž bych se musel bát, že když je pozměním, změny nebudou uloženy. Proto mě ty funkce file_get(put)_contents nezajímají, jsou pro mě nepoužítelné.
tak to znamená, že jsi došel ke zcela mylnému závěru. Funkce file_get(put)_contents je spolehlivá a použitelná.

PS: psal jsem, že sem nebudu psát, protože jsem se bál, že rozjedeš diskuzi na téma toho nového zámku co jsi vymyslel.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 17. 10. 2019, 12:38:51
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
Nic jiného netvrdím. Záleží přece na tom jakým způsobem ty funkce použijete a to jsem psal, že já hledám funkci, která umožňuje přístup k souboru více uživateli, načíst soubor, změnit soubor, zapsat soubor. V mých testech není ta změna.

Tak to jsem ti přece takový skript napsal. Fopen, flock, fread, fwrite, fclose. To funguje perfektně a bez chyby.

Samozřejmě je lepší používat file_get_contents a file_put_contents s tím, že mezi nimi ten soubor zamknutý není, což v jiných aplikacích vůbec nevadí. Obvykle se totiž používají pro zápis generovaného souboru, logu nebo čtení konfigurace.

Pro práci s daty, u kterých je riziko souběhu při R/W, je dobrá databáze SQLite. Sami autoři uvádí, že jejich cílem byla náhrada funkcí fopen, flock, fread a fwrite. Netuším, proč se tomu bráníš - na diskuzní fórum je to perfektní, rychlé, šetří to místem a má to vyřešeny všechny problémy, se kterými se potýkáš.

Těm grafům nerozumím a zřejmě nejsem jediný.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 18. 10. 2019, 07:31:14
Nic jiného netvrdím. Záleží přece na tom jakým způsobem ty funkce použijete a to jsem psal, že já hledám funkci, která umožňuje přístup k souboru více uživateli, načíst soubor, změnit soubor, zapsat soubor. V mých testech není ta změna.
To ale umožňují všechny funkce, o kterých tady byla řeč. Akorát se (kterákoli z nich) musí správně používat. Navíc ty vaše testy mohou ale nemusí případné chyby odhalit. Konkurenční programování je založené na tom, že pochopíte problém a nastudujete si dokumentaci použitých funkcí. Nelze to založit na testech, protože variant je příliš mnoho, takže je nedokážete otestovat všechny. A do třetice, výsledkem testu, který ověřuje, zda by váš kód mohl být správně, je výstup ano (možná je správně) nebo ne (není správně) – ne žádné grafy. Pokud vám z testu vyjde, že ten kód je špatně, nemá smysl z toho malovat nějaký graf, ale opravit ten kód.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 18. 10. 2019, 17:04:02
@Kit: Po jak velkých blocích je nejoptimálnější načítat data ze souboru? Dejmetomu, že mám texťák s emaily a id-éčkama uživatelů, na začátku je hlavička s rejstříkama cca 2KB. Je nějaký rozdíl v rychlosti či odezvě v tom jestli napoprvé načtu 2kB, 4kB nebo 8kB? Opakuji, že jde jen o první načtení hlavičky, z toho zjistím přesné umístění bloku, ve kterém hledat email po přihlášení; Takový blok by pak měl mít prakticky mezi 50-250 znaky. Takže i kdyby měl soubor 4MB, během přihlašování načtu jen hlavičku a pak ten hledaný blok.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: hawran diskuse 18. 10. 2019, 22:21:15
... nejoptimálnější...
?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 18. 10. 2019, 22:46:29
... nejoptimálnější...
?

Čemu nerozumíš ve slovu "nejoptimálnější"?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 18. 10. 2019, 22:51:06
@Kit: Po jak velkých blocích je nejoptimálnější načítat data ze souboru? Dejmetomu, že mám texťák s emaily a id-éčkama uživatelů, na začátku je hlavička s rejstříkama cca 2KB. Je nějaký rozdíl v rychlosti či odezvě v tom jestli napoprvé načtu 2kB, 4kB nebo 8kB? Opakuji, že jde jen o první načtení hlavičky, z toho zjistím přesné umístění bloku, ve kterém hledat email po přihlášení; Takový blok by pak měl mít prakticky mezi 50-250 znaky. Takže i kdyby měl soubor 4MB, během přihlašování načtu jen hlavičku a pak ten hledaný blok.

Optimální by mělo být 8 KiB, protože to je obvyklá velikost bufferu.

BTW: Slovo "nejoptimálnější" je nesmyslné - slovo "optimální" je superlativem a stupňovat se nedá.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: František Ryšánek 19. 10. 2019, 08:31:25
@Kit: Po jak velkých blocích je nejoptimálnější načítat data ze souboru? Dejmetomu, že mám texťák s emaily a id-éčkama uživatelů, na začátku je hlavička s rejstříkama cca 2KB. Je nějaký rozdíl v rychlosti či odezvě v tom jestli napoprvé načtu 2kB, 4kB nebo 8kB? Opakuji, že jde jen o první načtení hlavičky, z toho zjistím přesné umístění bloku, ve kterém hledat email po přihlášení; Takový blok by pak měl mít prakticky mezi 50-250 znaky. Takže i kdyby měl soubor 4MB, během přihlašování načtu jen hlavičku a pak ten hledaný blok.

Optimální by mělo být 8 KiB, protože to je obvyklá velikost bufferu.

To je totiž dobrá otázka :-(

Na úrovni blokové vrstvy a zřejmě i filesystému je dnes nejmenší optimální velikost přístupové transakce na x86 pravděpodoně 4 kB, což je obvyklá velikost stránky VM a obvyklá velikost sektoru na blokové vrstvě. A nejlíp ještě zarovnat na hranice 4 kB od začátku souboru. Filesystém sice alokuje ve větších "clusterech", ale ty IMO nemusí naráz číst a zapisovat. (Odhlédněme od faktu, že donedávna obvyklá velikost sektoru na disku bývala 512 B - ono to na věci možná mnoho neměnilo, vzhledem k tomu, jak funguje v UNIXu memory management v těsné spolupráci s blokovou vrstvou a souborovými systémy. A odhlédněme od existence "huge pages" na Linuxu a snad i jinde.)

A Kit má naopak pravdu v tom, že 8 kB/kiB je alokační jednotka Apache HTTPd "buckets" (https://ci.apache.org/projects/httpd/trunk/doxygen/group__APR__Util__Bucket__Brigades.html), konkrétně:
Kód: [Vybrat]
/* default bucket buffer size - 8KB minus room for memory allocator headers */
#define APR_BUCKET_BUFF_SIZE   8000
Což osobně čtu tak, že user-space alokátor Apache si přidělenou virtuální paměť (přidělena kernelem po 4 kB) parceluje pro potřeby file IO po 8kB (8192 B), ale payloadu Vaší PHP aplikace z toho dává jenom 8 kiB (8000 B).

Kromě toho je v Linuxu na blokové vrstvě nějaký pevný read-ahead, by default to bývalo 128 kB. A nějaký svůj vlastní adaptivní read-ahead má souborová vrstva - a dá se tuším i ladit explicitním syscallem na otevřený file descriptor, což ale spousta softu nedělá. A při dlouhém sekvenčním zápisu jsem pozoroval, že Linux láme ten stream na ATA transakce dlouhé taky řádově pár set kB - a pokud moje transakce (předávané mým softwarem z user space) nebyly zarovnané na určité hranice mocniny dvou v LBA adresaci disku, tak mi je "lámal vejpůl", aby na blokové vrstvě na té hranici končil a začínal... už je to pár let, dneska to může být jinak.

Při čtení jednoho bloku (Vaše "hlavička") podle mého vůbec nemá smysl se zabývat velikostí čtecí transakce. Obecně důležité je, minimalizovat počet těch transakcí. Jestli načtete jenom 2 kB, které opravdu potřebujete, nebo budete spekulovat na celý bucket, to je myslím dost jedno. Tady bych doporučil: zbytečně to nedrobte. Pokud jde o jednu transakci, tak si prostě řekněte "svému prostředí" o ta data která potřebujete, ale netřeba to zbytečně nafukovat, nepomůžete si. Ony už si to "vrstvy mezi vámi a diskem" vhodně přifouknou a zarovnají (případně zlomí vejpůl, pokud se někde netrefíte na zarovnání).

Podle mého má smysl optimalizovat především *zápis*. Pokud máte data hezky za sebou = taková optimalizace je možná, zapisujte v co největších blocích (zas tak aby Vám to nezačlo dělat problémy s dostupným objemem RAM). Usnadníte tím práci fyzickým diskům - ať už se bude jednat o flash (erase bloky velké pár set kB až jednotky MB) nebo o točivý disk (pro transakce větší než 1 MB se průchodnost v random zátěži začíná blížit průchodnosti sekvenční). Nemá ale smysl, dělat kvůli tomu po svém nějaký read-ahead a write-back, protože potřebujete zapsat 1 B a chcete to systému usnadnit. To je blbost - pokud potřebujete drobné zápisy rozprostřené po ploše, tak se asi nedá nic dělat, a uděláte líp, když to necháte na operačním systému.

Obecně třeba ten bucketový systém v Apačovi je podle mého původně myšlen tak, aby bylo možno transparentně optimalizovat práci s daty na souborovém systému / na disku. A dost jsem se svého času vztekal, že konkrétně pro problém "mnoho paralelních čtoucích sekvenčních klientů nad točivým diskem" ty buckety rozhodně nejsou optimalizované a není je jak ladit. (Jednotná velikost bucketu, nulová možnost práce s maličkými transakcemi vs. s read-aheadem pro zjevně sekvenční streamy. Leda by člověk celou tu bucketovou vrstvu zásadně přepsal.) Asi to docela dobře sedí na VM vrstvu s její 4kB velikostí stránky.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 19. 10. 2019, 10:28:31
Po jak velkých blocích je nejoptimálnější načítat data ze souboru?
Optimální je načítat data po stejných blocích, po jakých je načítá knihovní funkce do bufferu, po jakých s nimi pracuje souborový systém a po jakých s nimi pracuje disk. Přičemž v každé té vrstvě může být blok jinak velký, v lepším případě jsou to alespoň násobky. A v každé té vrstvě to může být v různých případech jinak. Takže nemá smysl to experimentálně zjišťovat, protože tím zjistíte pouze parametry pro ten případ, kde to testujete – a tam je lepší se podívat do konfigurace, jak máte nastavený souborový systém a jaký tam máte disk.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: ByCzech 19. 10. 2019, 14:20:06
Což osobně čtu tak, že user-space alokátor Apache si přidělenou virtuální paměť (přidělena kernelem po 4 kB) parceluje pro potřeby file IO po 8kB (8192 B), ale payloadu Vaší PHP aplikace z toho dává jenom 8 kiB (8000 B).

Jen pro upřesnění. Správě to je:

8kB = 8000 B
8kiB = 8192 B

Nestandardizovaně, když se to v počítačovém pravěku potřebovalo rozlišovat a data a paměťi se počítaly na tisíce bajtů:

8KB = 8192 B

Problém nastal, když se začaly data a paměti počítat v řádech miliónů bajtů a předpona mega (10^3) už má velké písmeno. Později došlo ke standardizaci jako norma EC 60027-2, kde jsou předpony odvozené od těch v tabulce SI, ale stejně se v tom pořád běžně dělá binec a to co je tím myšleno se musí často odvozovat z kontextu, viz např. výrobci disků vs výrobci pamětí, kde GB u disku je 10^6 (SI), ale u pamětí to je 2^20 (takže vlastně GiB).

https://cs.wikipedia.org/wiki/Bin%C3%A1rn%C3%AD_p%C5%99edpona
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 19. 10. 2019, 18:45:55
@Kit:
Pro mě není slovo optimální dostačující. Je optimální a ještě víc optimální. Optimální může být pro vysokoúrovňového programátora, tzn. dostačující, ale pro perfekcionistu nízkoúrovňového programátora je nutné použít superlativum nejoptimálnější, protože to znamená dokonalý stav, kterého každý pedant touží dosáhnout.

Slovo read-ahead se má číst [red ~hed] nebo [ríd ~hed]?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 19. 10. 2019, 18:57:35
František Ryšánek:
Díky za rozsáhlý popis.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 19. 10. 2019, 19:39:54
Mám pocit, že většinou budu provádět zápis do jednoho souboru (append) v rozsahu ~250, ~500, ~1000 bajtů, takže to zarovnávání řešit nemusím.

Ještě dotaz. Potřeboval bych do souboru zapsat rejstřík s idečkama (část první) a k tomu kompatibilní rejstřík s číslama řádků v jiném souboru (část druhá).

S tím se váže otázka na používání funkcí chr a ord. Když bych do souboru chtěl zapsat uživatelská idečka a je třeba to udělat binárně a bezpečně tj. zkopírovat dva bajty s daným id, jak to správně udělat? Já znám jen ty dvě funkce chr a ord mám obavy o to, že tyhle věci budou náročné na výkon. A neměl bych taky řešit endianness (česky endianita?) správnost přečtení z binárního souboru?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Filip Jirsák 19. 10. 2019, 19:42:18
Pro mě není slovo optimální dostačující. Je optimální a ještě víc optimální. Optimální může být pro vysokoúrovňového programátora, tzn. dostačující, ale pro perfekcionistu nízkoúrovňového programátora je nutné použít superlativum nejoptimálnější, protože to znamená dokonalý stav, kterého každý pedant touží dosáhnout.
Optimální ale neznamená dostačující, znamená to nejlepší možný, dokonalý. Jak může být něco nejlepší, když existuje něco ještě lepšího?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 19. 10. 2019, 20:00:29
Problém je v tom, že co je optimální nyní, nemusí být optimální zítra. Vývoj technologií a přístupy se furt mění. To na co dnes pohlížíte jako na optimální řešení, zítra být optimální nemusí. Jestliže to co nazýváte optimální je pomíjivé, pak to není nejoptimálnější (tj. absolutně dokonalé). Já ale míním ten nejoptimálnější stav, to jest více než sám můžete znát. Je to pomyslný stav, pomyslný pojem asi tak jako v elektronice a elektrice se můžeme bavit o supravodivých materiálech a supravodivosti - to jest taky stav, kterého běžně nedostahujete za normálních okolností, kromě těch nasimulovaných někde v laboratořích nebo speciálních vědeckých podmínkách. A žádný nejsupravodivější materiál taky vlastně neexistuje, protože by to musel být materiál, který nemusíte uměle ochlazovat :D.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: František Ryšánek 19. 10. 2019, 20:51:43
S tím se váže otázka na používání funkcí chr a ord. Když bych do souboru chtěl zapsat uživatelská idečka a je třeba to udělat binárně a bezpečně tj. zkopírovat dva bajty s daným id, jak to správně udělat? Já znám jen ty dvě funkce chr a ord mám obavy o to, že tyhle věci budou náročné na výkon. A neměl bych taky řešit endianness (česky endianita?) správnost přečtení z binárního souboru?

Popravdě mi teprve teď došlo, že nemáte k dispozici Céčkový typový systém, pointerovou aritmetiku apod. Prostě všechen ten bordel, který umožňuje koukat na data střídavě jako na buffer binárních bajtů, nulou zakončený řetězec znaků, integer o potřebné délce na nějaké adrese apod. Takže nevím, jak s tím bufferingem. Má PHP aspoň něco jako perlový "binmode" režim souborů? Datový typ "buffer binárních bajtů", nebo třeba jenom stringy co nesmí obsahovat nulové bajty?

Ohledně endianity... procesor při aritmetických operacích očekává data uložená v RAMce v souladu s endianitou Vaší instrukční sady. Formát uložení binárních dat v souboru (nebo na síti) může mít nějaký standard, který endianitu jasně stanoví = může být potřeba, konvertovat indiány mezi instrukční sadou a diskovým formátem.

Koukám, že PHP má jenom jeden integer podle architektury, a to se znaménkem... Tzn. 16bit unsigned hodnota se Vám do něj nejspíš vejde bez problému. Jak k tomu přistupovat po bajtech... jakožto PHP analfabet, bez pointerové aritmetiky, bych se to asi pokusil ohnout pomocí bitwise operátorů (https://www.php.net/manual/en/language.operators.bitwise.php), ty jsou zřejmě k dispozici. Levý a pravý shift, stejně jako masky používané s operací "AND" fungují na úrovni zdrojového textu všude stejně, nezávisle na indiánech v instrukční sadě = tyto operace použité ve zdrojáku jsou multiplatformní. A funkce ord() a chr() jsou myslím použitelné jenom na zobrazitelné ASCII znaky. Pokud potřebujete 16bit čísla ukládat buď jako dva bajty v binárním souboru nebo jako číslo v ASCII textu, podle mého budete potřebovat spíš sprintf()/sscanf() nebo něco na ten způsob (pro konverzi do/z ASCII formátu).
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 19. 10. 2019, 21:06:55
Popravdě mi teprve teď došlo, že nemáte k dispozici Céčkový typový systém, pointerovou aritmetiku apod. Prostě všechen ten bordel, který umožňuje koukat na data střídavě jako na buffer binárních bajtů, nulou zakončený řetězec znaků, integer o potřebné délce na nějaké adrese apod. Takže nevím, jak s tím bufferingem. Má PHP aspoň něco jako perlový "binmode" režim souborů? Datový typ "buffer binárních bajtů", nebo třeba jenom stringy co nesmí obsahovat nulové bajty?

Ano, PHP má i binary-safe mode.

Ohledně endianity... procesor při aritmetických operacích očekává data uložená v RAMce v souladu s endianitou Vaší instrukční sady. Formát uložení binárních dat v souboru (nebo na síti) může mít nějaký standard, který endianitu jasně stanoví = může být potřeba, konvertovat indiány mezi instrukční sadou a diskovým formátem.

V tom také není problém, i když k binární reprezentaci čísla není přístup. Bitové posuny a maskování však umí.

Koukám, že PHP má jenom jeden integer podle architektury, a to se znaménkem... Tzn. 16bit unsigned hodnota se Vám do něj nejspíš vejde bez problému. Jak k tomu přistupovat po bajtech... jakožto PHP analfabet, bez pointerové aritmetiky, bych se to asi pokusil ohnout pomocí bitwise operátorů (https://www.php.net/manual/en/language.operators.bitwise.php), ty jsou zřejmě k dispozici. Levý a pravý shift, stejně jako masky používané s operací "AND" fungují na úrovni zdrojového textu všude stejně, nezávisle na indiánech v instrukční sadě = tyto operace použité ve zdrojáku jsou multiplatformní. A funkce ord() a chr() jsou myslím použitelné jenom na zobrazitelné ASCII znaky. Pokud potřebujete 16bit čísla ukládat buď jako dva bajty v binárním souboru nebo jako číslo v ASCII textu, podle mého budete potřebovat spíš sprintf()/sscanf() nebo něco na ten způsob (pro konverzi do/z ASCII formátu).

Ano tohle všechno v PHP funguje, ale je zde zásadní otázka: Proč dělat tyhle binární opičky, když je to už hotové, v knihovnách, napsáno v C/C++, takže je to i rychlé?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: František Ryšánek 19. 10. 2019, 21:19:06
Ano tohle všechno v PHP funguje, ale je zde zásadní otázka: Proč dělat tyhle binární opičky, když je to už hotové, v knihovnách, napsáno v C/C++, takže je to i rychlé?

Já věděl, že se mám tentokrát zdržet komentáře :-)
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 19. 10. 2019, 22:18:09
o jakých knihovnách je řeč?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 20. 10. 2019, 09:40:21
o jakých knihovnách je řeč?

O těch, které jsou součástí PHP.
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 20. 10. 2019, 14:30:05
Stále mi není jasné jak mám optimálně pracovat s těma číslama.
máms smyčku kde provádím zřetězování. Každý klíč je pár: dvě písmena (dva bajty) a číslo offset (toto číslo ukazuje, v které části souboru s emaily mám začít hledat email). Celý klíč musí mít pevnou délku 4 bajtů.

$keys .= $sub.$size;

Jak mám ale zajistit aby to číslo mělo pevnou délku.
extrakci plánuju udělat takto:

$offset = substr($key, 2,2);

Dva bajty na číslo považuji více než dost - 65025 adres v souboru nikdy nebude.

Jak mám php říct, že číslo chci zapsat dvěma bajtama?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 20. 10. 2019, 15:06:30
Mám to.
Kód: [Vybrat]
$keys .= $sub.pack('S', $size);https://stackoverflow.com/questions/6453061/how-to-convert-integer-to-8bit-binary-data-by-using-php

S   unsigned short (always 16 bit, machine byte order)
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 23. 10. 2019, 20:07:28
Když stat() vrátí toto:
{
    [dev] => 64769
    [ino] => 13258558
    [mode] => 33188
    [nlink] => 1
    [uid] => 3333
    [gid] => 3333
    [rdev] => 0
    [size] => 20856
    [atime] => 1571853683
    [mtime] => 1571853683
    [ctime] => 1571853683
    [blksize] => 4096
    [blocks] => 48
)

Znamená to, že se tam používá velikost bloku 4096?

Taky dotaz, k čemu je dev, ino, rdev. Mohu tyto hodnoty nějak změnit? Jak?

Další dotaz. Když gid bych změnil gid (jak?) dostal bych se k souboru například příkazem stat() nebo nedostatl?
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: Kit 23. 10. 2019, 20:21:04
https://www.php.net/manual/en/function.stat.php
Název: Re:PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)
Přispěvatel: exkalibr 24. 10. 2019, 03:17:08
Už to mám.
$ss = stat();

'size'=>array(
  'size'=>$ss['size'], //Size of file, in bytes.
  'blocks'=>$ss['blocks'], //Number 512-byte blocks allocated
  'block_size'=> $ss['blksize'] //Optimal block size for I/O.
  ),


Jak teda zjistím velikost blocku? Když mám  [size] => 20856 a  [blocks] => 48
size div blocks mi dává 434,5 ... Takže co je to za 512 byte blocky? Spočítal jsem 6 blocků (optimal) po 4096 B. Jen nechápu o jakých 512 bytových blocích je v tom statu řeč.