skip to Main Content

I’d like to know if fstat() is cached.

Documentation says nothing about it.

(PHP 8.1.12)

EDIT:

I made a LOT of tests, I have now an accurate answer for that.

Introduction:

I created two scripts and ran them both simultaneously (locking the file pointer with an exclusive lock (flock($fp, LOCK_EX))* to prevent them from overwriting each other) and on their own; I printed print_r(fstat($fp)) at various stages of a loop that led to writing 5 MB of data. I also used var_dump(realpath_cache_get())

Returns an array of realpath cache entries. The keys are original path entries, and the values are arrays of data items, containing the resolved path, expiration date, and other options kept in the cache.

to detect the realpath cache and ran tests trying to clear and not clear the cache via clearstatcache().

What happened:

I found that the only item that gets cached is ‘atime’

time of last access (Unix timestamp)

, but most upsetting of all: it is not put in the realpath cache, consequently nothing will change if you clear it via clearstatcache(), you can only restart the machine or wait for the cache timeout to clear the data (depending on the machine).

Fortunately this doesn’t affect me since I only need ‘size’ element of fstat. Sadly I cannot give you the source code cause I changed it a lot of time to try all possibilities.

Thank you to everyone who spent time to help me.

*NOTE: Use flock in both files, if you use it only in one the other file will be able to write in the not locked file that has been ran before

CONCLUSION

The only cached element of fstat is atime, but it is not cached in the realpath, so clearstatcache() is useless

2

Answers


  1. I made a quick demo that appears to show that it is not cached. However, see the edit, too

    $filename = __DIR__.'/test.txt';
    
    @unlink($filename);
    touch($filename);
    echo 'STAT - Size before write: '.stat($filename)['size'], PHP_EOL;
    file_put_contents($filename, 'test');
    echo 'STAT - Size after write: '.stat($filename)['size'], PHP_EOL;
    clearstatcache();
    echo 'STAT - Size after cache clear: '.stat($filename)['size'], PHP_EOL;
    
    @unlink($filename);
    touch($filename);
    $fp = fopen($filename, 'wb');
    echo 'FSTAT - Size before write: '.fstat($fp)['size'], PHP_EOL;
    fwrite($fp, 'test');
    echo 'FSTAT - Size after write: '.fstat($fp)['size'], PHP_EOL;
    clearstatcache();
    echo 'FSTAT - Size after cache clear: '.fstat($fp)['size'], PHP_EOL;
    

    Output:

    STAT - Size before write: 0
    STAT - Size after write: 0
    STAT - Size after cache clear: 4
    FSTAT - Size before write: 0
    FSTAT - Size after write: 4
    FSTAT - Size after cache clear: 4
    

    Edit

    Per @Barmar, I ran the test again, this time with just an fstat call followed by a sleep(10), then I quickly updated the file with vim manually, and then one final fstat call (all in the same request), and that one came back as cached.

    I then ran that again, this time with clearstatcache() before the final fstat, and it did not change. I also tried the tests with both w and r modes for fopen, same results.

    So there does appear to be a cache of some sort, but I don’t think it is the stat cache.

    Login or Signup to reply.
  2. As a supplement:

    I also did exactly such a test as Chris Haas describes in the comment.

    /*
     * Open test.txt with a text editor
     * Run this script
     * Add some characters in the editor and save while the script is running
     */
    $file = __DIR__.'/../test/test.txt';
    $fp = fopen($file,'r');
    $size[] = fstat($fp)['size'];
    sleep(10);
    $size[] = fstat($fp)['size'];
    var_dump($size);
    //array(2) { [0]=> int(3) [1]=> int(13) }
    

    Same results for PHP on Win10 and a small Linux.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search