PHP - flock

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Voor een eenvoudige teller op één van mijn sites, gebruik ik een zelfgeschreven teller-script.

Het werkt extreem simpel;
  • er wordt een tekstbestandje geopend
  • daarin staat een getal (bv. 245)
  • bij elke pageview wordt dat getal opgehoogd met 1 (bv. 246)
  • daarna wordt het geupdate tekstbestand weggeschreven
Het principe van de teller werkt goed, maar het probleem is dat het tekstbestand zichzelf soms lijkt te resetten. Dan heb je bv. een totaal-pageviews van 25.010 en een dag later zijn het er 34 (bijvoorbeeld).

Ik denk zelf dat het komt doordat twee bezoekers op exact hetzelfde moment toegang krijgen tot het tekstbestand en dat het bestand dus wordt geblokkeerd door persoon 1 als persoon 2 de waarde ín het bestand wil verhogen... gevolg is dat de server er van uit gaat dat het bestand er niet is, en dus vrolijk uitgaat van 0 vorige bezoekers en dus gewoon een 1 wegschrijft.

Om dit te voorkomen heb ik natuurlijk van alles geprobeerd, en ik had zelf de hoop gevestigd op de flock functie, maar ook dat werkt niet... De teller blijft zichzelf resetten (overigens ook bij andere tekstbestanden waarbij ik de functie aanroep).

De codes die ik tot nu toe heb gebruikt, heb ik zelf geschreven en zijn eigenlijk allemaal hetzelfde- alleen de syntax is hooguit iets anders.

Ik kan niet verklaren waarom het tekstbestand soms wordt gereset... als het niet is gelockt, zou het nl. helemaal niet mogen worden aangepast... Verder heb ik nog met de variabelen achter fopen gespeeld (wb+, r+, etc...), maar dat biedt ook geen soelaas... helaas.

De read/write-code op de server van het tekstbestand is 666, overigens...

PHP:
1
2
3
4
5
6
7
8
$FileName = 'counter.txt'
$CountFile = fopen ($FileName, 'wb+');
if(flock($CountFile,LOCK_EX))
{
fwrite($CountFile,$ToonUpdate);
flock($CountFile,LOCK_UN);
}
fclose($CountFile);


PHP:
1
2
3
4
5
6
7
8
9
$FileName = 'counter.txt'
$fp = fopen($FileName, "r+");
if (flock($fp, LOCK_EX)) // do an exclusive lock
    { 
ftruncate($fp, 0); // truncate file
fwrite($fp, $ToonUpdate);
flock($fp, LOCK_UN); // release the lock
    } 
fclose($fp);


PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$the_file = 'counter.txt'; // het bestand met de counter-data
$the_data = 3421; // het counter-getal dat moet worden weggeschreven
$fh = fopen($the_file,'wb+');
$tries = 3;

while ($tries > 0)
{
$locked = flock($fh,LOCK_EX | LOCK_NB);
if(!$locked){sleep(5);$tries--;}
else{$tries = 0;}
}

if ($locked)
{
fwrite($fh,$the_data);
fflush($fh);
flock($fh,LOCK_UN);
fclose($fh);
}

[ Voor 3% gewijzigd door b2vjfvj75gjx7 op 05-09-2010 11:54 ]


Acties:
  • 0 Henk 'm!

  • new_guy
  • Registratie: Oktober 2009
  • Laatst online: 21:38
Is er een reden dat je dit niet in een database pompt..?

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Is er een reden dat je dit niet in een database pompt..?
De slechts denkbare; ik heb geen verstand van databases... ik focus me meer op PHP-scripting, Javascript, CSS, vormgeving en content... vandaar.

Maar dan nog zou het niet mogen dat een bestand wordt gereset, op het moment dat je als voorwaarde stelt dat er alleen toegang mag zijn als hij niet is gelockt, lijkt mij...?

Acties:
  • 0 Henk 'm!

  • Bigs
  • Registratie: Mei 2000
  • Niet online
Als je nou gewoon voordat je het bestand wegschrijft controleert of je wel een waarde uit het bestand hebt kunnen lezen dan ben je er volgens mij al. En anders kun je inderdaad het beste een database gebruiken.

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Als je nou gewoon voordat je het bestand wegschrijft controleert of je wel een waarde uit het bestand hebt kunnen lezen
Dat is wel een slimme work-around... maar bestaat er niet iets als een 100% werkende flock-methode?

Die functie zal niet voor niets zijn bedacht, lijkt mij...

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ik zou zeggen dat dit een prima moment is om dan juist wel iets over databases te gaan leren. Ergens geen kennis van hebben is wel een heel slecht excuus om niet voor de beste oplossing te gaan. :)

Verder: Waar hoort mijn topic?

WEB >> PRG

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

Verwijderd

Hoe kom je aan $ToonUpdate?

Ik neem aan door gewoon met fopen het bestand als read-only te openen, te controleren of dat is gelukt, en zo ja, dan pas te besluiten dat je het tellertje wilt uitlezen, ophogen en wegschrijven?

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Hoe kom je aan $ToonUpdate?
O ja... dat is een restje die ik had moeten omzetten naar normale data voor dit forum :)

Maar $ToonUpdate is de waarde die moet worden weggeschreven... Het representeert een getal, dat aangeeft hoe vaak een bepaalde cartoon is bekeken... Feitelijk is het gewoon een getal, bv. 3421
Ik neem aan door gewoon met fopen het bestand als read-only te openen, te controleren of dat is gelukt, en zo ja, dan pas te besluiten dat je het tellertje wilt uitlezen
Exact... en dat heb ik geprobeerd met het derde PHP-voorbeeld in mijn initiële post... Maar zelfs met die codes wordt de boel soms gereset... En ik kan niet achterhalen wat ik fout doe, of wat er op de server gebeurd als het mis gaat...

Er wordt daarbij netjes gekeken of het bestand in gebruik is, er worden 3 pogingen gedaan om dit te bereiken en tussen elke poging zit een plaspauze...

Mocht het bestand dan nog in gebruik zijn, dan zou er gewoon niets mogen gebeuren; liever geen pageview er bij dan één die alle andere reset...

[ Voor 16% gewijzigd door b2vjfvj75gjx7 op 05-09-2010 11:56 ]


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Misschien niet een oplossing voor je probleem, maar waarom niet een van de vele bestaande oplossingen gebruiken?

Acties:
  • 0 Henk 'm!

  • Bigs
  • Registratie: Mei 2000
  • Niet online
b2vjfvj75gjx7 schreef op zondag 05 september 2010 @ 11:44:
[...]


Dat is wel een slimme work-around... maar bestaat er niet iets als een 100% werkende flock-methode?

Die functie zal niet voor niets zijn bedacht, lijkt mij...
Het is niet een work-around, maar gewoon een verstandige manier van programmeren. In een request 5 seconden wachten tot je een lock hebt (voorbeeld 3) maakt de zaak alleen maar ernstiger. Bovendien verhelpt jouw voorbeeld het probleem niet omdat het lezen van het bestand nog steeds mis kan gaan waardoor je daarna alsnog een 0 naar het bestand schrijft. De correcte werkwijze zou zijn:

lock -> lezen -> truncate -> schrijven -> unlock

Zo weet je zeker dat een ander script het bestand niet kan bewerken terwijl jij het aan het updaten bent.

[ Voor 6% gewijzigd door Bigs op 05-09-2010 12:04 ]


Acties:
  • 0 Henk 'm!

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
In je flock gebruik je de LOCK_NB; non-blocking.
Terwijl jij dit locking mechanisme juist wél in blocking mode wilt gebruiken; Bezoeker 2 moet wachten tot bezoeker 1 de lock vrijgeeft

Zie ook de volgende warning in de documentatie
On some operating systems flock() is implemented at the process level. When using a multithreaded server API like ISAPI you may not be able to rely on flock() to protect files against other PHP scripts running in parallel threads of the same server instance!

[ Voor 46% gewijzigd door frickY op 05-09-2010 12:07 ]


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
In je flock gebruik je de LOCK_NB
Dus als ik LOCK_NB weghaal uit de syntax, dan zou het beter moeten gaan?
lock -> lezen -> truncate -> schrijven -> unlock
Dan ga ik dus maar uitvogelen hoe ik deze volgorde kan activeren :)
Misschien niet een oplossing voor je probleem, maar waarom niet een van de vele bestaande oplossingen gebruiken --- Google Analytics?
Omdat ik eigenwijs ben... en ik geen gebruik wil maken van scripts / services van derden... Ik vind het leuker om alles zelf uit te vogelen;

Liever een minder werkend eigen tellertje, dan de super-geavanceerde methode die Google gebruikt...

[ Voor 43% gewijzigd door b2vjfvj75gjx7 op 05-09-2010 12:11 ]


Acties:
  • 0 Henk 'm!

Verwijderd

frickY schreef op zondag 05 september 2010 @ 12:04:
In je flock gebruik je de LOCK_NB; non-blocking.
Terwijl jij dit locking mechanisme juist wél in blocking mode wilt gebruiken; Bezoeker 2 moet wachten tot bezoeker 1 de lock vrijgeeft.
Dat is een goede. Maar toch denk ik dat het al misgaat bij het lezen van de oude waarde(s) of het bepalen van de nieuwe.

Acties:
  • 0 Henk 'm!

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Oveirgens. Een fopen('file', 'w') zal de file truncaten nog voor je de lock hebt verkregen. Je zult de file moeten openen in append-mode. Daarna lock je hem, lees je de waarde, truncate je hem (ftruncate) en schrijf je de nieuwe waarde.

Google eens naar "php atomic file read/write" en/of "php thread-safe file read/write".

[ Voor 15% gewijzigd door frickY op 05-09-2010 12:11 ]


Acties:
  • 0 Henk 'm!

  • ZpAz
  • Registratie: September 2005
  • Laatst online: 15:23
Omdat ik eigenwijs ben... en ik geen gebruik wil maken van scripts / services van derden... Ik vind het leuker om alles zelf uit te vogelen;
Is dit dan geen goed moment om uit te vogelen hoe databases werken? ;)

Tweakers Time Machine Browser Extension | Chrome : Firefox


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Is dit dan geen goed moment om uit te vogelen hoe databases werken
Tja, als ik zo iets simpels als een flock al niet onder de knie krijg... :)

Acties:
  • 0 Henk 'm!

Verwijderd

Met alle respect, voor iets als een tellertje gaan verwijzen naar "een database" is natuurlijk ook complete onzin. Wie iets in een database gaat zetten omdat hij geen ervaring heeft met de bijeffecten van multithreading is ook maar een fucktard. En die snapt er na afloop nog steeds niet van.

Dit is echt gewoon een kwestie van defensief programmeren. Kijk naar de return values van de fopen en flock functies en doe daar iets mee! Controleer bijvoorbeeld of je écht wel die lock hebt verkregen. Of je écht wel de oude waarde kon uitlezen.

Acties:
  • 0 Henk 'm!

  • Dima_2005
  • Registratie: April 2007
  • Laatst online: 13-09 20:26

Dima_2005

T.net-verslaafde

Natuurlijk in een database is simpeler om defensief te programmeren. Je steekt gewoon een PHP_session_id in een tabel, en als je het aantal bezoekers wilt weten, vraag je dan gewoon een count op.

Een tweaker zoekt altijd op Google, ik zou dat ook beter moeten doen :)


Acties:
  • 0 Henk 'm!

  • console
  • Registratie: September 2002
  • Laatst online: 21:26
b2vjfvj75gjx7 schreef op zondag 05 september 2010 @ 12:07:
[...]


Dus als ik LOCK_NB weghaal uit de syntax, dan zou het beter moeten gaan?


[...]


Dan ga ik dus maar uitvogelen hoe ik deze volgorde kan activeren :)


[...]


Omdat ik eigenwijs ben... en ik geen gebruik wil maken van scripts / services van derden... Ik vind het leuker om alles zelf uit te vogelen;

Liever een minder werkend eigen tellertje, dan de super-geavanceerde methode die Google gebruikt...
Maak er dan een database achter waardoor je nog meer informatie kan opslaan van de gebruiker die jouw website bezoekt. Zo kan je zien waar de bezoeker vandaan komt; Zoekmachine (Google/Bing/Yahoo/etc.) en met welke keyword deze gebruiker binnenkomt.

Is veel leuker dan alleen een tellertje ;)

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Kijk naar de return values van de fopen en flock functies en doe daar iets mee!
Daar ben ik nu ook mee bezig... ik begin bij de basis :)

Als die eenmaal werkt, kan een geavanceerdere oplossing altijd nog...

En om nu een MySQL te beginnen om een count++ te doen, lijkt me wat overkill...

Acties:
  • 0 Henk 'm!

Verwijderd

Dima_2005 schreef op zondag 05 september 2010 @ 13:01:
Natuurlijk in een database is simpeler om defensief te programmeren. Je steekt gewoon een PHP_session_id in een tabel, en als je het aantal bezoekers wilt weten, vraag je dan gewoon een count op.
Of je raadpleegt gewoon software als Webalizer of AWstats. Nee, die gebruiken ook geen databases. Of je gebruikt Google Analytics.
Je wilt niet weten hoe vaak ik heb gezien dat het bijhouden van bezoekersstatistieken in een database een hoop gezeik heeft opgeleverd...

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Of je raadpleegt gewoon software als Webalizer of AWstats
Natuurlijk ben ik bekend met deze diensten... Aardig alternatief is ook http://piwik.org/

Maar uiteindelijk wil ik het gewoon zelf uitvogelen... ook omdat ik dan veel specifiekere info kan achterhalen en ordenen dan een standaard dienst je kan bieden...

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 21-09 10:43

Matis

Rubber Rocket

Waarom niet http://www.php.net/manual/en/function.file-get-contents.php gebruiken om het nummer in te lezen, het nummer op te hogen en weg te schrijven met http://php.net/manual/en/function.file-put-contents.php en als vlag LOCK_EX mee te geven.
Mochten er dan op exact hetzelde moment twee mensen het bestand claimen, dan wordt er maar 1tje geteld, immers schrijven beide processen dezelfde initiële waarde + 1 weg.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Tja.. maar ik gebruik deze functies al....

Dit is het script dat ik nu gebruik, en daarbij gaat het dus mis;

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// get score-value

$FileName = '/data/toonz.txt' // file with counter-data
$OldScore = file_get_contents($FileName); // get old-counter-value
$NewScore = $OldScore++;

$CountFile = fopen($FileName,'wb+'); // open file for writing new values
$locked = flock($CountFile,LOCK_EX); // first, lock the file
if ($locked) // only write something, when locked
{
fwrite($CountFile,$NewScore);
fflush($CountFile);
flock($CountFile,LOCK_UN);
fclose($CountFile);
}


Ik lees de oude waarde uit, zet het bestand op slot, bepaal de nieuwe waarde, en schrijf hem daarna weg...

Maar ook met dit script wordt het tekstbestandje af en toe dus vrolijk op 0 gezet...

[ Voor 25% gewijzigd door b2vjfvj75gjx7 op 05-09-2010 13:37 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Denk nou eens goed na stap voor stap wat er gebeurd en waar dat fout kan gaan. Dan moet het toch vrij duidelijk zijn waarom dit niet werkt. ;)

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Controleer nou eens @)(*&%(@*Q^ altijd de return value van elke system call.

[ Voor 3% gewijzigd door Voutloos op 05-09-2010 13:51 ]

{signature}


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Voutloos schreef op zondag 05 september 2010 @ 13:43:
Controleer nou eens @)(*&%(@*Q^ altijd de return value van elke system call.
PHP:
1
if ($locked)


In principe doe ik dat toch... script mag alleen doorgaan als de boel succesvol is gelocked...

Acties:
  • 0 Henk 'm!

  • disjfa
  • Registratie: April 2001
  • Laatst online: 03-07 14:47

disjfa

be

b2vjfvj75gjx7 schreef op zondag 05 september 2010 @ 13:47:
[...]
In principe doe ik dat toch... script mag alleen doorgaan als de boel succesvol is gelocked...
Dus ook een bestand wat hij net niet kan openen.....

disjfa - disj·fa (meneer)
disjfa.nl


Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
Ik denk dat ik wel een vieze workaround weet voor je blokkeringsprobleem. Gebruik 2 tekstbestanden.

dummy-code:
code:
1
2
3
4
5
6
7
-> Lees bestand1 en onthoud de waarde op
-> Nieuwe waarde bepalen
-> Maak bestand2 en sla de nieuwe waarde op
-> Verwijder bestand1

Eventueel:
-> Hernoem bestand2

Een andere optie is ook om gewoon het eerste tekstbestand in de map te lezen of het bestand dat voldoen aan naam = %count% oid.

Ik ben benieuwd of je hier nog problemen mee krijgt.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Aloys, het introduceren van een extra laag is een klassieke fout bij race condities. Gebruik aub de tools die je aangeboden worden (locks, mutexes, semaphore etc. etc) ipv net zo lang de boel complexer maken in de hoop dat er dan niet meer geracet wordt... ;)

Nogmaals, en zo moelijk was mijn hint niet, controleer gewoon altijd alle calls.

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Daarnaast gewoon even basistechnieken leren zoals hoe locking werkt.

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
disjfa schreef op zondag 05 september 2010 @ 13:48:
[...]

Dus ook een bestand wat hij net niet kan openen.....
Maar als je van te voren met if ($locked) controleert óf het bestand niet al in gebruik is door een ander proces, dan moet de server toch alleen iets doen als aan deze voorwaarde is voldaan?

Wat is anders de syntax om expliciet te bepalen dat hij het bestand met rust moet laten?

Lijkt mij dat "if" een redelijk daadkrachtige voorwaarde is...

if($locked)$DoeJeDing;else{$NietsDoen;}

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Ik zeg toch 2x ELKE CALL. En disjfa heeft het over openen. Dus misschien zou je (oa) ook de file_get_contents moeten checken...

{signature}


Acties:
  • 0 Henk 'm!

  • EvilWhiteDragon
  • Registratie: Februari 2003
  • Laatst online: 20-09 23:55
b2vjfvj75gjx7 schreef op zondag 05 september 2010 @ 13:37:
Tja.. maar ik gebruik deze functies al....

Dit is het script dat ik nu gebruik, en daarbij gaat het dus mis;

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// get score-value

$FileName = '/data/toonz.txt' // file with counter-data
$OldScore = file_get_contents($FileName); // get old-counter-value
$NewScore = $OldScore++;

$CountFile = fopen($FileName,'wb+'); // open file for writing new values
$locked = flock($CountFile,LOCK_EX); // first, lock the file
if ($locked) // only write something, when locked
{
fwrite($CountFile,$NewScore);
fflush($CountFile);
flock($CountFile,LOCK_UN);
fclose($CountFile);
}


Ik lees de oude waarde uit, zet het bestand op slot, bepaal de nieuwe waarde, en schrijf hem daarna weg...

Maar ook met dit script wordt het tekstbestandje af en toe dus vrolijk op 0 gezet...
Je controleert nog steeds het lezen niet.... Als je bestand niet ingelezen wordt, wat is dan dus automatisch de waarde van $NewScore?

LinkedIn
BlackIntel


Acties:
  • 0 Henk 'm!

Verwijderd

Om het helemaal voor te kauwen:

Je moet locken voordat je gaat lezen en pas weer unlocken nadat je hebt geschreven. Dat is de enige manier om de race condition te vermijden.

Anders heb je altijd nog het geval dat in de tijd tussen het lezen en het locken een ander proces het bestand geschreven heeft waardoor die wijziging teniet gedaan wordt.
Daarnaast moet je inderdaad continu controleren of hetgeen je doet wel gelukt is. Het heeft weinig zin om rustig verder te gaan als je script al gefaald heeft.

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
thx :)

Ik ga weer codes kloppen, en hopen dat ze kloppen.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Sowieso vind ik die fopen(wb+) al heel erg twijfelachtig. Volgens manual probeert hij het bestand aan te maken als het niet bestaat en anders truncate hij het.

Geen idee wat hij doet als er dan al een lock opstaat ( dat controleer je pas 1 regel later )

Ik heb zo snel even geen idee of dit effect heeft ( en zoja hoe dit te omzeilen ). Maar sowieso is zoals al eerder aangegeven je file_read_contents al niet safe.

Acties:
  • 0 Henk 'm!

Verwijderd

Waarom niet gewoon achteraan een (tijdelijk) bestand een spatie of dergelijke neerzetten? Daarna gewoon het aantal bytes tellen en je hebt je pageviews. Mode 'a' lijkt mij daar geschikt voor. Je kan bijvoorbeeld elke kilobyte (dus 1000 pageviews), het bestand leeg maken en het aantal schrijven naar een bestand (let wel op dat je dan weer wat pageviews mist!).

Als je het bestandje in ramdisk zet, gaat het een stuk sneller!

[ Voor 9% gewijzigd door Verwijderd op 05-09-2010 14:48 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Rutgerlak, het introduceren van een extra laag is een klassieke fout bij race condities. Gebruik aub de tools die je aangeboden worden (locks, mutexes, semaphore etc. etc) ipv net zo lang de boel complexer maken in de hoop dat er dan niet meer geracet wordt... ;).

Hier heb je bv de kans op 2 processen die tegelijk de 1000e hit menen te hebben en dan heb je weer hetzelfde probleem.
Verwijderd schreef op zondag 05 september 2010 @ 14:47:
Als je het bestandje in ramdisk zet, gaat het een stuk sneller!
Tijd is niet relevant. Je reduceert mogelijk hoevaak je last van de symptomen hebt, maar je hebt het probleem nog immer niet verholpen. Nofi maar lees je aub in over die onderwerp.

[ Voor 32% gewijzigd door Voutloos op 05-09-2010 14:51 ]

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Let trouwens sowieso op dat filelocking niet onder ieder OS even goed geimplementeerd is en je dus afhankelijk van het platform ook met flock nog problemen kunt krijgen.

Wat overigens ook netjes op de manual page staat van flock, in grote rode letters.

[ Voor 20% gewijzigd door Verwijderd op 05-09-2010 14:55 ]


Acties:
  • 0 Henk 'm!

  • 448191
  • Registratie: September 2004
  • Laatst online: 06-09-2024
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
class Counter
{
    private $_filePath;
    private $_fp;

    public function __construct($filePath)
    {
        $this->_filePath = $filePath;
    }

    public function getValue()
    {
        $this->_open();
        $value = $this->_read();
        $this->_close();

        return $value;
    }

    public function setValue($value)
    {
        $this->_open();
        $this->_write($value);
        $this->_close();

        return $this;
    }

    public function increment()
    {
        $this->_open();
        $this->_write($this->_read() + 1);
        $this->_close();

        return $this;
    }

    public function decrement()
    {
        $this->_open();
        $this->_write($this->_read() - 1);
        $this->_close();

        return $this;
    }

    private function _read()
    {
        return (int)fread($this->_fp, 1024);
    }

    private function _write($value)
    {
        ftruncate($this->_fp, 0);
        fwrite($this->_fp, $value);
    }

    private function _open()
    {
        $this->_fp = fopen($this->_filePath, 'a+');

        while(!flock($this->_fp, LOCK_EX | LOCK_NB)){
            usleep(100);
        }
    }

    private function _close()
    {
        flock($this->_fp, LOCK_UN);
        fclose($this->_fp);
    }
}

$counter = new Counter(
    tempnam('/tmp', 'Counter')
);

$counter
    ->setValue(99)
    ->increment()
    ->decrement()
    ->decrement()
;

//int(98)
var_dump($counter->getValue());

Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Thx... ik ben zelf ook flink aan het spelen met alle argumenten / variabelen / etc... en test die weer uit door heel veel fake-calls op het bestand los te laten...

Toch aardig dat zo'n simpel count++ veel reacties losmaakt :)

Acties:
  • 0 Henk 'm!

Verwijderd

Voutloos schreef op zondag 05 september 2010 @ 14:50:
Rutgerlak, het introduceren van een extra laag is een klassieke fout bij race condities. Gebruik aub de tools die je aangeboden worden (locks, mutexes, semaphore etc. etc) ipv net zo lang de boel complexer maken in de hoop dat er dan niet meer geracet wordt... ;).

Hier heb je bv de kans op 2 processen die tegelijk de 1000e hit menen te hebben en dan heb je weer hetzelfde probleem.

[...]
Tijd is niet relevant. Je reduceert mogelijk hoevaak je last van de symptomen hebt, maar je hebt het probleem nog immer niet verholpen. Nofi maar lees je aub in over die onderwerp.
Probleem is wel verholpen, want er wordt gewoon een spatie achteraan het bestand gezet elke keer ipv een oude waarde te verhogen met 1. Tijd maakt wel degelijk uit... anders moet je als je bijv. geen ZFS (of ander soort buffer) gebruikt 3ms lang wachten totdat het weggeschreven is!

Testje, 3 keer tegelijk gedraaid. Je verwacht de uitkomst 3*10000000=30000000 bytes. Het resultaat is "-rw-r--r-- 1 rutger rutger 30000000 2010-09-05 16:25 test.txt".
code:
1
2
3
4
5
6
<?php
$fopen = fopen('test.txt', 'a');

for ($i = 1; $i <= 10000000; $i++) {
    fwrite($fopen, ' ');
}


Met een soortgelijke code, alleen dan de oude waarde steeds verhogen krijgt het volgende resultaat: 16940828. Dit is dus hetzelfde dat de TS aangeeft. Mijn methode is voutloos! Mijn methode is ook een stuk sneller en kost veel minder cpu!

excuus als ik toch iets verkeer doe! Misschien reageert ie anders als in de loop de fopen komt.

Getest: gewoon in 3 terminal windows "php test.php" uitvoeren!

[ Voor 6% gewijzigd door Verwijderd op 05-09-2010 16:46 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Mogelijke eeuwige loop, regel 63. Verder heb ik al niet meer gekeken.
Hoe heb je dit getest? Met ab (Apache benchmark tool) tig concurrent requests doen? Niet vergeten dat het waarschijnlijk misgaat omdat het om een multi-threaded webserver gaat hè? Een loopje in een enkele thread met een file handle die al open is... Sja, dat is redelijk safe. Nu even 100 simultane requests naar een scriptje dat dat één keer moet en mag doen.

[ Voor 72% gewijzigd door Verwijderd op 05-09-2010 16:44 ]


Acties:
  • 0 Henk 'm!

  • 448191
  • Registratie: September 2004
  • Laatst online: 06-09-2024
Verwijderd schreef op zondag 05 september 2010 @ 16:39:
[...]

Mogelijke eeuwige loop, regel 63. Verder heb ik al niet meer gekeken.
Ja ach. In productiecode zou je er een extra timeout aan toe kunnen voegen. In de praktijk is dit alleen zinvol als je ook iets gaat doen met de timeout, anders voegt het alleen een complexiteit toe aan wat bedoeld was als een simpel voorbeeld voor de vraagsteller.

Overigens bespeur ik enige arrogantie in jouw antwoord. Ik ga er maar vanuit dat je niet zo bedoelde.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<?php
class Counter
{
    private $_filePath;
    private $_fp;
    private $_lockTimeout;

    public function __construct($filePath, $lockTimeOut = 1000)
    {
        $this->_filePath = $filePath;
        $this->_lockTimeout = $lockTimeOut;
    }

    public function getValue()
    {
        $this->_open();
        $value = $this->_read();
        $this->_close();

        return $value;
    }

    public function setValue($value)
    {
        $this->_open();
        $this->_write($value);
        $this->_close();

        return $this;
    }

    public function increment()
    {
        $this->_open();
        $this->_write($this->_read() + 1);
        $this->_close();

        return $this;
    }

    public function decrement()
    {
        $this->_open();
        $this->_write($this->_read() - 1);
        $this->_close();

        return $this;
    }

    private function _read()
    {
        return (int)fread($this->_fp, 1024);
    }

    private function _write($value)
    {
        ftruncate($this->_fp, 0);
        fwrite($this->_fp, $value);
    }

    private function _open()
    {
        $this->_fp = fopen($this->_filePath, 'a+');

        $start = microtime(true);
        
        while(!flock($this->_fp, LOCK_EX | LOCK_NB)){
            $time = (microtime(true) - $start) * 1000;
            if($time > $this->_lockTimeout){
                throw new RuntimeException(sprintf("Filelocking timeout after %g ms", $time));
            }
            usleep(100);
        }
    }

    private function _close()
    {
        flock($this->_fp, LOCK_UN);
        fclose($this->_fp);
    }
}

$counter = new Counter(
    tempnam('/tmp', 'Counter')
);

$counter
    ->setValue(99)
    ->increment()
    ->decrement()
    ->decrement()
;

//int(98)
var_dump($counter->getValue());

Acties:
  • 0 Henk 'm!

  • dutchcamel
  • Registratie: November 2004
  • Laatst online: 22:33
b2vjfvj75gjx7 schreef op zondag 05 september 2010 @ 16:05:
[...]


Thx... ik ben zelf ook flink aan het spelen met alle argumenten / variabelen / etc... en test die weer uit door heel veel fake-calls op het bestand los te laten...

Toch aardig dat zo'n simpel count++ veel reacties losmaakt :)
Goed punt, heb je hier al eens goed naar gekeken:

PHP:
1
$NewScore = $OldScore++;


Dat wordt je volgende probleem als je de locking eenmaal werkend hebt ;)

Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
controleer in while loop of bestand bestaat met een interval van een paar milliseconden > bestand hernoemen > bestand bewerken > naam herstellen

~of~

De teller in een bestand in een map opslaan en de tel bijhouden in de naam van het bestand ipv. de content. Via glob() kan je het enige bestand in die map terugvinden. Eventueel nog een controle of de naam van het bestand een cijfer is, voor het geval dat er bagger-bestanden in de map staan.

2 inefficiente methodes, maar zouden kunnen werken.

edit:
Ach ja, natuurlijk kan je ook gewoon controleren of het schrijven gelukt is door achteraf te controleren of de inhoud van het bestand gelijk is aan je gewenste inhoud. Zo niet, opnieuw proberen. Zo krijg je echter wel dat bepaalde tellen overgeslagen kunnen worden wanneer 2 scripts tegelijk van 1003 naar 1004 gaan.

[ Voor 78% gewijzigd door Gamebuster op 05-09-2010 19:49 ]

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Goed punt, heb je hier al eens goed naar gekeken:
Dat is eigenlijk een nep-syntax... heb ik er zelf snel in gezet om op dit forum inzichtelijk te maken wat de werking is...

De feitelijke waarde die wordt weggeschreven is complexer dan bv. 100+1 = 101... omdat ik ook een PaginaID, CounterDatum, etc... in het textbestand wegschrijf...

Dus los van de waarde die ik wil noteren, gaat het vooral om het voorkomen van dubbele script-requests...

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Gamebuster schreef op zondag 05 september 2010 @ 19:44:
controleer in while loop of bestand bestaat met een interval van een paar milliseconden > bestand hernoemen > bestand bewerken > naam herstellen
Je hernoemde bestand heeft dezelfde problematiek als je bestaande bestand enkel heb je er nu vele moeilijkheidsvariabelen bij gecreeerd omdat je nu oa. mag gaan afvangen wat er moet gebeuren :
- als bestand 1 gelockt is
- als bestand 1 er niet meer is en bestand 2 gelockt is
- als bestand 1 er niet meer is en bestand 2 niet gelockt is
- als bestand 1 er niet meer is en bestand 2 er ook niet meer is ( precies na controle op bestand 1 wordt bestand 2 in naam hersteld )
Etc.

Daarom wordt al meerdere keren aangegeven je eerst in te lezen in race-condities ;)
De teller in een bestand in een map opslaan en de tel bijhouden in de naam van het bestand ipv. de content. Via glob() kan je het enige bestand in die map terugvinden. Eventueel nog een controle of de naam van het bestand een cijfer is, voor het geval dat er bagger-bestanden in de map staan.
Het blijft dezelfde problematiek, 2 users die op hetzelfde moment de statistiek benaderen die lezen hetzelfde getal uit en proberen hetzelfde bestand weg te schrijven...
Ach ja, natuurlijk kan je ook gewoon controleren of het schrijven gelukt is door achteraf te controleren of de inhoud van het bestand gelijk is aan je gewenste inhoud. Zo niet, opnieuw proberen. Zo krijg je echter wel dat bepaalde tellen overgeslagen kunnen worden wanneer 2 scripts tegelijk van 1003 naar 1004 gaan.
Dus je gaat extra tellingen genereren?

Het is gewoon heel simpel, je moet het lezen en daarna schrijven in 1 transactie duwen die niet onderbroken kan worden.
Oftewel :
- Lock file
- Read file
- Write file
- Unlock file

Elke andere oplossing is leuk bedacht maar foutief en levert enkel maar meer problemen op

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
In de tussentijd had de TS makkelijker kunnen leren hoe je verbinding legt met een DB en gewoon simpel een record insert :+ Even tellen hoeveel records je hebt en klaar...

Acties:
  • 0 Henk 'm!

  • console
  • Registratie: September 2002
  • Laatst online: 21:26
Cartman! schreef op maandag 06 september 2010 @ 09:22:
In de tussentijd had de TS makkelijker kunnen leren hoe je verbinding legt met een DB en gewoon simpel een record insert :+ Even tellen hoeveel records je hebt en klaar...
Idd, ook gezien hij meer dat alleen een teller nu bijhoud, maar ook datum en paginaID opslaat wat ik zo uitmaakt uit zijn vorige posts. Lijkt mij een database toch fijner werken dan txt bestandjes :+

[ Voor 4% gewijzigd door console op 06-09-2010 09:27 ]


Acties:
  • 0 Henk 'm!

  • i-chat
  • Registratie: Maart 2005
  • Niet online
Verwijderd schreef op zondag 05 september 2010 @ 12:58:
Met alle respect, voor iets als een tellertje gaan verwijzen naar "een database" is natuurlijk ook complete onzin. Wie iets in een database gaat zetten omdat hij geen ervaring heeft met de bijeffecten van multithreading is ook maar een fucktard. En die snapt er na afloop nog steeds niet van.

Dit is echt gewoon een kwestie van defensief programmeren. Kijk naar de return values van de fopen en flock functies en doe daar iets mee! Controleer bijvoorbeeld of je écht wel die lock hebt verkregen. Of je écht wel de oude waarde kon uitlezen.
Met iets minder dan alle respect, maar iemand die op een multitreaded systeem, met multitreaded services (het serveren van meerdere requests op het zelfde moment) begint over fucktards omdat ze gebruik maken van de juiste tools (zelfs al is het om de verkeerde reden) is zelf niet veel beter dan een fucktard.

je hebt helemaal gelijk dat de opgegeven reden van het kiezen voor een database niet helemaal klopt,
maar om die keuze dan gelijk maar te betietelen als 'fucktard' is A: jammer, en B: getuigd van erg weinig inzicht, - je kunt namelijk prima op iets lopen schelden, maar de grote kunst van het 'wijs' zijn ligt hem in het, nadat je de situatie hebt geëvalueerd, geven van de juiste informatie om iemand tot inzicht te laten komen. een linkje naar een informatief stuk tekst, een howto, of een blog over het onderwerp is dus wenselijk.

wijsneus spelen kunnen we allemaal.


nu even iets meer on topic, de Fopen functie is niet bepaalt snel, en de methode van
open lock lees update unlock sluit lijkt me hopeloos traag, met een database zul je natuurlijk nog steeds defensief moeten programmeren, maar het wegschrijven etc gaat wel een stuk sneller, wat betekend dat de volgen tread minder lang hoeft te wachten als het druk is.

verder kun je met een database heel makelijk meer info loggen waaronder bijv. het tijdstip van een hit,
verder kun je ook makkelijker ook enkel de hits loggen en het tellen dus 'dynamisch' doen op het moment datje de stats pagina opent ... maar dat hangt natuurlijk ook af van de vraag of je 'een hitcounter op je hoofdsite wilt'

Acties:
  • 0 Henk 'm!

  • Keiichi
  • Registratie: Juni 2005
  • Laatst online: 19-09 22:32
Cartman! schreef op maandag 06 september 2010 @ 09:22:
In de tussentijd had de TS makkelijker kunnen leren hoe je verbinding legt met een DB en gewoon simpel een record insert :+ Even tellen hoeveel records je hebt en klaar...
Niet dat het een buitengewoon simple casus is om bekend te worden met locking, e.d.


In 2 minuten heb ik ook een dergelijk iets met SQLlite gemaakt :)

Solar @ Dongen: http://solar.searchy.net/ - Penpal International: http://ppi.searchy.net/


Acties:
  • 0 Henk 'm!

  • 448191
  • Registratie: September 2004
  • Laatst online: 06-09-2024
Keiichi schreef op maandag 06 september 2010 @ 09:50:
[...]


Niet dat het een buitengewoon simple casus is om bekend te worden met locking, e.d.


In 2 minuten heb ik ook een dergelijk iets met SQLlite gemaakt :)
SQLite gebruikt POSIX filelocking, net als flock(), maar dan op de hele database (omdat de hele database in een bestand staat). Niet de beste keuze voor high concurrency.

http://www.sqlite.org/lockingv3.html

Acties:
  • 0 Henk 'm!

  • Keiichi
  • Registratie: Juni 2005
  • Laatst online: 19-09 22:32
448191 schreef op maandag 06 september 2010 @ 13:28:
[...]


SQLite gebruikt POSIX filelocking, net als flock(), maar dan op de hele database (omdat de hele database in een bestand staat). Niet de beste keuze voor high concurrency.

http://www.sqlite.org/lockingv3.html
Voor een teller te laten oplopen zal ik daar niet zo heel bang voor zijn dat het bij high concurreny problemen gaat opleveren.

Solar @ Dongen: http://solar.searchy.net/ - Penpal International: http://ppi.searchy.net/


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Verwijderd schreef op zondag 05 september 2010 @ 13:18:
Je wilt niet weten hoe vaak ik heb gezien dat het bijhouden van bezoekersstatistieken in een database een hoop gezeik heeft opgeleverd...
Jij kent dus een hoop prutsers die het niet voorelkaar krijgen een simpel bezoekerstellertje in een DB in te bouwen?

Dit soort systemen gebaseerd op textfiles werken gewoon NIET. Kijk maar naar de eerste incarnaties van UBB waarin ook van een flat file database uitgegaan werd, en die gewoon steevast last hadden van corruptieproblemen bij grote aantallen gebruikers.

Je zult vast prima een simpel guestbook of tellertje in een flat file kunnen maken, maar lezen en schrijven naar een DB is praktisch net zo simpel (heck, simpeler zelfs dan klooien met filelocks), en itt tot een FFDB WEL schaalbaar.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • vistu
  • Registratie: Januari 2007
  • Laatst online: 18-09 15:17
Is het niet een stuk eenvoudiger om bij het runnen van je script een bestand .lock aan te maken, en pas te verwijderen nadat je script klaar is. Wanneer een tweede script loopt en ziet dat het bestand .lock aanwezig is, dan runt het script of niet, of wacht het totdat je .lock file weer weg is.

Acties:
  • 0 Henk 'm!

Verwijderd

Ja gewoon het wiel opnieuw uitvinden, dat werkt altijd ;)

Acties:
  • 0 Henk 'm!

  • 448191
  • Registratie: September 2004
  • Laatst online: 06-09-2024
Keiichi schreef op maandag 06 september 2010 @ 13:51:
[...]


Voor een teller te laten oplopen zal ik daar niet zo heel bang voor zijn dat het bij high concurreny problemen gaat opleveren.
Als je een inconsistent read voorelkaar krijgt, zoals de TS lijkt te suggereren, heeft het al problemen opgeleverd.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
vistu schreef op maandag 06 september 2010 @ 14:28:
Is het niet een stuk eenvoudiger om bij het runnen van je script een bestand .lock aan te maken, en pas te verwijderen nadat je script klaar is. Wanneer een tweede script loopt en ziet dat het bestand .lock aanwezig is, dan runt het script of niet, of wacht het totdat je .lock file weer weg is.
Vistu, het introduceren van een extra laag is een klassieke fout bij race condities. Gebruik aub de tools die je aangeboden worden (locks, mutexes, semaphore etc. etc) ipv net zo lang de boel complexer maken in de hoop dat er dan niet meer geracet wordt... ;).

Hier heb je bv de kans dat 2 processen tegelijk menen dat er geen .lock file is...

Zo. En dit is de 3e keer dat ik dit zeg. Denk nou (*&%@%@)% je eigen brouwsels helemaal uit en beargumenteer voor je zelf hoe de race conditie verdwenen zonder dat je een nieuwe geintrocueerd hebt... :(

{signature}


Acties:
  • 0 Henk 'm!

  • lauwsa
  • Registratie: Juli 2010
  • Laatst online: 10-09 20:43
Of je doet het gewoon zo:
De teller staat op 234949

ipv 234949 in het bestand te schijven toeg je er bvb 1 miljoen er bij
1234949.

Dus in het txt bestand staat 1234949, wil je het outputten op de site doe je -1000000
Als je er 1 bij gaat tellen kijk je als het bestand in gebruik is, is dat niet dan kijk je als het getal 1000000 of hoger is, is dat dan tel je er 1 bij. is het lager. Dan probeer je het bestand opnieuw te openen etc etc. na 3 keer mislukken schrijf je een error weg ;) dan weet je dat het niet lukt.

Bij het "instaleren" van het script maak je een bestand aan waar die 1000000 in staat ;)

Edit:
gewoon een goed idee. Als je zo iets snel wilt oplossen :P

Edit2:
Zodat je het later een beter oplossing kan vinden.

[ Voor 8% gewijzigd door lauwsa op 07-09-2010 15:45 ]


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ik vraag me af of je het topic hebt gelezen en of dit nu een enorme grap is, het slaat namelijk echt nergens op, sorry :{

Acties:
  • 0 Henk 'm!

  • lauwsa
  • Registratie: Juli 2010
  • Laatst online: 10-09 20:43
Zie mijn edit eens :P

Acties:
  • 0 Henk 'm!

  • ajakkes
  • Registratie: Maart 2004
  • Laatst online: 16-05 22:32

ajakkes

👑

Je zit Voutloos uit te dagen of niet? :+

👑


Acties:
  • 0 Henk 'm!

  • lauwsa
  • Registratie: Juli 2010
  • Laatst online: 10-09 20:43
Sorry :p haha.

Ik heb een tijd terug wat in php gedaan alleen niet veel. Dus ik heb niet veel ervaring er mee. Maar ke kan al met heeeel basis mysql zowat maken. Op internet staan zat voorbeelden btw ;)

maar goed ;)

Acties:
  • 0 Henk 'm!

  • EvilWhiteDragon
  • Registratie: Februari 2003
  • Laatst online: 20-09 23:55
@lauwsa, volgens mij doe je precies waar Voutloos in de post boven je over klaagt.

LinkedIn
BlackIntel


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ja, maar dan nog 'creatiever'...

Acties:
  • 0 Henk 'm!

  • lauwsa
  • Registratie: Juli 2010
  • Laatst online: 10-09 20:43
Dat was de bedoeling :P haha

Acties:
  • 0 Henk 'm!

  • ajakkes
  • Registratie: Maart 2004
  • Laatst online: 16-05 22:32

ajakkes

👑

Zal ik er dan nog een schepje bovenop doen?

Gewoon een file creeren met als naam "counter"-"random md5" en alle bestanden in de map tellen. :P

Zal TS z'n echte oplossing nog posten?

👑


Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Je kunt met file_get_contents ook het php-bestand met het tellerscript ophalen, het bestand verwijderen zodat niemand het meer uit kan voeren, vervolgens de teller in het tellerbestand ophogen, en vervolgens het tellerscript weer terugschrijven.

Je kunt ook een hele klasse zonder commentaar voorkauwen en daarin het probleem van de TS met twee regels code oplossen zonder te vertellen wat je daar doet (en wat je ook niet weet omdat je de eerste comment uit de manual hebt overgenomen).

TS: je zal concessies moeten doen. Wil je (lang) wachten tot je uiteindelijk een lock kunt bemachtigen, of wil je counts kwijtraken?

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • Dima_2005
  • Registratie: April 2007
  • Laatst online: 13-09 20:26

Dima_2005

T.net-verslaafde

IK weet nog lang geleden had ik het volgende:

* Elke bezoeker genereert een bestand (met random bestandsnaam)
* Er komt een count van aantal bestanden
* Tussen 1000 en 1100 bezoekers (wegen mogelijkheid van 2 bezoekers tegelijkertijd), worden 1000 bestanden verwijderd en in een speciale txt gestopt waar het aantal dus staat.
* Dit gebeurt dan bij elk duizendtal.

Dit zorgt voor een nauwkeurig aantal-telling. Het is niet heel efficient, maar efficienter dan elke keer een bestand openen en dichtdoen.

Een tweaker zoekt altijd op Google, ik zou dat ook beter moeten doen :)


Acties:
  • 0 Henk 'm!

  • ajakkes
  • Registratie: Maart 2004
  • Laatst online: 16-05 22:32

ajakkes

👑

Ik gok op kort wachten en counts kwijtraken. En eventueel proberen te loggen hoe vaak er kort gewacht moet worden zodat je kort wachten kan verlengen als je denkt veel counts kwijt te raken.

Als ik het goed begrepen heb is hij al blij met een grove schatting.

👑


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22:43
Ik snap de commotie en alle superingewikkelde voorstellen niet. Vooropgesteld dat je geen database wil gebruiken, lijkt het plan van aanpak van 2.4 GHz me prima. Dan is het een kwestie van: locken, lezen, ophogen, schrijven, en unlocken. Ik zou niet weten wat daar fout aan kan gaan.
CodeCaster schreef op dinsdag 07 september 2010 @ 16:28:
TS: je zal concessies moeten doen. Wil je (lang) wachten tot je uiteindelijk een lock kunt bemachtigen, of wil je counts kwijtraken?
Waarom zo'n concessie? Geen enkel proces houdt lang een lock vast, dus de enige reden waarom je lang zou moeten wachten is omdat flock() geen fairness garandeert en je zoveel kleine requests hebt dat je wachtende proces nooit aan de beurt komt. Die kans lijkt me verwaarloosbaar.
Dima_2005 schreef op dinsdag 07 september 2010 @ 16:36:
Ik weet nog lang geleden had ik het volgende:
[..]
Dit zorgt voor een nauwkeurig aantal-telling. Het is niet heel efficient, maar efficienter dan elke keer een bestand openen en dichtdoen.
Heb je dat gebenchmarkt? Het klinkt inderdaad gruwelijk inefficiënt en waarschijnlijk is het updaten van een bestand een stuk efficiënter, want dat blijft gewoon de hele tijd in je filesystem cache zitten (metadata wordt sowieso lazy geüpdate in moderne filesystems). Jouw oplossing lijkt me vele male belastender voor het filesystem omdat je op z'n minst elke keer een nieuw bestand moet alloceren en een directory entry moet updaten. Ik vraag me af waarom je denkt dat dit efficiënter zou zijn?

Acties:
  • 0 Henk 'm!

  • Spockz
  • Registratie: Augustus 2003
  • Laatst online: 21-09 10:08

Spockz

Live and Let Live

Jongens, stop nou eens met het aandragen van allerlei `oplossingen' die alleen maar een extra laag toevoegen waardoor het geheel complexer wordt en het probleem alleen maar wordt verschoven.

Kijk zoals gezegd eens naar mutexen, semaforen, etc. Lees anders ook dit dictaat even. Gedistribueerd Programmeren, Gerard Tel, Universiteit Utrecht (Vooral de eerste hoofdstukken bieden een oplossing voor dit probleem.)

Oh en 2.4Ghz: Met het hele locking verhaal ben je wel op de goede weg, je moet het alleen even goed uitvoeren. Lock aanvragen, kijken of dat lukt, waarde opvragen, waarde ophogen, waarde wegschrijven, lock vrijgeven. Probleem hierbij is dat je geen fairness (dwz, je krijgt niet gegarandeerd een lock) hebt. Maar dit zal in de praktijk niet zo'n probleem opleveren.

Overigens, met alle respect, negeer in ieder geval de volgende opmerkingen want ze slaan echt nergens op:
  1. Aloys in "PHP - flock"
  2. Verwijderd in "PHP - flock"
  3. Verwijderd in "PHP - flock"
  4. Gamebuster in "PHP - flock"
  5. vistu in "PHP - flock"
  6. lauwsa in "PHP - flock"
  7. creator1988 in "PHP - flock"

[ Voor 53% gewijzigd door Spockz op 07-09-2010 17:33 ]

C'est le ton qui fait la musique. | Blog | @linkedin
R8 | 18-55 IS | 50mm 1.8 2 | 70-200 2.8 APO EX HSM | 85 1.8


Acties:
  • 0 Henk 'm!

  • b2vjfvj75gjx7
  • Registratie: Maart 2009
  • Niet online
Bedankt voor alle comments :) Ik experimenteer er vrolijk op los... ben er nog niet 100% over uit hoe ik het moet doen, maar wel in welke richting ik het moet zoeken.

En ik vind het gewoon leuk alles zelf te programmeren, geen Google Analytics of Jquery voor mij... het zelf maken, uitzoeken en een eigen systeem [voor eigen gebruik] neerzetten, vind ik juist de sport van programmeren...

Acties:
  • 0 Henk 'm!

  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 21-09 08:50
Wat je beter zou kunnen doen is een memcached instance installeren, en voor elke gebruiker onder een GUID key een 1 wegschrijven. Dan maak je een cronjob aan die elke paar seconde een PHP pagina uitvoert die telt hoeveel cache-entries er zijn, en dan het bestandje opent en het aantal wegschrijft. Dan invalidate je daarna je hele cache. Omdat je maar één cronjob hebt gaat dit altijd goed.

Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Soultaker schreef op dinsdag 07 september 2010 @ 17:15:
Waarom zo'n concessie? Geen enkel proces houdt lang een lock vast, dus de enige reden waarom je lang zou moeten wachten is omdat flock() geen fairness garandeert en je zoveel kleine requests hebt dat je wachtende proces nooit aan de beurt komt. Die kans lijkt me verwaarloosbaar.
TS heeft z'n exacte code niet gepost en vertelt niet wat 'ie tussen locken en unlocken doet. De kans is er dat je lang moet wachten, maar als jij zegt dat de kans anders verwaarloosbaar is geloof ik dat :)
creator1988 schreef op dinsdag 07 september 2010 @ 17:21:
Wat je beter zou kunnen doen is een memcached instance installeren, en voor elke gebruiker onder een GUID key een 1 wegschrijven. Dan maak je een cronjob aan die elke paar seconde een PHP pagina uitvoert die telt hoeveel cache-entries er zijn, en dan het bestandje opent en het aantal wegschrijft. Dan invalidate je daarna je hele cache. Omdat je maar één cronjob hebt gaat dit altijd goed.
huillach

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
creator1988 schreef op dinsdag 07 september 2010 @ 17:21:
Wat je beter zou kunnen doen is een memcached instance installeren, en voor elke gebruiker onder een GUID key een 1 wegschrijven. Dan maak je een cronjob aan die elke paar seconde een PHP pagina uitvoert die telt hoeveel cache-entries er zijn, en dan het bestandje opent en het aantal wegschrijft. Dan invalidate je daarna je hele cache. Omdat je maar één cronjob hebt gaat dit altijd goed.
Ik hoop dat je dit sarcastisch bedoelt! Laten we dat in dit topic verder maar even achterwege, want voor je het weet gaat iemand het nog op die manier uitproberen.

Volgens mij is 2.4Ghz al op de goede weg, en dat is gewoon op de volgende manier
code:
1
2
3
4
lock( tellerbestand ) {
   teller = lees(tellerbestand);
   shrijf( tellerbestand, teller + 1 );
}

Je moet gewoon zorgen dat het lezen, ophogen en wegschrijven van de tellen een atomic actie is, en dan is het probleem opgelost. De exacte impelementatie met flock kan dan niet zo moeilijk meer zijn.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1