Transferring changes between two unrelated Perforce Servers can be a challenge. This talk explains how this can be done using a Python tool called PerforceTransfer. The concepts of this tool, its internal workings as well as its applications and limitations are explained.
1. #
Sven Erik
Technical Marketing
Robert Cowham
Professional Services
2. #
• Background
• Algorithm
• Configuration
• Adapting for continuous transfer
• Customer Case Study
3. #
Author of P4Python.
Started as Lead Consultant at Perforce.
Regular presenter at Perforce and other
conferences.
API experience includes P4OFC
(P4COM) and P4Python. Author of
'Learning Perforce SCM' by PACKT
Publishing, Sep 2013.
5. #
• One project in two separate Perforce Servers?
– e.g. Public Depot and Master Depot
Source P4D Target P4D
?
6. #
• Git? SHAs do not match.
• Sandbox? Can only talk to one server.
• Replication? Not practical.
• Reconcile? Changes? Integrations?
• Replay changes one by one ... ?
7. #
• Transfer workspace sharing the same root
Source Target
transfer
8. #
• One workspace on each server with shared root
• Client views have to match
– Depot views don’t have to match
– Filter projects you want to transfer
• Need to set options to allwrite
Client: src-trans
Root: /Users/sknop/perforce/transfer
Options: allwrite
View:
//source/project1/... //src-trans/...
Client: target-trans
Root: /Users/sknop/perforce/transfer
Options: allwrite
View:
//target/external/... //target-trans/...
9. #
• Written in Python (2.6+ and 3.3+) using P4Python
• Makes use of P4::Map and P4::Resolver
– Use Map instead of “p4 where”
– Resolver allows scripting of resolve results
10. #
counter = getCounter()
changes = p4 –p source changes ...@counter,#head
for change in changes:
filterChangeByClientView(change)
p4 –p source sync
if add: p4 –p target add
if delete: p4 –p target delete -v
if edit: p4 –p target sync –k ; p4 –p target edit
if move: p4 –p target sync –f old; p4 –p target edit old; p4 –p target move old new
integrate?
11. #
• Integrations within workspace view are transferred
– Resolve records match source records (details later)
• Integrations from outside the view are downgraded
– integrate add/edit/delete
• Use P4::Resolver to preserve resolve outcome
13. #
• usage: P4Transfer.py [-h] [-n] [-c CONFIG] [-m MAXIMUM] [-k] [-p] [-r] [-s]
• [--sample_config] [-i]
• P4Transfer
• optional arguments:
• -h, --help show this help message and exit
• -n, --preview Preview only, no transfer
• -c CONFIG, --config CONFIG Default is transfer.cfg
• -m MAXIMUM, --maximum MAXIMUM Maximum number of changes to transfer
• -k, --nokeywords Do not expand keywords and remove +k from filetype
• -p, --preflight Run a sanity check first to ensure target is empty
• -r, --repeat Repeat transfer in a loop - for continuous transfer
• -s, --stoponerror Stop on any error even if --repeat has been specified
• --sample_config Print an example config file and exit
• -i, --ignore Treat integrations as adds and edits
15. #
• How do we test P4Transfer with two servers?
• Use the “rsh trick”
– Spawn a local p4d but without consuming port
P4PORT=rsh:/bin/p4d -r /path/to/target.root –i
• Tests:
– Inject changes into source
– Transfer
– Verify result in target
17. #
• Experience based on source code migrations
– which can take days
• We want to keep an eye on things
– But have a life at the same time
• Reliability/robustness in the face of
(communication) errors
• Status / Error reporting to support the above
18. #
• Customer working with multiple third parties
• Provide some level of backup/DR
• Limited access to remote repositories
– Replicas considered but rejected
– Basically only read-only access
• Data size/connectivity issues
19. #
• Volume / connectivity bandwidth
– 280 Gb of data
• Seeding via offline backup would have been ideal
– 1Gb per hour transfer rate
– Single (early) changelist ~120Gb!
• We wanted
– Handle/report VPN disconnects
– Peace of mind…!
20. #
• Use standard Python logging module
– Subclass for custom behavior
– Beware of Python 2.x/3.x compatibility issues
• Custom logging enhancements
– Use circular buffer to remember last 50 lines
– Automatically notify users via email, including those
lines
22. #
• P4API / P4Python has callback options
# Report status per change
self.progress.ReportChangeSync()
# Create a custom callback object (next slide)
mycallback = SyncOutput(self.progress)
# Pass it to the P4 sync command
self.p4.run('sync', '...@{},{}'.format(change, change), handler=mycallback )
23. #
class SyncOutput(P4.OutputHandler):
def __init__(self, progress):
P4.OutputHandler.__init__(self)
self.progress = progress # Save reporting object
def outputStat(self, stat): # Function called by P4API
if 'fileSize' in stat:
# Report how much data synced for current file
self.progress.ReportFileSync(int(stat['fileSize']))
return P4.OutputHandler.HANDLED
24. #
• What happens when the Dragon King is:
– Der Drachenkönig.jpg
• Windows servers (not in Unicode mode) handle
(some) Unicode filenames happily
– no P4CHARSET required, but…
• On Mac/Unix - UTF8 does the job
• On Windows:
– Python 2.7 fine / Python 3.x requires work…
25. #
• On Windows run as a service
– Install: srvcinst.exe
– Run service: srvany.exe (or other equivalents)
26. #
• Basic algorithm unchanged
– Fixed a couple of bugs
– TDD => Test Harness
• Added repeat/polling options
• Enhanced Robustness
– Logging / Status reporting
– Error handling
27. #
Sven Erik Knop
sknop@perforce.com
Robert Cowham
rcowham@perforce.com
@robertcowham
28. #
RESOURCES
Public Depot:
swarm.workshop.perforce.com/projects/perforce-software-p4transfer/
Notas do Editor
JournalReader started in the public depot, but needed to be kept in sync with the master depot.
Configuration options to decide how frequently to report, e.g. every 0.5 Gb – depends on connectivity speed.
Main difference is that Python 3 all strings are unicode
Didn’t have to do too much for the customization
As all these things, the devil is in the details
Didn’t have to do too much for the customization
As all these things, the devil is in the details