Mike -- No longer here
Mike -- No longer here

Reputation: 2092

stream_set_write_buffer or file locking in PHP?

I'm trying to make a caching system where a large chunk of data (between 8 KB and 200 KB) can be written as fast as possible.

Currently I'm applying file locking functions using the code similar to below:

$file_handle=fopen($file_name,"w");
flock($file_handle,LOCK_EX);
fwrite($file_handle,$all_data);
flock($file_handle,LOCK_UN);
fclose($file_handle);

Is this the most optimal way speed wise to allow only one process at a time to write to the file if many are running the same script at once, or should I also include stream_set_write_buffer($file_handle,0); or should I ditch file locking?

Upvotes: 4

Views: 694

Answers (1)

clover
clover

Reputation: 5170

In short:

file_put_contents($file_name, $all_data, LOCK_EX);

Long story: There is one problem with your code: "w" mode is truncating a file before the lock is acquired. If two separate processes truncated a file, than one writes 200Kb, than another writes 8Kb, you will have 192Kb of garbage left in your file. I would recommend to open a file in "c" mode and truncate it in the end, after all data is written:

$file_handle = fopen($file_name, 'c');
stream_set_write_buffer($file_handle, 0); // try to disable write buffering
flock($file_handle, LOCK_EX);
fwrite($file_handle, $all_data); // write to possibly pre-allocated space
ftruncate($file_handle, strlen($all_data)); // remove gabage left from previous write
fflush($file_handle); // flush write buffers if enabled
flock($file_handle, LOCK_UN);
fclose($file_handle);

'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer is positioned on the beginning of the file. This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested).

You need to make sure that write buffer is flushed before releasing the lock by either calling fflush() or disabling write buffering. Since stream_set_write_buffer(); may fail, it's better to have fflush() anyway. Also note that write buffering is designed to improve performance of sequential writes. Since you're performing only one write operation, write buffer can slightly decrease performance, so, it's better to try to disable it first.

Upvotes: 1

Related Questions