Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Bezpieczny zapis i odczyt
Forum PHP.pl > Forum > PHP
xpose
Witam wszystkich.
Napewno wielu z Was slyszalo o niezawodnosci funkcji flock(), tak samo jak i ja.
Niestety w praktyce sprawa wyglada zupelnie inaczej. Przy dosc duzym obciazeniu - rzedu 200 uzytkownikow na sekunde - funkcja ta poprostu odpusza a efektem tego jest usuwanie zawartosci blokowanych plikow lub ich czesciowa destrukcja. Oto kod ktory wywoluje ta sytuacje:

  1. <?
  2. // =========================
  3. // OPERACJE NA PLIKACH
  4. // -------------------------
  5.  
  6. function file_DeleteLine ($filename, $index) {
  7. $file = file ($filename);
  8.  
  9. $fp = fopen ($filename, "w");
  10. flock($fp, LOCK_EX);
  11. for( $w = 0; $w < count($file); $w++ )
  12. {
  13. if ($index <> $w)
  14. fwrite ($fp, $file[$w]);
  15. }
  16. flock($fp, LOCK_UN);
  17. fclose($fp);
  18. }
  19.  
  20. function file_UpdateLine ($filename, $index, $line) {
  21. $file = file ($filename);
  22. $file[$index] = $line . "rn";
  23.  
  24. $fp = fopen ($filename, "w");
  25. flock($fp, LOCK_EX);
  26. for( $w = 0; $w < count($file); $w++ )
  27. {
  28. fwrite ($fp, $file[$w]);
  29. }
  30. flock($fp, LOCK_UN);
  31. fclose($fp);
  32. }
  33.  
  34. function file_GetLine ($filename, $index) {
  35. $file = fopen ($filename, "r");
  36. $line = -1;
  37. while (!feof ($file)) {
  38. $buffer = fgets($file, 4096);
  39. $line++;
  40. if ($line == $index) {
  41. fclose ($file);
  42. return $buffer;
  43. }
  44. }
  45. fclose ($file);
  46. }
  47.  
  48. function file_LinesCount ($filename) {
  49. if (file_exists($filename)) {
  50. if (filesize($filename) < 500000) {
  51. $file = file($filename);
  52. return count($file);
  53. } else {
  54. $file = fopen($filename, 'r');
  55. while (!feof ($file)) {
  56. fgets($file, 4096);
  57. $lines++;
  58. }
  59. fclose ($file);
  60. return $lines - 1;
  61. }
  62. } else return 0;
  63. }
  64.  
  65. function file_ReplaceLines ($filename, $from, $to) {
  66. $file = file ($filename);
  67.  
  68. $line = $file[$from];
  69. $file[$from] = $file[$to];
  70. $file[$to] = $line;
  71.  
  72. $fp = fopen ($filename, "w");
  73. flock($fp, LOCK_EX);
  74. for( $w = 0; $w < count($file); $w++ )
  75. {
  76. fwrite ($fp, $file[$w]);
  77. }
  78. flock($fp, LOCK_UN);
  79. fclose($fp);
  80. }
  81.  
  82. function file_InsertLine ($filename, $line) {
  83. $fp = fopen ($filename, "a");
  84. flock($fp, LOCK_EX);
  85. fputs ($fp, $line . "rn");
  86. flock($fp, LOCK_UN);
  87. fclose ($fp);
  88. }
  89.  
  90. function file_InsertLineOnTop ($filename, $line) {
  91. if (file_exists($filename)) {
  92. $fp = fopen ($filename, "r");
  93. if (filesize($filename) > 0) {
  94. $old_file = fread($fp, filesize($filename));
  95. }
  96. fclose ($fp);
  97. }
  98.  
  99. $fp = fopen ($filename, "w");
  100. flock ($fp, LOCK_EX);
  101. $file = $line . "rn" . $old_file;
  102. $file = str_replace ("rnrn", "rn", $file);
  103. fputs ($fp, $file);
  104. flock ($fp, LOCK_UN);
  105. fclose ($fp);
  106. }
  107.  
  108. function file_MoveLineToTop ($filename, $index) {
  109. $line = file_GetLine($filename, $index);
  110. file_DeleteLine($filename, $index);
  111. file_InsertLineOnTop($filename, $line);
  112. }
  113.  
  114. function file_SaveToFile ($filename, $something) {
  115. $fp = fopen ($filename, "w");
  116. flock($fp, LOCK_EX);
  117. fputs ($fp, $something);
  118. flock($fp, LOCK_UN);
  119. fclose ($fp);
  120. }
  121.  
  122. function file_ReadFromFile ($filename) {
  123. if (filesize($filename) > 0) {
  124. $fp = fopen ($filename, "r");
  125. $file = fread($fp, filesize ($filename));
  126. fclose ($fp);
  127. return $file;
  128. }
  129. }
  130.  
  131. function file_CreateFile ($filename) {
  132. $fp = fopen ($filename, "w");
  133. fclose ($fp);
  134. }
  135. ?>



W zwiazku z tym mam pytanie.
Czy jest mozliwe napisanie funkcji ktora bedzie dawala calkowita pewnosc ze dane nie zostana utracone ?

Serdecznie dziekuje za odpowiedz i pozdrawiam.
evo
Powiem tylk o tyle ze flock przy duzym obciazeniu wlasnie zawodzi i jest ten problem od dawna znany

Jedyny konkretny sposob to przesiadka na baze. Inne takie jak implementacja kopi rownozednych, ktore podczas wykonywania tworzysz i jesli dane ci gina mozesz w ciagu ulamka sekundy odtworzyc zawartosc lub implementacja ograniczen ilosci zapytan na plik to tylko pol srodki i wczesniej czy pozniej i tak przesiadziesz sie na baze.
envp
200 userów na sekunde ? sic!
heaven
Hej

a przypadiem nie powinieneś sprawdzić co zwraca flock?

może jak zwróci false to znaczy ze plik jest juz zablokowany i trzeba sobie odpuscic zapisywanie do niego ewentualnie poczekac chwilke i znowu sprobowac

  1. <?php
  2. if (flock($fp, LOCK_EX)) { // do an exclusive lock
  3.  fwrite($fp, "Write something heren");
  4.  flock($fp, LOCK_UN); // release the lock
  5. }
  6. ?>
xpose
  1. <?
  2. if (flock($fp, LOCK_EX)) {
  3. usleep(250000);
  4. flock ($fp, LOCK_EX);
  5. } else {
  6. flock ($fp, LOCK_EX);
  7. }
  8. ?>


Mam nadzieje ze to pomoze winksmiley.jpg.
Ewentualny wynik testu opisze tutaj.
Sedziwoj
Szybciej:
  1. <?php
  2. while (!flock($fp, LOCK_EX)) { usleep(250000);};
  3. ?>


Co najwyżej ograniczenie czasowe lub ilości powtórzeń (w sumie to to samo) można dorzucić.
heaven
zrób tak jak pokazał Sedziwoj.

wszędzie zamiast

  1. <?php
  2. flock($fp, LOCK_EX);
  3. ?>


wstaw

  1. <?php
  2. while (!flock($fp, LOCK_EX)) { usleep(100000);}
  3. ?>
Sedziwoj
Oczywiście nie tylko do zapisu trzeba tak zrobić ale również do odczytu, aby krzaczki nie wyskakiwały biggrin.gif

Na prośbę załączam z blokowaniem, od razu mówię że nie spr. więc przejrzeć i przetestować, oraz jest kwestia file() bo przecież on również odczytuje z pliku i może się to nie powieść wtedy zwraca false.
Nie miałem doświadczenia z tak obciążonymi systemami, a manual nic nie mówi na temat blokowania pliku bo przecież go nie otwieramy... tak jak jest teraz powinno już nie być kłopotów, ale bym radził dorzucić jakiś warunek wyjścia z tych pętli, bo jak się zrobi tak że zablokuje plik do zapisu i będzie się próbowało zrobić np. file() to się po prostu zawiesi (jeśli nie zwolni tego do zapisu).

Mamnadzieje że to już będzie działać sprawnie, ale nie daję żadnej gwarancji.
  1. <?php
  2. // =========================
  3. // OPERACJE NA PLIKACH
  4. // -------------------------
  5.  
  6. function file_DeleteLine ($filename, $index) {
  7. while (($file = file($filename))==false) { usleep(100000);}
  8. $fp = fopen ($filename, "w");
  9. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  10. for( $w = 0; $w < count($file); $w++ )
  11. {
  12. if ($index <> $w)
  13. fwrite ($fp, $file[$w]);
  14. }
  15. flock($fp, LOCK_UN);
  16. fclose($fp);
  17. }
  18.  
  19. function file_UpdateLine ($filename, $index, $line) {
  20. while (($file = file($filename))==false) { usleep(100000);}
  21. $file[$index] = $line . "rn";
  22. $fp = fopen ($filename, "w");
  23. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  24. for( $w = 0; $w < count($file); $w++ )
  25. {
  26. fwrite ($fp, $file[$w]);
  27. }
  28. flock($fp, LOCK_UN);
  29. fclose($fp);
  30. }
  31.  
  32. function file_GetLine ($filename, $index) {
  33. $file = fopen ($filename, "r");
  34. $line = -1;
  35. while (!flock($fp, LOCK_SH)) { usleep(100000);};
  36. while (!feof ($file)) {
  37. $buffer = fgets($file, 4096);
  38. $line++;
  39. if ($line == $index) {
  40. fclose ($file);
  41. return $buffer;
  42. }
  43. }
  44. flock($fp, LOCK_UN);
  45. fclose ($file);
  46. }
  47.  
  48. function file_LinesCount ($filename) {
  49. if (file_exists($filename)) {
  50. if (filesize($filename) < 500000) {
  51. while (($file = file($filename))==false) { usleep(100000);}
  52. return count($file);
  53. } else {
  54. $file = fopen($filename, 'r');
  55. while (!flock($fp, LOCK_SH)) { usleep(100000);};
  56. while (!feof ($file)) {
  57. fgets($file, 4096);
  58. $lines++;
  59. }
  60. flock($fp, LOCK_UN);
  61. fclose ($file);
  62. return $lines - 1;
  63. }
  64. } else return 0;
  65. }
  66.  
  67. function file_ReplaceLines ($filename, $from, $to) {
  68. while (($file = file($filename))==false) { usleep(100000);}
  69. $line = $file[$from];
  70. $file[$from] = $file[$to];
  71. $file[$to] = $line;
  72. $fp = fopen ($filename, "w");
  73. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  74. for( $w = 0; $w < count($file); $w++ )
  75. {
  76. fwrite ($fp, $file[$w]);
  77. }
  78. flock($fp, LOCK_UN);
  79. fclose($fp);
  80. }
  81.  
  82. function file_InsertLine ($filename, $line) {
  83. $fp = fopen ($filename, "a");
  84. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  85. fputs ($fp, $line . "rn");
  86. flock($fp, LOCK_UN);
  87. fclose ($fp);
  88. }
  89.  
  90. function file_InsertLineOnTop ($filename, $line) {
  91. if (file_exists($filename)) {
  92. $fp = fopen ($filename, "r");
  93. while (!flock($fp, LOCK_SH)) { usleep(100000);};
  94. if (filesize($filename) > 0) {
  95. $old_file = fread($fp, filesize($filename));
  96. }
  97. flock($fp, LOCK_UN);
  98. fclose($fp);
  99. }
  100. $fp = fopen ($filename, "w");
  101. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  102. $file = $line . "rn" . $old_file;
  103. $file = str_replace ("rnrn", "rn", $file);
  104. fputs ($fp, $file);
  105. flock ($fp, LOCK_UN);
  106. fclose ($fp);
  107. }
  108.  
  109. function file_MoveLineToTop ($filename, $index) {
  110. $line = file_GetLine($filename, $index);
  111. file_DeleteLine($filename, $index);
  112. file_InsertLineOnTop($filename, $line);
  113. }
  114.  
  115. function file_SaveToFile ($filename, $something) {
  116. $fp = fopen ($filename, "w");
  117. while (!flock($fp, LOCK_EX)) { usleep(100000);};
  118. fputs ($fp, $something);
  119. flock($fp, LOCK_UN);
  120. fclose ($fp);
  121. }
  122.  
  123. function file_ReadFromFile ($filename) {
  124. if (filesize($filename) > 0) {
  125. $fp = fopen ($filename, "r");
  126. while (!flock($fp, LOCK_SH)) { usleep(100000);};
  127. $file = fread($fp, filesize ($filename));
  128. flock($fp, LOCK_UN);
  129. fclose ($fp);
  130. return $file;
  131. }
  132. }
  133.  
  134. function file_CreateFile ($filename) { //a czy nie powinnieneś spr. czy już nie istnieje?
  135. $fp = fopen ($filename, "w");
  136. fclose ($fp);
  137. }
  138. ?>
xpose
Niestety podane przez Ciebie rozwiazanie nie dziala poprawnie.
Wyskakuje mi blad w linii nr. 35.
Sedziwoj
Oj, czy tak ciężko zobaczyć co jest nie tak?
  1. <?php
  2. function file_GetLine ($filename, $index) {
  3. $file = fopen ($filename, "r");
  4. $line = -1;
  5. while (!flock($file, LOCK_SH)) { usleep(100000);};
  6. while (!feof ($file)) {
  7. $buffer = fgets($file, 4096);
  8. $line++;
  9. if ($line == $index) {
  10. fclose ($file);
  11. return $buffer;
  12. }
  13. }
  14. flock($file, LOCK_UN);
  15. fclose ($file);
  16. }
  17. ?>

Chodziło o to że w tej funkcji w odróżnieniu od reszty uchwyt pliku masz w zmiennej $file (a winnych masz w $fp)
Popraw jeszcze funkcje file_LinesCount tzn. zamień linie 55 z:
  1. <?php
  2. while (!flock($fp, LOCK_SH)) { usleep(100000);};
  3. ?>

na
  1. <?php
  2. while (!flock($file, LOCK_SH)) { usleep(100000);};
  3. ?>

A mówiłem, że nie testowałem.

a jeszcze w file_LinesCount popraw flock bo też odwołuje się do złej zmiennej.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.