вторник, октября 12, 2010

Блокировка файла в php

Решил помочь Тормозу в его нелёгком деле задача заключается в следующем, нужно залочить файл на время выполнения и чтобы конкурентные процессы никак не сказались на работе скрипта, т.е. либо у нас есть доступ и мы изменяем файл или читаем, иначе ничего не делаем.
Предложено было масса вариантов, но так проблему Тормоз не решил.

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

Вообщем код:


function custom_flock($fname){
    /* возвращает имя ссылки в случае удачи, иначе false */
    $result = false;
    $lock_fname = '.lock.' . $fname;

    if (touch($lock_fname)) {

        $link_fname = $lock_fname . rand() . '.link';
        if (link($lock_fname, $link_fname)) {
            
            $result = $link_fname;
            
            $fp = fopen($lock_fname, 'r');
            $fstat = fstat($fp);
            if ($fstat['nlink'] != 2) {
                $result = false;
                unlink($link_fname);
            }
            fclose($fp);
        }
    }
    return $result;
}


И тест счетчика:


/* простой счетчик */

require_once 'custom_flock.php';

$fname = 'counter.txt';
$link = custom_flock($fname); // делаем блокировку файла
if ($link){ // удачно заблокировали
    $value = file_get_contents($fname);
    print 'value: ' . $value . "\n";
    file_put_contents($fname, 1 + $value);
    unlink($link); // не забываем удалять ссылку
}



Думаю этот вариант вполне рабочий.
скачать код

2 комментария:

Анонимный комментирует...

Спасибо, но "думаю" не прокатит, тестировать надо. А если учитывать, что просто взять и заменить мои функции твоими не получится, то лучше буду своё решение испытывать, у меня тоже мысли появились, как лучше делать.

И я тоже сдался, на 100% не уверен в причине сбоев. Однако, скорей всего верно твоё предположение о том, что файл подключается недописанным.

Jungle комментирует...

надо пробовать и моё и твоё решение, какое-нибудь из них должно сработать. да и просто нужно решить эту проблему.