Doc #61168 [Com]: fwrite() has no buffering
| From: | tstarling@php.net | Date: | Mon, 22 Apr 2013 01:02:52 +0000 |
| Subject: | Doc #61168 [Com]: fwrite() has no buffering | ||
| References: | 1 | Groups: | php.doc.bugs |
| Request: | Send a blank email to doc-bugs+get-9754@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=61168&edit=1
ID: 61168
Comment by: tstarling@php.net
Reported by: tstarling@php.net
Summary: fwrite() has no buffering
Status: Open
Type: Documentation Problem
Package: Streams related
Operating System: Linux
PHP Version: 5.4.0RC8
Block user comment: N
Private report: N
New Comment:
Still not even a documentation change? It's been more than a year, and I can't imagine it
being particularly complex to edit a single sentence in the manual.
Previous Comments:
------------------------------------------------------------------------
[2012-02-23 14:49:03] cataphract@php.net
Perhaps this change in plain_wrapper.c would be a good idea:
@@ -583,7 +583,13 @@
case PHP_STREAM_OPTION_WRITE_BUFFER:
if (data->file == NULL) {
- return -1;
+ char fixed_mode[5];
+ php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
+ data->file = fdopen(data->fd, fixed_mode);
+ if (data->file == NULL) {
+ return -1;
+ }
+ data->fd = -1;
}
if (ptrparam)
I'll have to think a bit more about the implications.
------------------------------------------------------------------------
[2012-02-23 10:32:05] cataphract@php.net
You're not checking the return value of stream_set_write_buffer. If you were, you'd have
noticed it returns -1 indicating failure.
PHP does not have buffering for writes as it does for reads. In fact, it has the opposite: it breaks
the data to write in chunk_size bits (see the undocumented stream_set_chunk_size in PHP 5.4).
Therefore, streams that want to provide write buffering must do so themselves; PHP merely provides a
way to configure the write buffering. In the case of plain files, write buffering is supported, but
only for stdio files, not plain file descriptors. The stream by default doesn't use stdio (to
avoid duplication of read buffers for instance).
Extensions can open a FILE* and pass it to php_stream_fopen_from_file(), but it seems that this
won't suffice because PHP will still use low-level I/O on the file descriptor returned by
fileno(), so you'd have to violate some abstractions and zero the fd field in the
php_stdio_stream_data structure (stored in stream->abstract) to force stdio to be used. This
should be revisited.
In any case, the documentation is wrong. I'm changing this to a documentation problem for the
time being.
------------------------------------------------------------------------
[2012-02-23 06:16:09] tstarling@php.net
Description:
------------
The stream_set_write_buffer() manual entry indicates that fwrite() buffers its output. This is
incorrect. For regular files, no buffering is ever done, each fwrite() call leads to a syscall.
This is a performance issue, especially for extensions like the CDB handler in DBA. I have a
real-world script that uses almost as much system CPU as user CPU, because each dba_insert() call
leads to multiple syscalls.
Test script:
---------------
$f = fopen( '/tmp/blah', 'w' );
stream_set_write_buffer( $f, 8192 );
for ( $i = 0; $i < 10; $i++ ) {
fwrite( $f, 'x' );
}
fclose( $f );
Expected result:
----------------
strace php write-tight-loop.php
...
write(3, "xxxxxxxxxx", 1) = 10
...
Actual result:
--------------
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
write(3, "x", 1) = 1
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61168&edit=1