Perforce Public Knowledge Base - P4 Obliterate - Behind the Scenes
Downloads Blog Company Integrations Careers Contact Try Free
Menu Search
Reset Search



P4 Obliterate - Behind the Scenes

« Go Back


I know what p4 obliterate does, but how does it work?
Why does Perforce recommend that p4 snap be run before obliterating?
The documentation for p4 obliterate states:
p4 obliterate can be used by Perforce administrators to permanently remove files from the depot. All information about the files is wiped out, including the files' revisions, the files' metadata, and any records in any labels or client workspace records that refer directly to those files. Once p4 obliterate completes, it appears to the server as if the affected file(s) had never existed. Copies of files in client workspaces are left untouched, but are no longer recognized as being under Perforce control.

The following diagram shows a simple case where files were branched out from main and then branched back in.

The administrator decides to oblierate the file "//depot/oblit/b.txt":


This is done with the command:

p4 obliterate -y //depot/oblit/b.txt

This results in the following output: 

//depot/oblit/b.txt#1 - purged
//depot/oblit/b.txt#2 - purged
//depot/oblit/b.txt#3 - purged
//depot/oblit/b.txt#4 - purged
//depot/oblit/b.txt#5 - purged
//depot/oblit/b.txt#6 - purged
Deleted 1 client 8 integration 6 revision record(s).

The output shows that all 6 revisions of "b.txt" were removed from the Perforce database. The 8 integration records that were deleted were from the 4 integrations that involved b.txt:
  • The integration from a to b.
  • The integration from b to c.
  • The integration from c to b.
  • The integration from b to a. 
Each integration stores two records - one with the source file to show where it was branched to, and one with the destination file to show where it was branched from, hence the 8 records. The client record that was purged was the "have" record, the record that indicates the workspace had "b.txt" synced.
Log File Output

The log file output for this command is sparse, even with maximum verbosity turned on:
 2009/08/07 12:35:59 pid 1686 a_user@test-ws [p4/2009.1.BETA/LINUX26X86_64/202559] 'user-obliterate -y b.txt'
 2009/08/07 12:35:59 pid 1686 completed .340s 0+12us 0+192io 0+0net 0k 0pf
Archive File Impact

Looking at the archive location in the depot directory on the Perforce server, the archive file for b.txt (b.txt,v) has been removed:
/var/perforce/2008.2/depot/oblit# ls
a.txt,v  c.txt,v

This is in keeping with one of obliterate's primary purposes - to free up disk space.

Effect on the Workspace

The obliterate does not remove the file from workspaces, it just disassociates it from being managed by Perforce.
~/Perforce/2008.2/oblit$ ls
a.txt  b.txt  c.txt

~/Perforce/2008.2/oblit$ p4 fstat b.txt
b.txt - no such file(s).

~/Perforce/2008.2/oblit$ p4 have //depot/oblit/...
//depot/oblit/a.txt#7 - /home/workspace/Perforce/2008.2/oblit/a.txt
//depot/oblit/c.txt#2 - /home/workspace/Perforce/2008.2/oblit/c.txt

Branching Effects

Since b.txt was a file branched from a.txt and used to create the c.txt file branch, removing b.txt has an impact on the branching history for these files:


Since a.txt was the original version of the file, removing b.txt produces a revision graph of a file that was never branched:
p4 filelog -i //depot/oblit/a.txt
... #7 change 28 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #6 change 27 integrate on 2009/08/07 by a_user@test-ws (text) 'meh'
... #5 change 21 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #4 change 20 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #3 change 17 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #2 change 16 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #1 change 15 add on 2009/08/07 by a_user@test-ws (text) 'meh'

However, c.txt now appears as a file branched with no discernible source (or base) file:
p4 filelog -i //depot/oblit/c.txt
... #2 change 24 edit on 2009/08/07 by a_user@test-ws (text) 'meh'
... #1 change 19 branch on 2009/08/07 by a_user@test-ws (text) 'meh'

We can see that Perforce has no knowledge that a.txt was ever used as the source of an obliterated file. An "anonymous branch record" is used for c.txt#1. Anonymous branch records are inserted anywhere that a revision occurs as the result of an obliterated branch.
Because a.txt#6 was the result of the branch from b.txt to a.txt, an anonymous record was inserted there as well, but instead of a "branch" notation, we have an "integrate" notation to let us know this revision was created as a result of a merge from an obliterated branch.

Effects on Source Code

Prior to the obliterate of b.txt, b.txt received changes from c.txt, and passed those changes on to a.txt. Obliterating a file does not remove any of the changes previously merged to existing files from the obliterated file.

Prior to the obliterate, the third line in c.txt was changed from "aka" (the line that existed in a.txt#3 when it was used to create b.txt#1) to "bbb". This changed line was integrated to b.txt. This line was changed again in b.txt to "abbb". This line was integrated from b.txt#6 to a.txt#6. Performing a diff between a.txt#6 and c.txt#2 thus shows the following changes:
~/Perforce/2008.2/oblit$ p4 diff2 a.txt#6 c.txt#2
==== //depot/oblit/a.txt#6 (text) - //depot/oblit/c.txt#2 (text) ==== content
< addd
< eee
< abbb
< xxxx
> aaa
> ccc
> bbb

After obliterating b.txt, the diff output is unchanged -- in other words, the third line of c.txt#2 is still "bbb", and "abbb" in a.txt#6.

Effects on future integrations

As Perforce purged all the integration records, it no longer has any record that c.txt ever received or provided changes to a.txt. This means that an integration performed between c.txt and a.txt is done as a baseless integration, with no common ancestor. For example:
~/Perforce/2008.2/oblit$ p4 integ c.txt a.txt
//depot/oblit/a.txt - can't integrate from //depot/oblit/c.txt#1,#2 without -i flag

The -i flag has to be used to force a baseless merge:
p4 integ -i c.txt a.txt

Obliterate, Lazy Copies and "p4 snap"

When a file is branched for the first time, Perforce does not create a physical copy of the file, instead Perforce creates a "lazy copy". Lazy copies are references to the source of the copy, and until the copy is modified, it remains a reference. Lazy copies allow Perforce to create branches with speed and minimize disk space usage, but difficulties can arise when obliterating a file that is the source of a lazy copy.

For example:
p4 add d.txt
//depot/oblit/d.txt#1 - opened for add

p4 submit -d "adding d.txt"
Submitting change 29.
Locking 1 files ...
add //depot/oblit/d.txt#1
Change 29 submitted.

p4 integ d.txt e.txt
//depot/oblit/e.txt#1 - branch/sync from //depot/oblit/d.txt#1

p4 submit -d "branching d.txt to e.txt"
Submitting change 30.
Locking 1 files ...
branch //depot/oblit/e.txt#1
Change 30 submitted.

At this point the file e.txt is a lazy copy of d.txt:


Examining the archive files shows that only d.txt is present, not e.txt:
/var/perforce/2008.2/depot/oblit# ls
a.txt,v  c.txt,v  d.txt,v

Without modifying e.txt to create a second revision (which would create e.txt,v in the archives), d.txt is obliterated:
p4 obliterate -y d.txt
Deleted 1 client 2 integration 1 revision record(s).

p4 fstat d.txt
d.txt - no such file(s).

p4 fstat e.txt
... depotFile //depot/oblit/e.txt
... clientFile /home/workspace/Perforce/2008.2/oblit/e.txt
... isMapped
... headAction branch
... headType text
... headTime 1249685216
... headRev 1
... headChange 30
... headModTime 1249685187
... haveRev 1

While d.txt no longer exists, e.txt still appears to be complete. Checking the archives now reveals an interesting result:
/var/perforce/2008.2/depot/oblit# ls
a.txt,v  c.txt,v  d.txt,v

Since e.txt relies on the contents of d.txt, Perforce leaves the d.txt archive in place.  Modifying e.txt creates a new e.txt,v which contains the new revisions of e.txt.  It does not contain revisions prior to the branch from d.txt.

The effects of p4 snap

Perforce will not erase versioned files if a lazy copy needs them.  But there is a risk that an administrator may wonder why a obliterated directory exists on the server, not knowing that another file needs these versioned files.  If the administrator erases this directory, important source files will be lost as seen by the MISSING! error upon the next "p4 verify".  By using "p4 snap", the lazy copy will be removed, a versioned file will be copied over to compensate, and therefore the versioned files on the server will be removed as expected.

In this example x.txt is created, and then branched to y.txt to create a lazy copy:
p4 add x.txt

p4 submit -d "added x.txt"
//depot/oblit/x.txt#1 - opened for add
Submitting change 31.
Locking 1 files ...
add //depot/oblit/x.txt#1
Change 31 submitted.

p4 integ x.txt y.txt
//depot/oblit/y.txt#1 - branch/sync from //depot/oblit/x.txt#1

p4 submit -d "branching from x.txt to y.txt"
Submitting change 32.
Locking 1 files ...
branch //depot/oblit/y.txt#1
Change 32 submitted.

Examining the archives confirms that there is no y.txt,v archive file:
/var/perforce/2008.2/depot/oblit# ls
a.txt,v  c.txt,v  d.txt,v  x.txt,v
Next, perform the p4 snap against the x.txt file:
p4 snap //... //depot/oblit/x.txt
//depot/oblit/y.txt#1 - copy from //depot/oblit/x.txt 1.31

Then obliterate the x.txt file
p4 obliterate -y //depot/oblit/x.txt
//depot/oblit/x.txt#1 - purged

Deleted 1 client 2 integration 1 revision record(s).

Since p4 snap copied the contents of y.txt to x.txt, checking the archive files reveals the following:
/var/perforce/2008.2/depot/oblit# ls
a.txt,v  c.txt,v  d.txt,v  e.txt,v  y.txt,v

Note that y.txt,v is present, but x.txt,v is not.

Note: The p4 snap command is often time consuming so you may want to run this command during off-hours.
Related Links



Was this article helpful?



Please tell us how we can make this article more useful.

Characters Remaining: 255