PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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.


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.

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í.

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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.

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.
« Poslední změna: 14. 10. 2019, 12:59:17 od LarryLin »


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?

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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()

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.

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.

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é.

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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?

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

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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.

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!";

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.
« Poslední změna: 14. 10. 2019, 15:04:03 od LarryLin »