[php] concorrenza nei file

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
Avatar utente
disko
Prode Principiante
Messaggi: 217
Iscrizione: sabato 27 ottobre 2007, 16:52

[php] concorrenza nei file

Messaggio da disko »

Salve, ho finito un piccolo software per evitare problemi dovuti a scritture/letture simultanee di file.
Si basa sulla funzione flock di PHP, spero possa essere utile :)
https://github.com/jstar88/SafeIO
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [php] concorrenza nei file

Messaggio da crap0101 »

non capisco una cosa: se flock() non supporta il multithreading, quante probabilità ci sono di agire sullo stesso file contemporaneamente di cui l'autore del codice non è a conoscenza?

Altra cosa - non so se è un comportamento "previsto" - è normale non poter riutilizzare lo stesso path durante una sessione?

Codice: Seleziona tutto

crap0101@crap0101-virtual-machine:~/test$ php -a
Interactive shell
php > include("SafeIO/SafeIO.php");
php > $filePath = "data.txt";
php > SafeIO::startTransaction($filePath);
php > $contents = "some cool data";
php > $reset = true;
php > SafeIO::stopTransaction($filePath, $contents, $reset );
php > SafeIO::startTransaction($filePath);
PHP Warning:  flock(): 3 is not a valid stream resource in /home/crap0101/test/SafeIO/SafeIO.php on line 77
PHP Warning:  Uncaught exception 'Exception' with message 'Error while trying to get lock at data.txt' in /home/crap0101/test/SafeIO/SafeIO.php:77
Stack trace:
#0 php shell code(1): SafeIO::startTransaction('data.txt')
#1 {main}
  thrown in /home/crap0101/test/SafeIO/SafeIO.php on line 77

Codice: Seleziona tutto

crap0101@crap0101-virtual-machine:~/test$ php -a
Interactive shell

php > include("SafeIO/SafeIO.php");
php > $filePath = "data.txt";
php > $contents = "some cool data";
php > $reset = true;
php > SafeIO::save($filePath, $contents , $reset);
php > SafeIO::startTransaction($filePath);
PHP Warning:  flock(): 3 is not a valid stream resource in /home/crap0101/test/SafeIO/SafeIO.php on line 77
PHP Warning:  Uncaught exception 'Exception' with message 'Error while trying to get lock at data.txt' in /home/crap0101/test/SafeIO/SafeIO.php:77
Stack trace:
#0 php shell code(1): SafeIO::startTransaction('data.txt')
#1 {main}
  thrown in /home/crap0101/test/SafeIO/SafeIO.php on line 77
php > 
inoltre, la parte della doc riferita alle transazioni mi sembra fuorviante (ho evidenziato le frasi):
Transactions are usefull to ensure an atomic behavior. Expecially, in generic applications , you need to execute actions that require time (like DB queries,loop etc) to know exactly what you need to do: in this situation a common problem is to keep unchanged the target file from modification of others processes.

include("../SafeIO.php");
SafeIO::startTransaction("data.txt","hello world!");
//<----
// ... Other users can't write data.txt while you are inside here ...
//<----
SafeIO::stopTransaction("data.txt"); // now the lock is released
echo SafeIO::open("data.txt");
chi sono i processi e utenti? quelli "normali" del SO? perchè io la intenderei così, ma non è quello che succede

Codice: Seleziona tutto

crap0101@crap0101-virtual-machine:~/test$ php -a
Interactive shell

php > include("SafeIO/SafeIO.php");
php > SafeIO::startTransaction("data.txt","hello world!");
php > // modifico il file da un altro processo: echo 222 > data.txt
php > SafeIO::stopTransaction("data.txt");
php > echo SafeIO::open("data.txt");
222
d'altra parte, è possibile usando anche le funzioni "normali"

Codice: Seleziona tutto

php > include("SafeIO/SafeIO.php");
php > SafeIO::startTransaction("data.txt","hello world!");
php > $f = fopen("data.txt", "a+");
php > fwrite($f, "XXX");
php > SafeIO::stopTransaction("data.txt");
php > echo SafeIO::open("data.txt");
XXX
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
Avatar utente
disko
Prode Principiante
Messaggi: 217
Iscrizione: sabato 27 ottobre 2007, 16:52

Re: [php] concorrenza nei file

Messaggio da disko »

non capisco una cosa: se flock() non supporta il multithreading, quante probabilità ci sono di agire sullo stesso file contemporaneamente di cui l'autore del codice non è a conoscenza?
PHP istanzia un processo univoco per ogni request, a differenza di altri linguaggi come il Java.Infatti un limite prestazionale è la saturazione della CPU anche se non del tutto utilizzata.
Comunque tornando alla domanda, i processi si possono svolgere in parallelo ed in tal caso è probabile che il file sia soggetto a delle race condition.
Il problema non si presenta solo se si usano le sessions in quanto in questo caso esse stesse rappresentano dei lock: una sessione può essere inizializzata solo quando quella precedente è finita e quindi tutte le operazioni all'interno di essa sono safe.
Altra cosa - non so se è un comportamento "previsto" - è normale non poter riutilizzare lo stesso path durante una sessione?
fixato
php > include("SafeIO/SafeIO.php");
php > SafeIO::startTransaction("data.txt","hello world!");
php > $f = fopen("data.txt", "a+");
php > fwrite($f, "XXX");
php > SafeIO::stopTransaction("data.txt");
php > echo SafeIO::open("data.txt");
XXX
quì hai commesso 2 errori: il primo è quello di utilizzare funzioni esterne, che rilasciano il lock in automatico(come il manuale php dice).
Il secondo è un errore logico,stai scrivendo dallo stesso processo.

Per verificare le problematiche relative alla concorrenza prova questo esempio
https://github.com/jstar88/SafeIO/blob/ ... /test2.php

vedrai che se clicchi nella seconda tab di un browser, la pagina aspetterà il completamento dello script avviato nella prima tab.
Questo significa che se uno script lento stà salvando dei dati, è possibile accedere a tali dati (per lettura o scrittura) solo al termine dell'operazione, come è giusto che sia.. altrimenti agiresti su dati obsoleti.
Se invece non utilizzi SafeIO, non c'è alcuna regola di accesso ai file e potresti ottenere dati corrotti.
Avatar utente
Zoff
Moderatore Globale
Moderatore Globale
Messaggi: 33338
Iscrizione: mercoledì 10 ottobre 2007, 22:36

Re: [php] concorrenza nei file

Messaggio da Zoff »

L'idea è interessante ma l'implementazione lascia un po' a desiderare.
Perché usare una classe se poi usano solo ed esclusivamente metodi statici? Tanto vale definite della dunzioni safe_* che assomigliano a quelle usate comunemente dai programmatori, così ta mantenere una continuità logica nel funzionamento.
È opinabile, secondo me, la scelta di trascinarsi dietro il pathname invece che un reference creato appositamente per tener traccia dei comportamenti.
Inoltre i nomi startTransaction() e stopTransaction() sono fuorvianti perché le transazioni sono fortemente legate ai concetti di comit e soprattutto rollback, mentre quello che fanno è solo gestire dei lock.
Così com'è semrba piu' un wrapper per flock piuttosto che una libreria per lagestione della concorrenza dei file.

Molto piu' interessante sarebbe stata l'implementazione di una libreria ad oggetti che permettesse di gestire la concorrenza con la creazione di opportuni oggetti.

Esempio in pseudo codice:

Codice: Seleziona tutto

$safeFile = new ConcurrentFile( 'file.ext' );
$safeFile->write('something to write');
$safeFile->close();
PS: Manca anche la gestione della lettura dei file.
Prima di aprire una discussione leggi le Guide, poi vedi se c'è un HowTo nel Wiki e fai una ricerca nel Forum!
Applica semplicemente il [Risolto]! Prova: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=548821
Vuoi qualcosa di piu' dal forum? Prova i miei script: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=597066
Avatar utente
disko
Prode Principiante
Messaggi: 217
Iscrizione: sabato 27 ottobre 2007, 16:52

Re: [php] concorrenza nei file

Messaggio da disko »

Sì i nomi delle funzioni non sono molto appropriate.
La funzione per leggere è già implementata.
Riguardo l'architettura avevo preso in considerazione l'idea di un oggetto ma l'ho scartata in quanto:
[*] l'utilizzatore della classe deve comunque tenere il riferimento dell'oggetto accessibile ovunque, anche se il problema è risolvibile con il multitone.
[*] sarebbero 3 istruzioni al posto di una corrente
[*]

Codice: Seleziona tutto

$safeFile = new ConcurrentFile( 'file.ext' );
$safeFile->write('something to write');
$safeFile->close();
quì c'è un limite di implementazione, infatti come da codice sarebbe opportuno bloccare la scrittura e lettura di altri processi dal costruttore alla funzione close(). Tuttavia è uno spreco
computazionale bloccare tutto nel caso seguente

Codice: Seleziona tutto

$safeFile = new ConcurrentFile( 'file.ext' );
$data = $safeFile->read();
$safeFile->close();
tanto che si usa richiedere uno share-lock in caso di lettura.
Flock già si occupa della concorrenza, quindi è chiaro che si tratti di uno wrapper.. poi non vedo opportuno utilizzare vecchi stili in php 4
Avatar utente
Zoff
Moderatore Globale
Moderatore Globale
Messaggi: 33338
Iscrizione: mercoledì 10 ottobre 2007, 22:36

Re: [php] concorrenza nei file

Messaggio da Zoff »

Quel codice non voleva essere completo.
Nulla vieta di fare per scritture in piu' tempi:

Codice: Seleziona tutto

$safeFile = new ConcurrentFile( 'file.ext' );
$safeFile->writelock();
//Scrivi quello che ti pare nel tempo che vuoi
$safeFile->releasewritelock();
$safeFile->close();
Questo significa che la read() e la write() gestiscono rispettivamente shared-lock e write-lock atomicamente, in piu' puoi richiedere un writelock per scritture in piu' tempi. In piu' avendo l'oggetto ConcurrentFile la write può essere intelligente e controllare se esiste già il writelock oppure no.

Tra l'altro mi sembra che lo shared-lock non sia gestito neanche nel tuo codice no?
Prima di aprire una discussione leggi le Guide, poi vedi se c'è un HowTo nel Wiki e fai una ricerca nel Forum!
Applica semplicemente il [Risolto]! Prova: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=548821
Vuoi qualcosa di piu' dal forum? Prova i miei script: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=597066
Avatar utente
disko
Prode Principiante
Messaggi: 217
Iscrizione: sabato 27 ottobre 2007, 16:52

Re: [php] concorrenza nei file

Messaggio da disko »

sì, circa linea 30.
Interessante capire esattamente cosa una applicazione richiede.
Se per esempio ho uno script che legge il file di configurazione e lo aggiorna, eseguito su 2 processi A e B.
Com'è impostato funziona così:
A e B leggono il file, A lo aggiorna mentre B aspetta. Quando A ha finito, B lo aggiorna.
Tuttavia sorge una domanda, B lo dovrebbe aggiornare con calcoli effettuati su dati letti prima o dopo la scrittura di A?

Forse sarebbe il caso di far leggere e scrivere A, solo dopo B può leggere e scrivere.
La cosa più semplice per poterlo usare sarebbe usare la tua prima sintassi per richiedere l'esclusive-lock dal costruttore fino alla fine, che dici?
Avatar utente
Zoff
Moderatore Globale
Moderatore Globale
Messaggi: 33338
Iscrizione: mercoledì 10 ottobre 2007, 22:36

Re: [php] concorrenza nei file

Messaggio da Zoff »

L'esclusive-lock nel costruttore sicuramente garantisce l'atomicità ma è un collo di bottiglia notevole.
Se fosse un operazione fatta di frequente ridurrebbe le performance dell'applicazione.

Secondo me meglio il lock implicito nella read() e nella write() e lasciare al programmatore la richiesta esplicita di un esclusive lock per scritture multiple che si vuole vengano eseguite atomicamente.
Prima di aprire una discussione leggi le Guide, poi vedi se c'è un HowTo nel Wiki e fai una ricerca nel Forum!
Applica semplicemente il [Risolto]! Prova: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=548821
Vuoi qualcosa di piu' dal forum? Prova i miei script: http://forum.ubuntu-it.org/viewtopic.php?f=70&t=597066
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [php] concorrenza nei file

Messaggio da crap0101 »

disko [url=http://forum.ubuntu-it.org/viewtopic.php?p=4429725#p4429725][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
php > include("SafeIO/SafeIO.php");
php > SafeIO::startTransaction("data.txt","hello world!");
php > $f = fopen("data.txt", "a+");
php > fwrite($f, "XXX");
php > SafeIO::stopTransaction("data.txt");
php > echo SafeIO::open("data.txt");
XXX
quì hai commesso 2 errori: il primo è quello di utilizzare funzioni esterne, che rilasciano il lock in automatico(come il manuale php dice).
Il secondo è un errore logico,stai scrivendo dallo stesso processo.
Riguardo la fwrite, sicuro? forse in versioni vecchie, nella doc vedo degli esempi in cui flock() è usato proprio insieme a fwrite.
Riguardo la scrittura dallo stesso processo, non dovrebbe essere ancora più semplice - e anche auspicabile - che possa lokkare ugualmente? Nella doc non ho letto di riferimenti a questa cosa, mi aspetterei che possa funzionare *anche* nello stesso processo.
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
Avatar utente
disko
Prode Principiante
Messaggi: 217
Iscrizione: sabato 27 ottobre 2007, 16:52

Re: [php] concorrenza nei file

Messaggio da disko »

PHP supports a portable way of locking complete files in an advisory way (which means all accessing programs have to use the same way of locking or it will not work)
Intendo che la funzione la puoi usare ma devi essere con un handle lokkato, se lo cambi non funziona più .

Ho fatto la v2 :) , è venuta carina.. tra l'altro è possibile nidificare i lock
https://github.com/jstar88/SafeIO/tree/master/v2
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: steff e 5 ospiti