- на файл (file) создается замок/файл на запись (wlock) и замок на чтение (rlock);
- пред чтением создается жесткая ссылка (rlink) на замок rlock и проверяется количество ссылок на замок wlock == 1, т.е. проверяем на запись, если всё удачно, то читаем файл и в конце удаляем rlink;
- перед записью создаем wlink на wlock и считаем количество ссылок wlock == 2 и rlock == 1, т.е. проверяем нет ли записывающих и читающих, если всё успешно, то записываем в файл, а затем удаляем wlink;
Думаю понятен принцип.
сам код:
function get_link_count($fname){
$fp = fopen($fname, 'r');
if ($fp) {
$stat = fstat($fp);
fclose($fp);
return $stat['nlink'];
}
return false;
}
function custom_flock($fname, $mode = 'r'){
/* возвращает имя ссылки в случае удачи, иначе false
@$fname имя файла
@$mode режим блокировки
r - на чтение
или
w - на запись
если режим чтения, то смотрим не заблокирован ли файл на запись
если режим записи, то смотрим не заблокирован ли файл на запись или чтение
*/
$rlock = '.lock.' . $fname . '.read';
$wlock = '.lock.' . $fname . '.write';
clearstatcache();
if (file_exists($fname) and touch($rlock) and touch($wlock)) {
if ('w' == $mode){
$link = $wlock . rand() . '.link';
if (link($wlock, $link)){
if(get_link_count($wlock) == 2 and get_link_count($rlock) == 1){
return $link;
} else {
unlink($link);
}
} else {
unlink($link);
}
} else {
$link = $rlock . rand() . '.link';
if (link($rlock, $link)){
if (get_link_count($wlock) == 1){
return $link;
} else {
unlink($link);
}
} else {
unlink($link);
}
}
}
return false;
}
Данная схема не гарантирует целостности файла при падении скрипта, для этого нужно делать журнал для откатки на последнюю версию. Так же нужно автоматически удалять старые ссылки в случае падения скрипта.
код можно скачать здесь
в архиве доступны тесты которые я опробовал на тесте ab в результате тестов целостность файла была сохранена, там 2 теста test_counter.php и test_chain.php. test_chain.php как раз таки и подтверждает целостность файла.
Тест заключается в следующем последовательно пишем в файл 1 или 0 если был последний 0, то запишем 1 и наоборот в конце теста проверяем правильность последовательности 0 и 1 если последовательность правильная, то целостность файла сохраняется.
19 комментариев:
Как-то сложновато, много, на первый взгляд, лишних операций. Ссылки, подсчёт ссылок.
Я пока архив не скачивал. Скажи параметры тестирования ab, и сколько циклов прогонял?
вот так гонял ab -kc 100 -t 30 http://localhost/jungle/custom_flock/test_chain.php
потом так ab -n 500 -c 100 http://localhost/jungle/custom_flock/test_chain.php
операций нет так уж и много, зато целостность сохраняется
скачай архив, попробуй погонять тесты.
У тебя значения конкурентности слишком большие. Я вчера тоже игрался, и понял, что нецелесообразно ставить его значение более 3-10, потому что тогда вообще эффект не наблюдается. Он захлёбывается, что ли :)
Я гоняю на конкурентности 3.
Сбои у моих старых функций наблюдались, если прогнать 1000 циклов ab с 50 запросами каждый и конкурентностью 3 (ab -n 50 -c 3). При таких условиях получалось примерно 20 сбросов.
Я сейчас допишу свою функцию, поставлю на такой прогон и спать. А потом проснусь, поработаю ещё, и, если поеду в лес, запущу твой тест. Хотя, честно говоря, страшно компьютер в пустой квартире оставлять под таким стрессовым тестом, так что может до следующей ночи тогда.
В любом случае спасибо! Не оставил меня в беде :)
да не за что, самому интересно стало, вот и решил помочь, надеюсь что выход будет найден :)
провел тест ещё без блокировки файла, который подтвердил, что мой метод работает ;)
так что бери на вооружение, не ломай себе голову, двигай другие проекты, а то будет дедлайн :)
В смысле "без блокировки". Поясни, пожалуйста.
да просто тест без всяких блокировок файла, что бы сравнить 2 результата метод с блокировкой VS без блокировки
И что, хочешь сказать без блокировок сбросов не было? Трудно поверить. Как точно ты проверял? Какой алгоритм?
наоборот без блокировок были сбросы, т.е. последовательность 0 и 1 была не правильной, а с блокировкой последовательность была правильной.
Кстати, опытным путём выяснил, что задержка в 5000 микросекунд - это очень много, слишком. Пока в локалке у меня оптимальные результаты при 500 мс, но я думаю, их надо подбирать под сервер и нагрузку. Возможно, в Daos 2.0 это будет отдельно настраиваться в группе тонких настроек, ну или вообще автоматически подбираться параметры.
ну вот видишь твой метод с задержками, а мой без :)
Это как это без? В функциях, которые ты сделал под Daos задержки остались.
нет я имею ввиду не твой модифицированный код, а так да для статистики нужны задержки тогда
Минут через 15-20 запускаю тестирование с твоими версиями функций (задержки только уменьшил до такого же значения, как у меня сейчас) и спать :) Утром отпишусь.
Не, всё же не стал запускать. Сейчас голова совсем не варит, но просматривая твой код наткнулся на какую-то странную конструкцию.
Что за do? Странный цикл. Разве в PHP допустимы такие конструкции? Я знаю while. И если допустимы, то при каких условиях из этого цикла выход?
Ну вот, а второй комментарий потерялся?f
хм, не знаю, только этот был
ну как там дела?
нашел комментарий :), blogger глючит :)
да есть такой оператор do
он как while, только условие проверяется в конце цикла.
Я уже понял :) Тест запущу на эту ночь теперь, прошлым утром тестировал вариант с сессиями. Он, кстати, очень неплохо себя показал.
Отправить комментарий