file_put_contents() + flock() выдают 'out of free disk space '

HORO

Новичок
Задача запретить всем параллельно читать и писать в файл.
Ну сделал LOCK_EX перед чтением и LOCK_UN после записи.
И на windows 7 стало выдавать ошибку
Warning: file_put_contents() [function.file-put-contents]: Only 0 of 26 bytes written, possibly out of free disk space
ошибка только под виндой возникает.
Подскажите как заставить это работать под виндой...

вот так лочу
PHP:
function LockData($file,$locker=LOCK_EX){
    static $streams=array();
    $md=md5($file);

    if(empty($streams[$md])){
        $streams[$md]=fopen($file,'a+');
    }
    $i=0;
    do{
        $lock=flock($streams[$md],$locker);
    }while(!$lock && ++$i<=3);

    return $lock;
}
 

HORO

Новичок
В общем, проблема в том что вот этот код под виндой выдаст вам ошибку
PHP:
<?php
$fp=fopen("test.txt","a+");
flock($fp,LOCK_EX);
file_put_contents("test.txt","str");
решается это использованием старых добрых fseek, ftruncate, fwrite
 

fixxxer

К.О.
Партнер клуба
file_put_contents внутри делает еще один fopen, странно что у тебя это работало :)

может быть, в юникс-системах блокировки per process? интересный момент

но вообще, у file_put_contents есть третий аргумент
 

HORO

Новичок
А разве нельзя несколько раз один и тот же файл открыть?
я это вижу так, что file_put_contents должен игнорить LOCK_EX если не задан 3й параметр...
file_get_contents же нормально работает при открытом fopen c a+ в LockData...
Но 3й параметр мне не подходит, тк залочить требуется от начала чтения и до конца записи, поэтому без flock не обойтись

У меня кстати ещё все зависало, причем с полным игнором time_limit, но закономерность я не понял... вроде если помещаю file_put_contents в отдельную функцию и там пытаюсь писать в залоченный файл... flock - разве игнорит time limit?
 

fixxxer

К.О.
Партнер клуба
1) ну файл-то ты открыл ;) а вот блокировка, похоже, работает по-разному: в юниксах per process, а в винде per file handle, хотя я не уверен и не проверял, но по твоему описанию - похоже на то
2) ожидание освобождения блокировки уходит в ядро (либо в системный процесс, зависит от архитектуры ОС), ему, конечно, пофигу на пхпшные лимиты
 
  • Like
Реакции: HORO

HORO

Новичок
похоже на то, во всяком случае вот этот код
PHP:
<?php

$fp=fopen("test.txt","a+");
flock($fp,LOCK_EX);

$fp2=fopen("test.txt","w+");
fwrite($fp2,"text");
под виндой ниче не выдал и не записал, а под линукс нормально в файл записал text
 

AnrDaemon

Продвинутый новичок
Твой код неверен и работать не должен.
Ты либо fopen/flock/fwrite, либо file_put_contents. Но не всё сразу.
А то попытки почистить ружжо и подстрелить зайцца одновременно выглядят… смешно.
 

HORO

Новичок
А чеж ты раньше не написал что "в винде per file handle" ? :D
если б я знал, я тоже сразу все на fopen переписал, а так мне только лок нужен был, то что работало я разумеется не трогал.
А то попытки почистить ружжо и подстрелить зайцца одновременно выглядят… смешно.
на винде? )))
 

HORO

Новичок
почитай топик )
не это надо и проблема не в этом, а в том о чем fixxxer написал...
и лок надо не на время зависи, а от начала чтения и до конца записи, т.е. 3й аргумент put contents не подходит
в общем вот что вышло
PHP:
function LockData($file,$locker=LOCK_EX){
    static $streams=array();

    $md=md5(str_replace($_SERVER['DOCUMENT_ROOT']."/","",$file));
    $is_nb=($locker & LOCK_NB)==LOCK_NB;

    if(empty($streams[$md])){
        $streams[$md][0]=fopen($file,'a+');
    }else if($locker==$streams[$md][1]){
        return $streams[$md][0];
    }

    $i=0;
    do{
        $lock=flock($streams[$md][0],$locker);
    }while(!$lock && ++$i<=3 && !$is_nb);

    if($lock) $streams[$md][1]=$locker;
    else $streams[$md][1]=0;

    if($lock && ($locker & LOCK_UN)==LOCK_UN){
        fclose($streams[$md][0]);
        unset($streams[$md]);
        return null;
    }

    return $lock?$streams[$md][0]:false;
}

function ReadData($file,$lock=false){
    if(is_file($file)){

        $fp=LockData($file,$lock?LOCK_EX:LOCK_SH);
        if(is_resource($fp)){
            fseek($fp,0);
            $size=filesize($file);
            if($size>0){
                $data=fread($fp,$size);
            }
            if(!$lock) LockData($file,LOCK_UN);
        }

        if(!empty($data)){
            return unserialize($data);
        }
    }
    return false;
}

function WriteData($file,$data){
    $fp=LockData($file);
    ftruncate($fp,0);
    fseek($fp,0);
    fwrite($fp,serialize($data));
    fflush($fp);
    LockData($file,LOCK_UN);
    clearstatcache();

}


кстати ещё инетерсная особенность обнаружилась, если подряд делать 2 раза flock(LOCK_EX) (в ReadData() и WriteData()) то блокировка слетает в момент второго лока...для этого пришлось "else if($locker==$streams[$md][1])"

а на линуксе можно )
 
Последнее редактирование:
Сверху