<feed xmlns='http://www.w3.org/2005/Atom'>
<title>delta/ccache.git/src/test_lockfile.cpp, branch master</title>
<subtitle>github.com: ccache/ccache
</subtitle>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/'/>
<entry>
<title>feat: Improve automatic cache cleanup mechanism</title>
<updated>2023-01-17T19:25:06+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2023-01-05T18:14:27+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=defb83cc6641b7356c1426c0ba782ac735748917'/>
<id>defb83cc6641b7356c1426c0ba782ac735748917</id>
<content type='text'>
The cache cleanup mechanism has worked essentially the same ever since
ccache was initially created in 2002:

- The total number and size of all files in one of the 16 subdirectories
  (AKA level 1) are kept in the stats file in said subdirectory.
- On a cache miss, the new compilation result file is written (based on
  the first digits of the hash) to a subdirectory of one of those 16
  subdirectories, and the stats file is updated accordingly.
- Automatic cleanup is triggered if the size of the level 1 subdirectory
  becomes larger than max_size / 16.
- ccache then lists all files in the subdirectory recursively, stats
  them to check their size and mtime, sorts the file list on mtime and
  deletes the 20% oldest files.

Some problems with the approach described above:

- (A) If several concurrent ccache invocations result in a cache miss
  and write their results to the same subdirectory then all of them will
  start cleaning up the same subdirectory simultaneously, doing
  unnecessary work.
- (B) The ccache invocation that resulted in a cache miss will perform
  cleanup and then exit, which means that an arbitrary ccache process
  that happens to trigger cleanup will take a long time to finish.
- (C) Listing all files in a subdirectory of a large cache can be quite
  slow.
- (D) stat-ing all files in a subdirectory of a large cache can be quite
  slow.
- (E) Deleting many files can be quite slow.
- (F) Since a cleanup by default removes 20% of the files in a
  subdirectory, the actual cache size will (once the cache limit is
  reached) on average hover around 90% of the configured maximum size,
  which can be confusing.

This commit solves or improves on all of the listed problems:

- Before starting automatic cleanup, a global "auto cleanup" lock is
  acquired (non-blocking) so that at most one process is performing
  cleanup at a time. This solves the potential "cache cleanup stampede"
  described in (A).
- Automatic cleanup is now performed in just one of the 256 level 2
  directories. This means that a single cleanup on average will be 16
  times faster than before. This improves on (B), (C), (D) and (E) since
  the cleanup made by a single compilation will not have to access a
  large part of the cache. On the other hand, cleanups will be triggered
  16 times more often, but the cleanup duty will be more evenly spread
  out during a build.
- The total cache size is calculated and compared with the configured
  maximum size before starting automatic cleanup. This, in combination
  with performing cleanup on level 2, means that the actual cache size
  will stay very close to the maximum size instead of about 90%. This
  solves (F).

The limit_multiple configuration option has been removed since it is no
longer used.

Closes #417.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The cache cleanup mechanism has worked essentially the same ever since
ccache was initially created in 2002:

- The total number and size of all files in one of the 16 subdirectories
  (AKA level 1) are kept in the stats file in said subdirectory.
- On a cache miss, the new compilation result file is written (based on
  the first digits of the hash) to a subdirectory of one of those 16
  subdirectories, and the stats file is updated accordingly.
- Automatic cleanup is triggered if the size of the level 1 subdirectory
  becomes larger than max_size / 16.
- ccache then lists all files in the subdirectory recursively, stats
  them to check their size and mtime, sorts the file list on mtime and
  deletes the 20% oldest files.

Some problems with the approach described above:

- (A) If several concurrent ccache invocations result in a cache miss
  and write their results to the same subdirectory then all of them will
  start cleaning up the same subdirectory simultaneously, doing
  unnecessary work.
- (B) The ccache invocation that resulted in a cache miss will perform
  cleanup and then exit, which means that an arbitrary ccache process
  that happens to trigger cleanup will take a long time to finish.
- (C) Listing all files in a subdirectory of a large cache can be quite
  slow.
- (D) stat-ing all files in a subdirectory of a large cache can be quite
  slow.
- (E) Deleting many files can be quite slow.
- (F) Since a cleanup by default removes 20% of the files in a
  subdirectory, the actual cache size will (once the cache limit is
  reached) on average hover around 90% of the configured maximum size,
  which can be confusing.

This commit solves or improves on all of the listed problems:

- Before starting automatic cleanup, a global "auto cleanup" lock is
  acquired (non-blocking) so that at most one process is performing
  cleanup at a time. This solves the potential "cache cleanup stampede"
  described in (A).
- Automatic cleanup is now performed in just one of the 256 level 2
  directories. This means that a single cleanup on average will be 16
  times faster than before. This improves on (B), (C), (D) and (E) since
  the cleanup made by a single compilation will not have to access a
  large part of the cache. On the other hand, cleanups will be triggered
  16 times more often, but the cleanup duty will be more evenly spread
  out during a build.
- The total cache size is calculated and compared with the configured
  maximum size before starting automatic cleanup. This, in combination
  with performing cleanup on level 2, means that the actual cache size
  will stay very close to the maximum size instead of about 90%. This
  solves (F).

The limit_multiple configuration option has been removed since it is no
longer used.

Closes #417.
</pre>
</div>
</content>
</entry>
<entry>
<title>enhance: Delay LongLivedLockFileManager thread start to first register</title>
<updated>2023-01-15T20:33:57+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2023-01-05T10:38:55+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=35a387e15924d5982d2a812759fb476a547b619a'/>
<id>35a387e15924d5982d2a812759fb476a547b619a</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>enhance: Extract lock keep-alive thread to a manager class</title>
<updated>2022-12-13T19:38:37+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2022-12-05T19:50:58+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=b1b71d20b4ff0eebd6d0abc965d22d887203b364'/>
<id>b1b71d20b4ff0eebd6d0abc965d22d887203b364</id>
<content type='text'>
Instead of running one keep-alive thread per lock, a long-lived LockFile
now lets a separate LongLivedLockFileManager object handle keep-alive
for several locks in a single thread.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Instead of running one keep-alive thread per lock, a long-lived LockFile
now lets a separate LongLivedLockFileManager object handle keep-alive
for several locks in a single thread.
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor: Make LockFile guard itself without a LockFileGuard</title>
<updated>2022-12-13T19:36:56+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2022-11-13T08:02:16+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=c78a0825cc3a0b2216000b7a310aecf40c1d1aaa'/>
<id>c78a0825cc3a0b2216000b7a310aecf40c1d1aaa</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor: Improve formatting of test_lockfile.cpp</title>
<updated>2022-07-08T10:53:30+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2022-07-08T10:53:30+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=39269882e0d2915068e98668f65aa8eeb07ad558'/>
<id>39269882e0d2915068e98668f65aa8eeb07ad558</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>enhance: Improve lock file implementation</title>
<updated>2022-07-05T18:04:25+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2022-07-05T18:04:25+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=0babd33e84147e923a729ee07a3b85097ec8baa8'/>
<id>0babd33e84147e923a729ee07a3b85097ec8baa8</id>
<content type='text'>
This commit improves brings two improvements to the lock file
implementation:

1. Support for long-lived locks.
2. Support for non-blocking lock acquisition.

There are now two types of lock file classes: ShortLivedLockFile and
LongLivedLockFile. On Windows the implementations are identical. On
other systems, LongLivedLockFile creates a separate "alive file" whose
mtime will be updated regularly by a helper thread until the lock is
released. This makes it possible for another process to wait for the
lock indefinitely but also to know then a lock is stale and can be
broken. The ShortLivedLockFile class works like the lock file class used
to work before: it considers a lock stale after waiting for two seconds
and noticing that the symlink target has not changed during that time.
ShortLivedLockFile is to be used when the lock is expected to be held
for a very short time so that it's a waste of resources to start a
helper thread to keep the lock alive.

On some systems it would be possible to update mtime of the symlink
itself instead of a separate file, but that does not seem to be portable
enough.

Also worth mentioning is that the reason to not use proper fcntl/flock
locks on non-Windows systems is to continue supporting a cache directory
on NFS since file locks on NFS don't have a good track record.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This commit improves brings two improvements to the lock file
implementation:

1. Support for long-lived locks.
2. Support for non-blocking lock acquisition.

There are now two types of lock file classes: ShortLivedLockFile and
LongLivedLockFile. On Windows the implementations are identical. On
other systems, LongLivedLockFile creates a separate "alive file" whose
mtime will be updated regularly by a helper thread until the lock is
released. This makes it possible for another process to wait for the
lock indefinitely but also to know then a lock is stale and can be
broken. The ShortLivedLockFile class works like the lock file class used
to work before: it considers a lock stale after waiting for two seconds
and noticing that the symlink target has not changed during that time.
ShortLivedLockFile is to be used when the lock is expected to be held
for a very short time so that it's a waste of resources to start a
helper thread to keep the lock alive.

On some systems it would be possible to update mtime of the symlink
itself instead of a separate file, but that does not seem to be portable
enough.

Also worth mentioning is that the reason to not use proper fcntl/flock
locks on non-Windows systems is to continue supporting a cache directory
on NFS since file locks on NFS don't have a good track record.
</pre>
</div>
</content>
</entry>
<entry>
<title>test: Add program for manually testing the lock file implementation</title>
<updated>2022-07-04T18:58:43+00:00</updated>
<author>
<name>Joel Rosdahl</name>
<email>joel@rosdahl.net</email>
</author>
<published>2022-07-03T09:48:14+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/ccache.git/commit/?id=62df0178c0e7915a95399986d5685990ac924703'/>
<id>62df0178c0e7915a95399986d5685990ac924703</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
