Calling ftell() after a write() call causes glibc to flush the buffer. This results in performance degradations for certain of our user applications where we depend on knowing where the file-pointer while doing small record writes. Below is a sample code which demonstrates the issues that we are seeing testwrite.c #include <stdlib.h> #define MEGABYTE 1048576 int main(int argc, char *argv[]) { int ret; char filename[512]; char *data; int dsize, size, chunksize, count; FILE *myfile; int ftell_on = 0; chunksize = 208; //=============================================================== // Process arguments // <output_file> // <write_size> // <0/1> //=============================================================== char *usage_str = "Usage arguments : <output_file> <file_size> <0/1> \n"; if (argc < 3) { printf ("Invalid arguments : \n"); printf ("\t %s \n", usage_str); return 1; } sscanf(argv[1],"%s",filename); sscanf(argv[2],"%d",&dsize); sscanf(argv[3],"%d",&ftell_on); dsize *= MEGABYTE; data=malloc(sizeof(char) * dsize); if(!data) { perror("malloc() failed"); abort; } myfile = fopen(filename,"w"); if(myfile == NULL) { perror("fopen failed()"); abort; } for(count=0; count<dsize; count+=chunksize) { if(count+chunksize <= dsize) { size = chunksize; } else { size = dsize-count; } ret = fwrite(data,size,1,myfile); if(ret != 1) { perror("Write failed\n"); abort(); } if (ftell_on == 1) { int pos; pos = ftell(myfile); if (pos < 0) { perror("ftell() failed"); abort(); } } } ret = fclose(myfile); } gcc -o testwrite.exe testwrite.c 1. Run code with ftell on strace ./testwrite.exe file 1 1 write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 208) = 208 write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 208) = 208 2. Run code with ftell off strace ./testwrite.exe file 1 0 write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 32768) = 32768 write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 32768) = 32768
Per the comments in libio/fileops.c (_IO_new_file_seekoff): /* Flush unwritten characters. (This may do an unneeded write if we seek within the buffer. But to be able to switch to reading, we would need to set egptr to ptr. That can't be done in the current design, which assumes file_ptr() is eGptr. Anyway, since we probably end up flushing when we close(), it doesn't make much difference.) FIXME: simulate mem-papped files. */ Ulrich, any ideas for a design addressing the FIXME suggestion?
Hello, is anything new wrt. this bug? I have just ran into it on my RHEL and Fedora systems.
Is this bug still unaddressed? I don't see how _IO_new_file_seekoff should even come into it, since the operation is ftell, not fseek; if this function is being called for ftell, that seems to be the whole problem...
I have posted a patch for this: http://sourceware.org/ml/libc-alpha/2012-09/msg00198.html for those who want to try this out.
Fixed in master: http://sourceware.org/git/?p=glibc.git;a=commit;h=adb26faefe47b7d34c941cbfc193ca7a5fde8e3f
forgot to close the bug.
Fixes here appear to have caused https://sourceware.org/bugzilla/show_bug.cgi?id=16532