I verified the behavior of Perforce exclusive locks in detail

I verified the behavior of Perforce exclusive locks in detail

Here is what we confirmed regarding practical operational specifications for Perforce exclusive locks (binary+l), including deadlock occurrence, resolution by administrators, differences from non-exclusive (binary+w), and automatic assignment via typemap.
2026.07.19

This page has been translated by machine translation. View original

Introduction

In development environments where binary assets are handled by multiple people, Perforce's exclusive locks are unavoidable. The mechanism where one person opening a file for editing prevents others from opening it is powerful, but for those accustomed to Git, some of the behavior may feel a little unfamiliar.

In this article, we set up a Perforce instance with two users and verify the behavior of exclusive lock deadlocks, administrative release, differences from non-exclusive locks, and automatic assignment via typemap.

There are two file types for binaries that differ in how locking works. binary+l is a file type with an exclusive lock—when one person opens a file for editing, other users cannot open it. binary+w is non-exclusive, allowing multiple people to open the file simultaneously. This article focuses on verifying these two types. The procedures are provided in the body text so you can reproduce them locally.

What is Perforce

Perforce (Helix Core) is a centralized version control system widely used in development environments that handle large binary files with many contributors. It is frequently adopted in game development and has an exclusive lock mechanism to protect binaries that cannot be merged. The server process is called p4d, and the client is called p4.

Verification Environment

  • macOS
  • Helix Core p4d 2025.2
  • 2 users: tester_a and tester_b

Target Audience

  • Administrators who want to design Perforce lock operations
  • People working in development environments that handle large binary files with multiple contributors

References

Background and Problem Statement

Why does Perforce use locks? Its primary domain is game development, where most files are binaries such as textures and 3D models. Unlike text files, binaries cannot be meaningfully merged. Since merging is not possible, allowing simultaneous editing means one person's work will be lost. That is precisely why exclusive locks, which restrict editing to one person at a time, are a rational protective measure.

On the other hand, there are aspects of lock behavior that are difficult to notice without actually running it in production. Let's verify the following in practice: the success or failure of blocked commands, what happens to files when an administrator releases a lock, and the scope of application when typemap is added retroactively.

Verification Method

We start p4d locally and prepare two users, tester_a and tester_b, each with their own workspace. As the targets of verification, we register two binary files with the binary+l type, which represents an exclusive lock.

Starting p4d

Perforce's p4d and p4 can be obtained from the official download page.

start-p4d.sh
mkdir -p p4root
p4d -r "$PWD/p4root" -p 1666 -L "$PWD/p4d.log" -J "$PWD/p4root/journal" -d
export P4PORT=1666
# Disable authentication for verification. Do not use this setting in production.
p4 configure set security=0

Preparing Users and Files

We create workspaces for tester_a and tester_b, and register two binaries with binary+l (assetX.bin and assetY.bin).

Script for preparing users and files
setup-users.sh
# Create tester_a's workspace and register exclusive lock binaries
export P4USER=tester_a P4CLIENT=ws_a
p4 client -i <<EOF
Client: ws_a
Owner: tester_a
Root: $PWD/ws_a
View:
	//depot/... //ws_a/...
EOF
mkdir -p ws_a && cd ws_a
head -c 1048576 /dev/urandom > assetX.bin
head -c 1048576 /dev/urandom > assetY.bin
p4 add -t binary+l assetX.bin assetY.bin
p4 submit -d "baseline: assetX/Y.bin (binary+l)"
cd ..
# Create tester_b's workspace and sync
p4 -u tester_b -c ws_b client -i <<EOF
Client: ws_b
Owner: tester_b
Root: $PWD/ws_b
View:
	//depot/... //ws_b/...
EOF
p4 -u tester_b -c ws_b sync

Verification Results

Deadlock Due to Exclusive Locks

tester_a opens assetX.bin for editing, and tester_b opens assetY.bin for editing. They then each attempt to open the other's file as well.

deadlock.sh
# tester_a opens X, tester_b opens Y
p4 -u tester_a -c ws_a edit //depot/assetX.bin
p4 -u tester_b -c ws_b edit //depot/assetY.bin
# Each tries to open the other's file
p4 -u tester_a -c ws_a edit //depot/assetY.bin
p4 -u tester_b -c ws_b edit //depot/assetX.bin

binary+l locks out other users the moment a file is opened for editing. Therefore, the line where tester_b tries to open assetX.bin is rejected as follows.

//depot/assetX.bin - can't edit exclusive file already opened for edit
... //depot/assetX.bin - also opened by tester_a@ws_a

Each is waiting for the other's file, and neither can obtain the second file. This is a deadlock.

There is a behavior worth noting for automation. While it is generally the case that a command returning a non-zero exit code indicates failure, in this case of blocking by exclusive lock, the exit code of p4 edit was 0.

$ p4 -u tester_b -c ws_b edit //depot/assetX.bin ; echo "exit=$?"
//depot/assetX.bin - can't edit exclusive file already opened for edit
... //depot/assetX.bin - also opened by tester_a@ws_a
exit=0

If a script or automation only checks the exit code, it will not notice that it was blocked by a lock. Note that in the case of a submit conflict described later, the exit code is 1.

Administrative Release

A lock held by another user can be released by a user with admin privileges. In this minimal configuration, protections are not set, and in that case Perforce grants super privileges to all users, so in practice any user can release locks. In production, use p4 protect to restrict this to administrators.

First, check who has what open.

$ p4 opened -a
//depot/assetY.bin#2 - edit default change (binary+l) by tester_b@ws_b *exclusive*

The *exclusive* marker indicates that it is an exclusive lock. Now suppose tester_b has made uncommitted edits to this file. What happens to those edits when an administrator releases the lock? You might expect that a forced release would discard the other person's work or revert it to its original state, but verification showed that neither is the case.

We hash the file before and after the edit, then have an administrator release the lock.

$ md5 -q ws_b/assetY.bin        # Before editing
a8470858dab3f9774e473bb0babeb582
# tester_b modifies the file locally (uncommitted edit)
$ md5 -q ws_b/assetY.bin        # After editing
6fdb30a7d9d8faffb47a6efaf409e0ea

$ p4 -u admin -c ws_b revert -C ws_b //depot/assetY.bin
//depot/assetY.bin#2 - was edit, cleared

$ md5 -q ws_b/assetY.bin        # After release
6fdb30a7d9d8faffb47a6efaf409e0ea

The hash after release remains the same as after editing, and has not reverted to the depot contents. This can be explained by the behavior of p4 revert.

$ p4 help revert
...
The -C flag allows a user to specify the workspace that has the file
opened rather than defaulting to the current client workspace. When
this option is used, the '-k' flag is also enabled ...

The -k flag marks the file as reverted in server metadata without
altering files in the client workspace.

The -C flag, which specifies another user's workspace, implicitly enables -k. The -k flag only releases the open state in the server-side metadata, without touching the client's files. In other words, an administrative release clears the server-side open state and lock, but does not modify the files in the lock holder's workspace. The lock is actually released, and the party that was waiting can now edit that file.

$ p4 -u tester_a -c ws_a edit //depot/assetY.bin
//depot/assetY.bin#2 - opened for edit

The lock holder's edits remain in their workspace, but the server-side open state is cleared.

The above covers the case where the lock holder has made no preparations. When the lock holder wants to ensure their work is preserved, they should shelve their changes to the server before the release. Gather the edits into a numbered changelist and then shelve them (create a changelist with p4 change, then move the edits there with p4 reopen -c).

$ p4 -u tester_b -c ws_b shelve -c 15
... //depot/assetY.bin - warning: shelve of +l file
Change 15 files shelved.

One important thing to note here is that shelving does not release the lock. Even after shelving, p4 opened -a still shows *exclusive*, and the block on others remains. Shelving only saves the work; to actually release the lock, an administrator's action is still required. Even after the administrator releases it, the shelved changes remain.

$ p4 -u admin -c ws_b revert -C ws_b //depot/assetY.bin
//depot/assetY.bin#2 - was edit, cleared
$ p4 changes -s shelved
Change 15 on 2026/07/19 by tester_b@ws_b *pending* 'WIP assetY'

The lock holder can later unshelve to retrieve their saved edits intact.

$ p4 -u tester_b -c ws_b unshelve -s 15 //depot/assetY.bin
//depot/assetY.bin#2 - unshelved, opened for edit

If the lock holder shelves their work before the release, it is preserved. Conversely, if they have made no preparations, the server-side open state is cleared and any unshelved edits remain only in their local workspace. That is why it is important for the administrator to contact the lock holder before performing a release.

Differences from Non-Exclusive (binary+w)

Exclusive locks are not the only option. Setting the file type to binary+w makes it non-exclusive, allowing two people to open the same binary at the same time. While this is more convenient since there is no waiting, the handling of conflicts requires attention.

Here we register assetW.bin as binary+w.

p4 add -t binary+w assetW.bin

We then have two people open it simultaneously.

$ p4 -u tester_a -c ws_a edit //depot/assetW.bin
//depot/assetW.bin#3 - opened for edit
$ p4 -u tester_b -c ws_b edit //depot/assetW.bin
//depot/assetW.bin#3 - opened for edit
... //depot/assetW.bin - also opened by tester_a@ws_a

There is no blocking as with binary+l; a warning is shown, but the second person can also open the same file. The problem appears at submit time. After both have made edits, tester_a submits first, and when tester_b subsequently tries to submit, tester_b is asked to resolve.

$ p4 -u tester_a -c ws_a submit -d "A edits assetW"
Change 13 submitted.
$ p4 -u tester_b -c ws_b submit -d "B edits assetW"
//depot/assetW.bin - must resolve before submitting
Out of date files must be resolved or reverted.

$ p4 -u tester_b -c ws_b resolve -am //depot/assetW.bin
Non-text diff: 0 yours + 0 theirs + 0 both + 1 conflicting
//ws_b/assetW.bin - resolve skipped.

Since binaries cannot be merged, auto-merge (-am) is skipped. The remaining choices are to accept your own version (-ay) or the other person's version (-at), and whichever version is not chosen will not be reflected in this file. binary+w eliminates wait times at the cost of deferring conflict resolution decisions to submit time.

Automatic Assignment via typemap

To prevent forgetting to assign exclusive locks, you can use typemap to define file types by extension in advance. To verify the scope of application, we first add one file, art_old.psd, before setting up the typemap. At this point there is no typemap, so it becomes a regular binary.

After that, we configure the typemap.

typemap.sh
p4 typemap -i <<EOF
Typemap:
	binary+l //....uasset
	binary+l //....umap
	binary+l //....psd
EOF

After this, .psd files added subsequently will become binary+l even without specifying -t.

$ p4 add art_new.psd
$ p4 opened //depot/art_new.psd
//depot/art_new.psd#1 - add default change (binary+l) *exclusive*

typemap is applied only at the time of addition (p4 add) and does not apply retroactively to files that were already added before the setting. A .psd file that existed before the setting remains binary.

$ p4 fstat -T "depotFile, headType" //depot/art_old.psd
... depotFile //depot/art_old.psd
... headType binary

To convert existing files to binary+l, a separate migration is needed: change the type with p4 edit -t binary+l and submit. When introducing typemap, forgetting this migration leaves a situation where only the old files lack locks.

Discussion

Choosing Between binary+l and binary+w

Aspect binary+l (exclusive) binary+w (non-exclusive)
Simultaneous editing Blocks the second person's edit Both can open at the same time
Timing of conflict Does not occur (stopped at edit time) Resolve at submit time
Binary conflict resolution Not needed Choose between your version or theirs
Suitable files Assets touched by one person at a time (.uasset, .psd, audio, etc.) Things where parallel editing can be managed operationally

For most binaries that cannot be merged, it is clearest to set the default to binary+l and auto-assign via typemap, reserving binary+w only for files where parallel editing is explicitly acceptable.

Prevention and Preparing for Lock Conflicts

Lock conflicts can be reduced more through upfront design than through post-hoc releases. Effective practices include using typemap to prevent forgotten assignments, and monitoring with p4 opened -a to identify files that have remained *exclusive* for a long time without movement, then following up early. Since an administrative release only clears the server-side open state, protecting the lock holder's work requires contacting them before the release and, if necessary, having them shelve their changes.

Note that separate from the exclusive open behavior of binary+l covered in this article, there is also an advisory lock via the p4 lock command. That command allows edit but stops at the submit stage; it appears as *locked* in p4 opened -a, and its behavior differs from *exclusive*, which stops at edit time.

Summary

We verified Perforce's exclusive locking behavior across the following areas: deadlock occurrence, administrative release, differences from non-exclusive locking, and the scope of typemap application. Key behaviors to keep in mind for actual operations include: the exit code is 0 even when blocked, an administrative release does not modify files in the workspace, and typemap does not apply retroactively to existing files. For those accustomed to Git in particular, some of this behavior may feel somewhat unfamiliar. We hope this article serves as useful reference material when operating Perforce locks.


ゲーム開発・運用環境の効率化を支援します

Classmethodの専門家による包括的なクラウド活用とデジタル化支援で、ゲーム開発の効率を最大化しましょう。AWSの導入から運用、最適化まで、最新技術と豊富な経験であらゆる課題を解決します。株式会社CAPCOM様、株式会社SNK様などの事例もご覧いただけます。

ゲーム業界のサービス詳細を見る

Share this article