Single-page operational reference for the SDP-managed Perforce estate. Aimed
at the operator who's been paged at 2 AM and needs to find the right command
fast. Companion to the full SDP_Guide.Unix.html and the failover doc
DR-Failover-steps-Unix-standby.md in this directory.
/p4/<inst>/ # per-instance dir (typically <inst> = "1")
├── bin/ -> /p4logs/p4/<inst>/bin # per-instance binaries
├── root/ -> /p4root/p4/<inst>/db1 # online db.* files
├── offline_db/ -> /p4logs/p4/<inst>/db2 # offline db copy for checkpoints
├── logs/ -> /p4journal/p4/<inst>/logs # log + journal
├── checkpoints/-> /p4checkpoints # rotated checkpoints
├── depots/ -> /p4depot/p4/<inst>/depots # archive content
├── tmp/ -> /p4logs/p4/<inst>/tmp
├── .p4tickets
└── .p4trust
/p4/common/ # shared across all instances on a host
├── bin/ -> /p4depot/p4/common/bin # SDP scripts + p4 binaries
└── config/ # passwd files, mkdirs.cfg, etc.
/p4/ssl/ # certificate.txt, privatekey.txt, config.txt
/p4/sdp/ # vendored SDP source tree (synced from repo)
sudo -i -u perforce
source /p4/common/bin/p4_vars 1 # <inst>; populates P4PORT, P4USER, P4TICKETS, etc.
Useful exports after sourcing:
| Var | Typical value | Notes |
|---|---|---|
P4HOME |
/p4/<inst> |
base |
P4PORT |
<host>:1666 |
local p4d |
P4MASTERPORT |
<commit>:1666 |
upstream commit master |
P4USER |
p4admin |
default admin |
P4TICKETS |
/p4/<inst>/.p4tickets |
per-instance, NOT ~/.p4tickets |
P4TRUST |
/p4/<inst>/.p4trust |
for SSL fingerprints |
P4SERVICEUSER |
svc_<replica-id> |
service account on master |
P4REPLICA |
TRUE / empty |
TRUE on standbys / replicas / edges |
systemctl status p4d_1 # p4d
systemctl status p4broker_1 # broker (where present)
systemctl status p4p_<name> # proxy (one per p4p instance)
systemctl status p4prometheus # metrics exporter
journalctl -u p4d_1 -e # log tail
The init scripts at /p4/<inst>/bin/p4d_<inst>_init {start|stop|restart|status}
are what the systemd units wrap.
p4 pull -lj # journal+statefile state vs master
p4 pull -ls # file-transfer summary (active/total)
p4 pull -l --filter=failed # only failed transfers (sticky retries)
p4 servers -J # all servers + their last-known journal pos
p4 monitor show -ae # active commands incl. background pulls
p4 -ztag info | grep -E "version|server"
Output format note (post-2025.1): p4 pull -lj says capital Journal /
Sequence. Older parsers grepping lowercase miss every match.
/p4/common/bin/daily_checkpoint.sh 1 # rotate journal + checkpoint
/p4/common/bin/weekly_checkpoint.sh 1
/p4/common/bin/p4verify.sh 1 # archive integrity
/p4/common/bin/recreate_db_checkpoint.sh 1 # rebuild offline db from latest
/p4/common/bin/sync_replica.sh 1 # rsync from master (replica only)
/p4/common/bin/recover_replica.sh 1 # full replica DB recover
/p4/common/bin/recover_edge.sh 1 # edge-server variant
/p4/common/bin/recover_standby_db.sh 1 # standby variant
/p4/common/bin/live_checkpoint.sh 1 # snapshot without stopping p4d
/p4/common/bin/convert_standby_to_master.sh 1
/p4/common/bin/convert_old_master_to_standby.sh 1
Reference: sdp/doc/DR-Failover-steps-Unix-standby.md for the full procedure.
p4 configure show # everything
p4 configure show <serverid> # per-server
p4 configure set <serverid>#<name>=<val>
p4 configure unset <serverid>#<name>
# Replica startup (typical)
p4 configure set <replica-id>#startup.1='journalcopy -i 0'
p4 configure set <replica-id>#startup.2='pull -L -i 0'
p4 configure set <replica-id>#startup.3='pull -u -i 1'
| File | Path | Source |
|---|---|---|
| License | /p4/<inst>/root/license |
Perforce Support |
| p4d cert | /p4/ssl/certificate.txt |
autogen via p4d -Gc reading /p4/ssl/config.txt, or pre-baked |
| p4d key | /p4/ssl/privatekey.txt |
same |
| Broker cert/key | /p4/ssl/certificate.txt / privatekey.txt |
typically per-cluster, sourced from HashiCorp Vault |
| Trust fingerprint | /p4/<inst>/.p4trust |
populated by first p4 trust -y |
p4 -p ssl:<host>:1666 trust -y # accept fingerprint (per-instance)
p4d -Gc # generate self-signed pair from /p4/ssl/config.txt
| Script | When | What |
|---|---|---|
daily_checkpoint.sh |
nightly | rotate journal + take checkpoint |
weekly_checkpoint.sh |
weekend | full checkpoint + verify |
p4login.sh |
every 4h | refresh p4admin ticket |
sync_replica.sh |
nightly | rsync archives from master (replicas) |
/p4/common/bin/p4 is mode 0700 perforce:perforce and lives on NFS with
root_squash — root cannot execve it. Anything that runs as root and
shells p4 must sudo -u perforce first.P4TICKETS defaults to $HOME/.p4tickets. The SDP convention is
per-instance at /p4/<inst>/.p4tickets — only set after source p4_vars.
A bare p4 login outside that env writes the wrong ticket file.journalcopy for the journal + pull for
archives. Forwarding-replicas use pull for both. The startup config
differs.Sequence_Difference from p4 pull -lj means the replica is
"ahead" of what the queried master endpoint reports — almost always means
the replica is now talking to a different master than it used to (LB
rotation, recent P4TARGET change). Real divergence, not a metric flap.0xF1 for ñ from
cp1252) won't store on UTF-8-strict shared volumes (Pure, some NFS
appliances). Native ext4 / xfs is fine. Fix is p4 move to a clean name —
see "Discovery" below.p4_<rel>.<bld> symlinked to p4_<inst> —
version upgrades swap the symlink, not the binary.sudo -u perforce p4 verify -m1 //... 2>&1 \
| grep -P '[\x80-\xff]' \
| tee /tmp/non-utf8-paths.txt
# OR, walk the depot tree on disk
sudo find /p4/1/depots -name $'*\xf1*' 2>/dev/null
Once the list is in hand, a p4 -c <client> move per file (or batched in a
single submit) renames them to UTF-8-clean names. Coordinate with the depot's
consumers — Maya / Yeti / etc. scenes referencing the old literal paths will
break.
sdp/doc/SDP_Guide.Unix.html — full SDP guidesdp/doc/DR-Failover-steps-Unix-standby.md — failover procedure/p4/common/bin/ — every script you might needp4 help <command> — beats Googlingp4 servers -J — instant view of replica health across the estate# SDP Cheat Sheet
Single-page operational reference for the SDP-managed Perforce estate. Aimed
at the operator who's been paged at 2 AM and needs to find the right command
fast. Companion to the full `SDP_Guide.Unix.html` and the failover doc
`DR-Failover-steps-Unix-standby.md` in this directory.
## Paths (the SDP layout, abbreviated)
```
/p4/<inst>/ # per-instance dir (typically <inst> = "1")
├── bin/ -> /p4logs/p4/<inst>/bin # per-instance binaries
├── root/ -> /p4root/p4/<inst>/db1 # online db.* files
├── offline_db/ -> /p4logs/p4/<inst>/db2 # offline db copy for checkpoints
├── logs/ -> /p4journal/p4/<inst>/logs # log + journal
├── checkpoints/-> /p4checkpoints # rotated checkpoints
├── depots/ -> /p4depot/p4/<inst>/depots # archive content
├── tmp/ -> /p4logs/p4/<inst>/tmp
├── .p4tickets
└── .p4trust
/p4/common/ # shared across all instances on a host
├── bin/ -> /p4depot/p4/common/bin # SDP scripts + p4 binaries
└── config/ # passwd files, mkdirs.cfg, etc.
/p4/ssl/ # certificate.txt, privatekey.txt, config.txt
/p4/sdp/ # vendored SDP source tree (synced from repo)
```
## Environment (always do this first)
```bash
sudo -i -u perforce
source /p4/common/bin/p4_vars 1 # <inst>; populates P4PORT, P4USER, P4TICKETS, etc.
```
Useful exports after sourcing:
| Var | Typical value | Notes |
|-------------------|--------------------------------|----------------------------------------|
| `P4HOME` | `/p4/<inst>` | base |
| `P4PORT` | `<host>:1666` | local p4d |
| `P4MASTERPORT` | `<commit>:1666` | upstream commit master |
| `P4USER` | `p4admin` | default admin |
| `P4TICKETS` | `/p4/<inst>/.p4tickets` | per-instance, NOT `~/.p4tickets` |
| `P4TRUST` | `/p4/<inst>/.p4trust` | for SSL fingerprints |
| `P4SERVICEUSER` | `svc_<replica-id>` | service account on master |
| `P4REPLICA` | `TRUE` / empty | `TRUE` on standbys / replicas / edges |
## Service control
```bash
systemctl status p4d_1 # p4d
systemctl status p4broker_1 # broker (where present)
systemctl status p4p_<name> # proxy (one per p4p instance)
systemctl status p4prometheus # metrics exporter
journalctl -u p4d_1 -e # log tail
```
The init scripts at `/p4/<inst>/bin/p4d_<inst>_init {start|stop|restart|status}`
are what the systemd units wrap.
## Replication health (run as perforce)
```bash
p4 pull -lj # journal+statefile state vs master
p4 pull -ls # file-transfer summary (active/total)
p4 pull -l --filter=failed # only failed transfers (sticky retries)
p4 servers -J # all servers + their last-known journal pos
p4 monitor show -ae # active commands incl. background pulls
p4 -ztag info | grep -E "version|server"
```
Output format note (post-2025.1): `p4 pull -lj` says capital `Journal` /
`Sequence`. Older parsers grepping lowercase miss every match.
## Daily / weekly ops
```bash
/p4/common/bin/daily_checkpoint.sh 1 # rotate journal + checkpoint
/p4/common/bin/weekly_checkpoint.sh 1
/p4/common/bin/p4verify.sh 1 # archive integrity
/p4/common/bin/recreate_db_checkpoint.sh 1 # rebuild offline db from latest
/p4/common/bin/sync_replica.sh 1 # rsync from master (replica only)
/p4/common/bin/recover_replica.sh 1 # full replica DB recover
/p4/common/bin/recover_edge.sh 1 # edge-server variant
/p4/common/bin/recover_standby_db.sh 1 # standby variant
/p4/common/bin/live_checkpoint.sh 1 # snapshot without stopping p4d
```
## Failover / standby promotion (high-stakes)
```bash
/p4/common/bin/convert_standby_to_master.sh 1
/p4/common/bin/convert_old_master_to_standby.sh 1
```
Reference: `sdp/doc/DR-Failover-steps-Unix-standby.md` for the full procedure.
## Configuration
```bash
p4 configure show # everything
p4 configure show <serverid> # per-server
p4 configure set <serverid>#<name>=<val>
p4 configure unset <serverid>#<name>
# Replica startup (typical)
p4 configure set <replica-id>#startup.1='journalcopy -i 0'
p4 configure set <replica-id>#startup.2='pull -L -i 0'
p4 configure set <replica-id>#startup.3='pull -u -i 1'
```
## License + SSL
| File | Path | Source |
|-------------------|---------------------------------------------|----------------------------------------------------------------------|
| License | `/p4/<inst>/root/license` | Perforce Support |
| p4d cert | `/p4/ssl/certificate.txt` | autogen via `p4d -Gc` reading `/p4/ssl/config.txt`, or pre-baked |
| p4d key | `/p4/ssl/privatekey.txt` | same |
| Broker cert/key | `/p4/ssl/certificate.txt` / `privatekey.txt`| typically per-cluster, sourced from HashiCorp Vault |
| Trust fingerprint | `/p4/<inst>/.p4trust` | populated by first `p4 trust -y` |
```bash
p4 -p ssl:<host>:1666 trust -y # accept fingerprint (per-instance)
p4d -Gc # generate self-signed pair from /p4/ssl/config.txt
```
## Cron / queue health
| Script | When | What |
|-------------------------|-------------|-----------------------------------------------|
| `daily_checkpoint.sh` | nightly | rotate journal + take checkpoint |
| `weekly_checkpoint.sh` | weekend | full checkpoint + verify |
| `p4login.sh` | every 4h | refresh `p4admin` ticket |
| `sync_replica.sh` | nightly | rsync archives from master (replicas) |
## Common gotchas (the real ones, not the manual)
- `/p4/common/bin/p4` is mode `0700 perforce:perforce` and lives on NFS with
`root_squash` — **root cannot `execve` it**. Anything that runs as root and
shells `p4` must `sudo -u perforce` first.
- `P4TICKETS` defaults to `$HOME/.p4tickets`. The SDP convention is
per-instance at `/p4/<inst>/.p4tickets` — only set after `source p4_vars`.
A bare `p4 login` outside that env writes the wrong ticket file.
- Forwarding-**standbys** use `journalcopy` for the journal + `pull` for
archives. Forwarding-**replicas** use `pull` for both. The startup config
differs.
- A negative `Sequence_Difference` from `p4 pull -lj` means the replica is
"ahead" of what the queried master endpoint reports — almost always means
the replica is now talking to a different master than it used to (LB
rotation, recent `P4TARGET` change). Real divergence, not a metric flap.
- Filenames with bytes that aren't valid UTF-8 (e.g., `0xF1` for `ñ` from
cp1252) won't store on UTF-8-strict shared volumes (Pure, some NFS
appliances). Native ext4 / xfs is fine. Fix is `p4 move` to a clean name —
see "Discovery" below.
- p4 binaries on disk follow `p4_<rel>.<bld>` symlinked to `p4_<inst>` —
version upgrades swap the symlink, not the binary.
## Discovery: find paths with non-UTF-8 bytes
```bash
sudo -u perforce p4 verify -m1 //... 2>&1 \
| grep -P '[\x80-\xff]' \
| tee /tmp/non-utf8-paths.txt
# OR, walk the depot tree on disk
sudo find /p4/1/depots -name $'*\xf1*' 2>/dev/null
```
Once the list is in hand, a `p4 -c <client> move` per file (or batched in a
single submit) renames them to UTF-8-clean names. Coordinate with the depot's
consumers — Maya / Yeti / etc. scenes referencing the old literal paths will
break.
## Quick refs (open these first when paged)
- `sdp/doc/SDP_Guide.Unix.html` — full SDP guide
- `sdp/doc/DR-Failover-steps-Unix-standby.md` — failover procedure
- `/p4/common/bin/` — every script you might need
- `p4 help <command>` — beats Googling
- `p4 servers -J` — instant view of replica health across the estate
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 32642 | Russell C. Jackson (Rusty) | SDP Cheat Sheet for quick reference. |