Compare-and-Swap over POSIX-compliant filesystem objects
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
There is no standard POSIX system call that gives you a true memory-style compare-and-swap operation over arbitrary filesystem objects. What POSIX does give you are a few atomic building blocks, especially rename, link, mkdir, and open with exclusive-creation semantics, and you combine those to approximate optimistic concurrency or atomic replacement.
Why Filesystem CAS Is Harder Than Memory CAS
In memory, compare-and-swap means "replace value X with value Y only if the current value is still X." That is a single primitive operating on one memory location.
Filesystems are different:
- file contents may be large, not one machine word
- metadata and data may change independently
- POSIX atomicity guarantees are narrower than people assume
- many operations are atomic only for names, not for full content validation
So the honest answer is that POSIX filesystems do not expose a general-purpose CAS primitive over file contents.
What POSIX Does Guarantee Well: Atomic Rename
The strongest common building block is atomic replacement through rename. If you write new data to a temporary file and then rename it over the old path on the same filesystem, other processes see either the old file or the new file, not a half-written mixture.
This gives atomic replace, which is often what people actually need. But notice the missing part: there is no built-in compare step that checks whether current.txt still has an expected version before the replace happens.
Simulating CAS with Versioned Names
A common pattern is to store immutable versions under unique names and then atomically switch a pointer-like filename.
For example:
- read the current version marker
- write a new file with a new version name
- atomically rename a reference file or symlink to point at the new version
- fail if the expected old version is no longer current
This is not a single POSIX CAS instruction, but it approximates optimistic concurrency if you keep version information separate from the payload.
Exclusive Creation as a Coordination Primitive
Another useful tool is open with O_CREAT | O_EXCL, which creates a file only if it does not already exist.
This is useful for leader election, one-writer claims, and coarse-grained optimistic coordination. It is not full compare-and-swap over file content, but it is a standard atomic filesystem primitive that solves many practical races.
Directory Creation as an Atomic Claim
mkdir is also commonly used as an atomic claim mechanism because creating a directory either succeeds or fails if the path already exists.
This works well in shell scripts and simple operational tooling. Again, it is not a byte-level CAS. It is a name-based atomic ownership pattern.
What You Cannot Rely On
You should not assume that reading a file, comparing its content in user space, and then writing back a replacement is atomic. Another process can always change the file between your read and write unless you add coordination.
So the naive pattern:
- read file
- compare expected content
- write file if unchanged
is not safe by itself under concurrency.
To make it safe, you usually need one of:
- a lock file or directory lock
- atomic rename around versioned content
- advisory locking such as
fcntl - a higher-level database or coordination service
Common Pitfalls
- Assuming POSIX provides a built-in compare-and-swap syscall for file contents.
- Treating atomic
renameas though it also performs a compare step. - Reading and rewriting a file optimistically without any locking or version check.
- Forgetting that
renameatomicity depends on staying within the same filesystem. - Expecting name-level atomicity to solve every content-level concurrency problem.
Summary
- POSIX does not provide a general CAS primitive over filesystem objects.
- Atomic
renameis the main tool for safe replace operations. - '
open(..., O_CREAT | O_EXCL)andmkdirare useful atomic claim primitives.' - To approximate CAS, combine versioning, locks, and atomic name updates.
- If you need stronger compare-and-update guarantees, a database or coordination service is often the better abstraction.

