Файлы и паралельное вып. скриптов

no_santa

Снегур
Я кладу файлы в папку выше корня, сохраняя их оригинальные имена в БД. Если файлов много - бью директории по дате.
 

AmdY

Пью пиво
Команда форума
no_santa
какое это имеет отношение к теме?
 

DiMA

php.spb.ru
Команда форума
да просто знакомые слова встретил... "файл"
 
Вопрос по одновременному доступу к маленьким файлам с небольшой вероятностью коллизий. flock() не использую , так как читал, что он не работает под некоторыми платформами и файловыми системами. Подскажите, пожалуйста, на сколько такой алгоритм благоприятный, что не учтено, как можно сделать по другому:

Запись в файл.
Создаем файл LOCK('LOCKимя файла') с временем начала записи.
Создаем временный файл на базе оригинала.
В случае успешной записи удаляем оригинал и переименовываем временный файл.
Удаляем LOCK.

Запрос на запись
Смотрим LOCK файл. Если нет => Запись в файл
Если есть.
1. Если разница между текущим временем и временем в LOCK больше 1-2 секунд(значит был сбой, так как маленькие файлы не могут записываться дольше.(?)), удаляем LOCK файл и временный файл. Дальше => Запись в файл.

2. Если разница меньше, запускаем цикл с небольшим значением в usleep() и счетчиком. Как только пропал файл LOCK => Запись в файл. Если счетчик больше, к прим. значения 100, прерываем рекурсию, возвращаем ошибку.
 

DiMA

php.spb.ru
Команда форума
Dattaya

Это полнейший и страшнейший говнокод... Вернее, не говнокод, а непонимание атомарности и многопоточности.

1. Приведенное тобой решение работать не будет, т.к. дыряво и действительно возможны коллизии. На мелком проекте бага может и не случится. На более крупном - вероятность уничтожения данных, если он потенциально существует дыра, равен 100%. Циклы ожидания блокировок так же бред (все проще и короче пишется, в 1-2 строки кода).
2. flock() отличная функция и работает везде. Не читай советскую прессу с утра.
3. это почти единственный способ получить надежный лок от файловой системы любой ОС
4. практически никто не в состоянии правильно оперировать flock(), даже в документации пример с ошибкой (в прошлые годы, сейчас на http://ru.php.net/flock исправлено)
5. на flock() зацикливаться не нужно, существуют десятки методов сделать лок другими средствами

Правильный пример. Файл lock нужно создать заранее до старта проекта (для упрощения).

$f=fopen("lock", "r+");
flock($f, LOCK_EX);

Далее читаем содержимое и пишем/стираем флаг "занят". Для упрощения на ошибки можно ничего не проверять, т.к. их в нормальном случае быть не может (если того файла действительно нет или нет прав открыть на чтение+запись). Но в серьезной работе естественно все нужно проверять.
 

clanth

Новичок
А не проще использовать функции взаимоблокировок, предназначенные именно для этого?
http://www.php.net/manual/en/function.sem-acquire.php и хотим - ждем, не занимая процессорного времени, хотим, опросили и вышли
кроме того можно использовать аналог .pid файлов и спрашивать жив ли еще скрипт posix_kill($PID,0)
 
Ещё не совсем понял работу функции file_put_contents.
Запускаю её без флага LOCK_EX:
Файл test1.php:
PHP:
<?php
$data = '
0. 11111111111111111111111111111111111111111111111111111111111111111111111111111
1. 11111111111111111111111111111111111111111111111111111111111111111111111111111
2. 11111111111111111111111111111111111111111111111111111111111111111111111111111
3. 11111111111111111111111111111111111111111111111111111111111111111111111111111
4. 11111111111111111111111111111111111111111111111111111111111111111111111111111
5. 11111111111111111111111111111111111111111111111111111111111111111111111111111
6. 11111111111111111111111111111111111111111111111111111111111111111111111111111
7. 11111111111111111111111111111111111111111111111111111111111111111111111111111
8. 11111111111111111111111111111111111111111111111111111111111111111111111111111
9. 11111111111111111111111111111111111111111111111111111111111111111111111111111
'.PHP_EOL;
for ($i = 0; $i < 400; $i++)
    file_put_contents('file', $i.$data, FILE_APPEND);
Файл test2.php тот же самый, только с другой $data.
Запускаю скрипты в браузере. В файле 'file' блоки $data чередуются, но ни разу не смешиваются. Пробовал с большими $data; под windows 7 и freebsd.
Что я делаю неверно? На сколько я понимаю, без флага блокировки должно было произойти смешивание данных. Или оно так быстро записывает данные, что не успевает смешаться?
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
А не проще использовать функции взаимоблокировок, предназначенные именно для этого?
http://www.php.net/manual/en/function.sem-acquire.php и хотим - ждем, не занимая процессорного времени, хотим, опросили и вышли
Ты на продакшене пробовал это использовать? Всё нормально работает? Мне как раз надо что-то подобное
 

clanth

Новичок
Ты на продакшене пробовал это использовать? Всё нормально работает? Мне как раз надо что-то подобное
Использую уже не один год, отлично работает, но надо быть осторожным, что бы не возникало взаимоблокировок http://msdn.microsoft.com/ru-ru/library/ms177433.aspx
Но пользовался только под линуксом, кстати могут при дебаге пригодиться команды ipcs и ipcrm
 
По поводу предыдущего вопроса. Наверное я понял свое заблуждение, функции file_put_contents делают запись в файл поочередно. Но если используется флаг блокировки, функция чтения file_get_contents уже не сможет прочитать данные.
 

DiMA

php.spb.ru
Команда форума
1. Тестировать "file_put_contents(FILE_APPEND);" в один поток - это чушь. Если уж и писать юнит тесты - то хотя бы не так криво, как сам код (смысла в кривом юнитнеста кривого кода - не много). Твой тест совершенно ничего не протестировал. Т.е. нужно тестировать код многопоточно.

2. Для безопасной работы нужно хотя бы прочитать документацию - file_put_contents($file, $person, FILE_APPEND | LOCK_EX);

3. Указанная функция не имеет ни малейшего отношения к проблеме, заданной ТС, т.е. никак не применима.
 
Сверху