Layout change in releases after 0.6.0. When the data directory is derived
from a root, PG_EMBED_ROOT or the per-user default, each cluster gets a data
directory of its own under the root. This lets concurrent processes, such as
cargo nextest running one process per test, each bootstrap a working cluster
in one root. Up to 0.6.0 they shared one directory, and every process but the
first failed with pg_ctl: another server might be running.
| 0.6.0 and earlier | Later releases | |
|---|---|---|
| Data directory | <root>/data |
<root>/data/<name>/ |
| Password file | <root>/install/.pgpass |
<root>/data/<name>.pgpass |
| Liveness lock | none | <root>/data/<name>.lock |
Table: Data layout under a derived root.
<name> is <pid>-<nanoseconds>-<counter>, unique to each cluster. The
install tree, <root>/install, is still shared. A cluster left directly in
<root>/data by an earlier release is no longer used, and the bootstrap logs a
warning naming it; it can be deleted.
- Explicit
PG_DATA_DIRis unchanged. Setting it keeps a single data directory at that path, with its password file in the install tree, and skips everything below. - Clean-up. Each process holds a kernel lock on its cluster's
.lockfile until it exits. The next bootstrap in the root removes every cluster whose lock it can take, which are those whose process has gone, however it ended. A reused process ID cannot fool this, because the held lock decides, not the ID. A cluster whose data directory is removed while its process lives, for example byTestCluster's drop, leaves its.lockand.pgpassfiles until the process exits. - Orphaned servers. If a test process dies abruptly, its
postgresserver can outlive it. Before removing a dead cluster's directory, the bootstrap reads itspostmaster.pid. A live process counts as that cluster's server only if it is apostgresserving that directory (its working directory is the cluster's, read from/procon Linux and withlsofelsewhere), so a recycled process ID that now belongs to another database is left alone. The bootstrap stops the server the waypg_ctl stop -m immediatedoes, and removes the directory only after the server has exited. A server it cannot stop, or cannot confirm, keeps its directory, and a warning is logged. runand the binary keep one directory. The setup-onlyrunfunction and thepg_embedded_setup_unprivbinary initialize a cluster to be used after they exit, so they keep the derived<root>/datadirectory as in 0.6.0 rather than taking a slot that the next bootstrap would sweep. ATestClusterin the same root claims a slot of its own and does not reuse it; setPG_DATA_DIRto share one directory.CleanupMode::Fullshares the install tree. Clusters run side by side from one install tree, so a full clean-up removes it only when no other cluster in the root is running from it. Otherwise it removes just its own data directory. The check and the removal hold a guard file,.claim-guard, that new clusters wait on when claiming a directory.- Setup turns. Clusters sharing an install tree take turns populating it,
under a lock on
<root>/install/.pg-embed-setup.lock, so a cold root is set up once rather than raced. Once the tree is populated, clusters initialize and start in parallel; only the brief copy of cached binaries is serialized. Clusters that declare extensions retake the lock while the extensions are installed, so that step is also serialized.
ADR 005 records the design.