WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




Блокировка одновременной записи в файл без использования функции flock


Прислал: Андрей Черный [ 01.03.2004 @ 11:07 ]
Раздел:: [ Статьи по Perl ]


При работе CGI-скриптов, осуществляющих запись в файлы (а это большинство их видов - счетчики. гостевые книги, форумы и т.п.) возможна ситуация, когда два или более одновременно запущенных "экземпляра" скрипта попытаются одновременно записывать свои данные в файл.

Как минимум, это чревато потерей результатов работы одного из экземпляров скрипта, а как максимум - нарушением структуры файла данных и невозможностью нормальной работы скрипта до вмешательства админа.

Поэтому в CGI-скриптах принимают специальные меры по блокировке одновременного использования файлов данных несколькими скриптами одновременно. В языке Perl, как и во многих языках программирования, есть специальная функция "блокировки" файла flock.

Однако на практике эта функция не работает в портах Perl под Windows 9x. Соответственно, скрипты, использующие эту функцию, на мой взгляд, не могут считаться кросс-платформенными. Это также затрудняет отладку скриптов на машине под Windows перед перносом их на UNIX-хостинг.

Тем не менее, защиту файлов от одновременного использования можно организовать и "своим путем", и это будет работать на всех системах.

Предлагаемый здесь метод основан на использовании временного файла с заранее известным именем.

Суть метода простая - перед тем, как "занять" файл данных, скрипт создает этот временный файл, а после освобождения - удаляет. Таким образом, наличие этого временного файла означает, что файл данных занят. Другой экземпляр скрипта перед записью проверяет наличие временного файла и, если он есть, дожидается его удаления первым экземпляром, и только затем начинает работу с файлом данных.

Имя для временного файла может быть любым - главное, чтобы для блокировки разных файлов данных разными скриптами использовались разные имена.

Фрагмент Perl-кода, реализующий такую защиту, может быть таким:


$lockfile="data.tmp"; #Имя временного файла блокировки
$count=50; $interval=0.05; #Кол-во попыток и интервал между ними

if (-e $lockfile)
{
#Если временный файл есть, ждем его удаления другим процессом

while (($count>0)&&(-e $lockfile))
{
sleep $interval;
$count-=1;
};
};

if ($count==0){
#Здесь размещается код обработки непредвиденной ошибки
};
open TF,">$lockfile"; #Создаем временный файл
close TF;

#...
#Здесь размещается собственно код работы с файлом данных
#...

unlink $lockfile; #Удаляем временный файл

Этот участок скрипта проверяет, существует ли временный файл. Если он существует, то производится ($count) проверок его существования через интервалы ($interval) секунд (значения 50 и 0.05 можно заменить своими; предполагается, что время ($count*$interval) более чем достаточное, чтобы другой процесс завершил работу с файлом данных). Как только временный файл будет удален другим процессом, произойдет выход из цикла; далее скрипт создает свой временный файл, осущетсвляет работу с файлом данных и удаляет временный файл.

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

Во многих случаях имеет смысл "блокировать" файл данных не только во время записи в него, а во время всего цикла "чтение-модификация-запись". В противном случае очень возможна потеря результатов работы одного из "экземпляров" скрипта.

На мой взгляд, этот подход не менее надежный, чем "стандартный Perl-овский", но зато нормально работающий и под Win9x, и под UNIX-подобными системами. При разработке своих CGI-скриптов я предпочитаю этот метод. В частности, в моем "Скрипте для ведения логов и учета посещений" описанным выше образом блокируется одновременное использование трех используемых скриптом файлов данных, и в процессе многолетнего использования мной этого CGI-скрипта никаких эксцессов, связанных конкретно с этим, не было.

Автор: Андрей Черный
//angel07.webservis.ru
программирование CGI-скриптов на Perl;
авторская коллекция скриптов;
статьи о хостинге;
интернет-пользователю.


 :::::  Sergey пишет 09.03.2004 @ 17:44 
Да в общем-то ничего нового не сказано. Такой метод применен по-моему в Ultimate Bulletin Board http://www.ultimatebb.com и на каких-то еще форумах. Это во-первых. А во-вторых, с таким же успехом можно использовать модуль с CPAN FileLock или lockfile. Там проблема имен временных файлов решается автоматически.
 :::::  NeoNox пишет 11.03.2004 @ 13:12 
Неверная и вредная статья.
Запомните навсегда: НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ПРОВЕРКУ СУЩЕСТВОВАНИЯ ФАЙЛА "if (-e $lockfile)" ПОТОМУ КАК НАРВЕТЕСЬ НА СИТУАЦИЮ ГОНКУ ПРОЦЕССОВ.
Переведи http://secu.zzu.edu.cn/book/Perl/Perl%20Bookshelf%20%5B3rd%20Ed%5D/cookbook/ch07_12.htm и будет тебе щастье.
 :::::  Andrey Chorny пишет 12.03.2004 @ 09:05 
А что такое "гонка процессов" и чем она чревата?

Чем плохо выражение if (-e $lockfile) {}; ?
Как же тогда лучше проверять наличие файла?
Попытаться его открыть?
 :::::  NeoNox пишет 12.03.2004 @ 11:02 
Андрей, ты всеже сходи по линке которую я дал.
Гонки происходят между проверкой существования файла с данным именем и операцией которую вы собираетесь с ним произвести. Вы знаете что такое атомарная операция? Если да, то проверка на существование файла ею не является.
 :::::  Андрей Черный пишет 17.03.2004 @ 13:49 
По линку сходил (кстати, спасибо за линк - в этой книге кроме блокировки файлов еще много чего интересного :-) )

Согласен с Вами - описанный метод не обеспечивает 100% защиты, а зищищает только в "1-м приближении", т.к. между проверкой временного файла на существование и работой с файлом данных всегда есть промежуток времени, за который этот самый временный файл может как нельзя некстати появиться :-)

Кстати, я несколько лет назад видел где-то статью на эту же тему, так там автор вообще очень категорично утверждает, что блокировка временными файлами - это круто, а flock - отстой даже под UNIX, и предлагал какую-то библиотеку, работа которой основана на тех же временных файлах (причем человек этот вроде как разбирающийся, судя по другим его статьям). Прочитав ее, я решил в своих скриптах применять этот принцип. Использовать чей-то код не хотелось по соображениям (c), поэтому "с идеи" написал свой (описанный в этой статье). Три года успешно (срывы были 1 раз за три года) использую его в одном скрипте на своем сайте, который запускается при каждой загрузке каждой страницы. Наверное, у меня не было с этим проблем, т.к. не было сильной загрузки скриптов, или ну просто повезло :-)

NeoNox-у отдельный thanks.
 :::::  CGVictor пишет 11.11.2004 @ 19:50 
А что народ думает о методе Спектатора (spectator.ru, "Как мы побороли flock")? Там, правда, реализация на ПХП, но суть не меняется... Он говорит, у него без проблем работает, да и у меня самого неплохо...
 :::::  Green Kakadu пишет 18.11.2004 @ 16:53 
#народ думает о методе Спектатора (spectator.ru, "Как мы побороли flock")?
тоже неидеальный вариант.
Типа все считывается, изменяется, пишется в уникальный временный файл, а потом rename(tem-file,file);
Пока кто-то что-то калякает в свой временный файл, другой дятел может делать тоже самое, но уже в свой :) вопрос в том кто из них последним сделает rename, тот и победил
 :::::  Андрей Черный пишет 22.11.2004 @ 16:26 
А что Вы скажете насчет такого метода:

- проверить отсутстве
- создать временный файл
- прочитать файл данных
- выждать n-е время
- ЗАНОВО считать файл данных
- сравнить данные, считанные в 1-й и 2-й раз
- если не изменились - записываем файл данных и удаляем временный файл.

Время (доли секунды) рассчитываем таким образом, чтобы второй экземпляр скрипта, если он "перепрыгнет" временный файл, созданный первым скриптом, уже заведомо внес изменения.

 :::::  Андрей Черный пишет 22.11.2004 @ 16:30 
Первым пунктом я хотел сказать "проверить отсутствие временного файла" :-)
Прошу прощения :-)
 :::::  Alor пишет 06.12.2004 @ 12:34 
Можно предложить другой вариант - сделать обращение к внешнему скрипту, который поставит данный процесс в очередь и ждет разрешения на работу. Принцип такой:
- скрипт обращается к внешнему скрипту и получает идентификатор, при
этом внешний скрипт ставит процесс в очередь
- с этим идентификатором скрипт обращается к внешнему за разрешением
- когда добро дано и работа окончена скрипт посылает информацию внешнему
о завершении работы и внешний скрипт удаляет процесс из очереди и дает добро
следующему в очереди процессу

Таким образом процессам не надо "побеждать", а приоритет имеет тот, который раньше пришел.
 :::::  Zed пишет 12.01.2005 @ 01:57 
народ с придложеным методом может еще возникнуть следующая проблема по каким либо причинам процес будет убит до того как удалит файл и все остольные процесы просто полетят...

а вот предпоследний вариант тоже прикольно а что если другой процес сразу после того как текущий считает файл второй раз изменит его тогда опять же возникнит таже проблема...

P.S.
у меня почемуто пока не открывается страница придложеная NeoNox-ом возможно там и что то изменит мое мнение но пока я за flock это всетоки посикс.. так что лучше его и предерживатся..
 :::::   пишет 12.01.2005 @ 01:59 
кстате тут могут помочь симофоры но почемуто они не дохнут по окончанию процесса... это тупа... а вот flock дохнет если процесс слетел..
 :::::  Phoinix пишет 17.01.2005 @ 16:58 
[цитата]
Однако на практике эта функция не работает в портах Perl под Windows 9x. Соответственно, скрипты, использующие эту функцию, на мой взгляд, не могут считаться кросс-платформенными. Это также затрудняет отладку скриптов на машине под Windows перед перносом их на UNIX-хостинг.[/цитата]

Если это было основным "побудителем" к данному решению, то это IMHO глупо:
1. Кроссплатформенность не при чем, сервера под Win9x - я встречал за редким исключением и буквально не долго;
2. Win2K и выше - прекрасно поддерживает flock, кроссплатформенность соблюдается;
3. Хорошо, отладка производится под Win9x, обычно это домашний компьютер (у нас на работе везде стоит Win2k), но как ты на домашнем компьтере сможешь эмулировать одновременно десятки процессов что бы проверить flock??? у меня не получалось никогда... не успевал просто...
 :::::  Zed пишет 18.01.2005 @ 01:26 
да да Все весело юзаем flock и спим спокойно!!!
 :::::  laeda пишет 09.10.2006 @ 13:39 
И что если в
> #Здесь размещается собственно код работы с файлом данных
скрипт упадет => файл не удалиться, а это будет печально...
 :::::  Tony Darko пишет 24.12.2006 @ 16:01 
вот-вот.. лучше бы дескриптор привязать (perldoc tie). тогда мона описать ф-ю DESTROY и при слёте всё равно в ней удалять временный файл. да и по закрытию мона там же прописать удаление..
Имя:
Email:
URL

Введите сумму двух чисел девять и шесть (девять+шесть=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0279880