Perforce 服务端搭建:Server、Proxy、Trigger 与 UE 工程
Perforce 服务端搭建:Server、Proxy、Trigger 与 UE 工程
这篇把我搭 P4 服务端时踩过、查过的东西归到一处:单机和多实例的 Server/Proxy 怎么装、日常用哪些命令管服务、checkpoint 和 verify 怎么排期、trigger 怎么配,以及给 UE4 工程做 typemap 和权限表时要注意什么。命令基于 P4 Server 2015.2,部分配置项更早的版本没有。
安装前准备
- 从 https://www.perforce.com/downloads/helix 下
perforce.exe、p4v、p4admin。 - 服务器留足磁盘和算力,容量评估参考官方 System Administrator Guide。
- 准备好 P4 Server 的 License 文件。
Windows 上安装 Server
perforce.exe 会一次性装好 Perforce 服务、Perforce Proxy 和命令行客户端。版本服务 p4d 可以跑成开机自启的 Windows 服务(p4s.exe),也可以用 p4d.exe 在命令行手动拉起。安装器默认把它配成 Windows 服务。
配置 P4 要用管理员权限的 cmd:
:: 不带 Unicode 支持
p4d -d D:\P4Root init -n
:: 带 Unicode 支持(在安装目录 C:\Program Files\Perforce\Server 下执行)
p4d -xi
p4 set -s P4CHARSET=auto
p4 set -S Perforce P4ROOT=D:\P4Root
服务的起停用下面三条命令,或者直接进 services.msc 操作:
p4 admin stop
p4 admin start
p4 admin restart
一台机器跑多个 Server 实例
多个 Perforce 服务可以在同一台机器上用不同端口共存,要靠 svcinst.exe 来建额外服务。
停掉当前 Perforce 服务。
给第二个实例建目录,比如
D:\p4Root2。把
p4d.exe、p4s.exe、svcinst.exe和license文件拷进这个目录。在新目录下创建服务,
-n是服务名、-e是服务 exe 路径、-a表示自启:svcinst create -n Perforce2 -e D:\p4Root2\p4s.exe -a设置
Perforce2的参数:p4 set -S Perforce2 P4ROOT=D:\p4Root2 p4 set -S Perforce2 P4PORT=1667 p4 set -S Perforce2 P4LOG=log2 p4 set -S Perforce2 P4JOURNAL=journal2启动服务:
svcinst start -n Perforce2。
用命令行做服务端配置
执行下面的配置前,先设好要操作的实例,确保命令打到对的服务:
set p4port=<P4SERVER>:1666
p4 configure set dm.user.noautocreate=2:禁止新用户自助建账号,只有超级用户能建新用户。并行 sync/submit 相关(后两条 2015.2 起才有):
p4 configure set net.parallel.max=8 p4 configure set net.parallel.threads=8 p4 configure set net.parallel.submit.threads=8journal 前缀:
p4 configure set journalPrefix=checkpoint/<yourPrefix>。之后建的 checkpoint 都会落在<P4ROOT>\checkpoint目录、以<yourPrefix>开头,服务端目录结构更清楚。
用 Active Directory 做用户认证
挂个 trigger 让 AD 来认证登录,能省掉单独维护一套 P4 用户密码。
服务器上把
p4auth_ad.exe放到C:\。命令行执行
p4 triggers。在弹出的编辑器末尾加一行(这行必须缩进,否则会报语法错):
ad auth-check auth "c:\p4auth_ad.exe <ldap-host> 389 CN=Users,DC=<domain>,DC=com <domain>\%user%"重启 P4 服务。
第一次以超级用户身份登录、新建用户。
重启后,改用 Windows 账号密码登录。
用 P4Admin 做配置
P4Admin 能干的事:建用户和组、设密码安全级别、管权限、管 depot、监控进程等。
- 密码安全级别:在
Administration → Password Security Level,设成3(强制 ticket 认证)。设密码前要先设好这个级别。 - 建用户和组:
Users & Groups标签页里增删改。建组时至少塞一个用户进去——组只有在含用户时才真正存在。 - 权限管理:
Permissions标签页,细节参考 p4 protect。
服务端维护:目录结构、checkpoint、verify
Perforce 存两类数据:版本化文件和元数据。版本化文件是用户提交的内容,存在 depot 目录树里;元数据是 changelist、打开的文件、workspace 规格、branch mapping 等,以 db.* 文件的形式放在服务器根目录顶层,每个 db.* 是一张二进制编码的数据库表。
Checkpoint 是能完整重建数据库元数据的快照文件。建 checkpoint 时数据库会被锁,从而拿到内部一致的快照,同时也能截断不断变长的 journal。系统备份前先做一次 checkpoint 是好习惯:
set p4port=<P4SERVER>:1666
p4 admin checkpoint -Z
可以在服务器上用任务计划定时跑。这个过程会干扰 P4 上的文件传输和数据库操作,所以安排在每周日中午这种低峰时段。
Verify 用存储的 MD5 摘要校验每个文件版本的完整性:
p4 verify -qz //...
小库可以每天跑,大库改成每周一次。
Proxy(P4P)搭建
Proxy 缓存文件版本,给异地或带宽受限的团队加速。准备工作和 Server 类似:从官网下 p4p.exe、p4v,Proxy 机器留足磁盘和算力。
装成 Windows 服务
把 p4p.exe 重命名为 p4ps.exe 就能跑成 Windows 服务。多实例同样靠 svcinst.exe:
建目录,比如
D:\p4Proxy2。把
p4ps.exe和svcinst.exe拷进去。创建服务:
svcinst create -n "PerforceProxy2" -e D:\p4Proxy2\p4ps.exe -a设参数:
p4 set -S "PerforceProxy2" P4PORT=<PortOnProxyMachine> p4 set -S "PerforceProxy2" P4TARGET=<TargetServerIP>:<TargetServerPort> p4 set -S "PerforceProxy2" P4PCACHE=D:\p4Proxy2\Cache p4 set -S "PerforceProxy2" P4LOG=log启动:
svcinst start -n "PerforceProxy2"。缓存文件落在D:\p4Proxy2\Cache。
端口要通
服务起来后确认 Perforce 端口可达。先用 telnet 探:
telnet <host_ip> <port_number>
不通就去防火墙放行对应端口。
预热缓存
P4P 只在用户提交新版本或请求已有版本时才缓存文件,不会预取。性能收益只有在文件被缓存之后才出现。可以建一个专用 workspace 来给 Proxy 预取文件,用 -Zproxyload 避免把文件真写进 workspace、白白消耗时间和磁盘:
p4 -Zproxyload sync //<Depot>/...
在 Proxy 机器上用任务计划安排在夜间预热。
磁盘空间管理
P4P 缓存的文件版本会一直堆积,它自己不删、也不管磁盘消耗,放任不管迟早爆盘。要回收空间就删 Proxy 根目录下的文件。删缓存文件不用停 Proxy;但如果不停 Proxy 直接删了缓存,必须同时删掉 Proxy 根目录下的 pdb.lbr 文件。
参考 P4 Proxy 文档。
Trigger:原理、类型与配置
Helix Server 支持 trigger——在特定操作发生时被调用的用户脚本或程序。changelist 提交、表单变更、用户登录或改密码等都能触发。脚本返回 0 操作继续,返回其他值操作失败。
常见用途:
- 校验 changelist 内容,补上权限表覆盖不到的规则(比如提交
file1时强制也提交file2)。 - 在某条命令执行前后做动作。
- 校验或定制表单(比如
p4 client时生成定制的默认 workspace view,或强制用户填有意义的描述)。 - 对接外部认证(LDAP、AD)。
- 从仓库外的数据源取归档内容。
详见 Triggers 章节。
trigger 行格式
<TriggerName> <TriggerType> <depotPath> "<what to do>"
<TriggerType> 的常见取值:
archive 外部归档访问
bgtask 服务端用户进程
auth-check 认证校验 / auth-check-sso SSO 校验 / auth-set 设置认证
change-submit pre-submit / change-content 内容提交 / change-commit post-submit / change-failed 提交失败
command 用户命令前后
edge-submit Edge Server 提交相关
form-in/out/save/commit/delete 表单各阶段
shelve-submit/commit/delete shelve 各阶段
journal-rotate journal 轮转
(完整列表见官方 Trigger table fields。)
<what to do> 是这条 trigger 实际要执行的命令:
- 命令必须用双引号括起来,支持各种脚本。
- 脚本在 P4 上:
"%//test/test/add.bat%";脚本在 P4 服务器本机:"E:\test\test.bat"。 - 支持传入 trigger 变量,例如把
%changelist%透传给脚本:"%//test/test/add.bat% %changelist%"或"E:\test\test.bat %changelist%"。 - 脚本若有运行环境要求,要在 P4 服务器本机装好对应环境(需要 IT 开远程权限)。装 Python 这类时:
- 服务器上一切操作右键以管理员身份运行,否则可能不生效。
- 装 Python 时自定义安装目录并勾选加入环境变量;默认装到 user 目录下的话,即使勾了加入环境变量,在 P4 服务下也可能读不到。
- 如果脚本会往 P4V 输出日志,要在 P4V 里打开对应配置,否则看不到输出。
一个例子:提交触发 Jenkins 构建
用 admin 用户登录 P4。
把要执行的命令写进
xxx.bat,提交到 P4。在 P4V 里开 cmd,执行
p4 triggers打开 trigger 配置文件。写入一行:
UGSJenkinsPrecompile change-commit //test/test/... "%//test/test/add.bat% %changelist%"含义:每当有 changelist 提交到
//test/test/...,就执行 P4 上的add.bat。
在 Jenkins 里配置 SSL P4 连接
Jenkins P4 插件建 credential 有两种方式。前提:Jenkins 的 JDK 不能用 25 版本。
方式一:Perforce Password Credential。 密码不含特殊字符就正常填。含特殊字符的密码很容易出问题——Jenkins P4 插件测试连接时若把密码拼进命令行(如 p4 login),这些字符会导致认证失败:
| 字符 | 问题 |
|---|---|
| | Windows batch 里是管道符,会截断命令 |
^ | Windows batch 的转义字符 |
\ | 路径分隔符,某些上下文会被解析 |
' | 部分 shell/脚本里需要转义 |
方式二:Perforce Ticket Credential。 密码含特殊字符时改用 ticket 来配 credential,绕开命令行转义问题。
给 UE4 工程搭 P4
UE4 引擎及其生成数据体量大,优先考虑用 stream 以便扩展。
设置 Typemap(推荐默认值)
Typemap 决定 p4 add 时各类文件用什么 filetype。详见 p4 help typemap:
TypeMap:
binary+w //depot/....exe
binary+w //depot/....dll
binary+w //depot/....lib
binary+w //depot/....app
binary+w //depot/....dylib
binary+w //depot/....stub
binary+w //depot/....ipa
binary //depot/....bmp
text //depot/....ini
text //depot/....config
text //depot/....cpp
text //depot/....h
text //depot/....c
text //depot/....cs
text //depot/....m
text //depot/....mm
text //depot/....py
binary+l //depot/....uasset
binary+l //depot/....umap
binary+l //depot/....upk
binary+l //depot/....udk
binary+l //depot/....ubulk
手动改文件类型
如果上传资源前忘了设 typemap,得手动给部分文件补可写属性:登录 P4V,在 workspace 下对应文件夹右键 open Command windows here,执行:
p4 edit -c default -t +w //depot/....exe
p4 edit -c default -t +w //depot/....dll
p4 edit -c default -t +w //depot/....target
p4 edit -c default -t +w //depot/....modules
p4 edit -c default -t +w //depot/....lib
p4 edit -c default -t +w //depot/....app
p4 edit -c default -t +w //depot/....dylib
p4 edit -c default -t +w //depot/....stub
p4 edit -c default -t +w //depot/....ipa
然后提交 default pending list 里的文件。
在权限表里排除生成目录(重要)
UE4 的生成目录别提交进 P4,在 protect 表里加排除规则:
=open group Dev * -//<BranchName>/.../DerivedDataCache/...
list group Dev * -//<BranchName>/.../Intermediate/...
list group Dev * -//<BranchName>/.../obj/...
=write group Dev * -//<BranchName>/Code/.../Saved/...
DerivedDataCache 实际有一个随 UE4 自带的有效目录,用 =open(no open)规则即可;Saved 应该提交到 LatestBuilt 目录而非源码目录。
初始提交
- 把初始引擎 drop 提交到
//ProjectName/Code/...。 - 编译后,把第一份编译产物提交到
//ProjectName/Code/...。
出包
编译代码:
- Build:
//<BranchName>/Code/Engine/Build/BatchFiles/Build.bat - Rebuild:
//<BranchName>/Code/Engine/Build/BatchFiles/Rebuild.bat - 用法:
- Editor:
(Re)Build.bat <UE4ProjectName>Editor <Platform> <Configuration> <.uprojectPath> -waitmutex(更稳妥的做法是用 DevEnv 编译解决方案,确保 Editor 所需文件都被构建)。 - Game:
(Re)Build.bat <UE4ProjectName> <Platform> <Configuration> <.uprojectPath> -waitmutex。
- Editor:
启动 Editor 需要 UE4Editor-<UE4ProjectName>.dll,缺了就 Rebuild Editor。
归档 Editor(robocopy,排除 intermediate 与 pdb,32 线程):
robocopy <WorkRoot>\Engine\Binaries\Win64 <TargetPath>\Engine\Binaries\Win64 /E /XD intermediate /XF *.pdb /MT:32
robocopy <WorkRoot>\Engine\Plugins <TargetPath>\Engine\Plugins /E /XD intermediate /XF *.pdb /MT:32
robocopy <WorkRoot>\Game\Binaries\Win64 <TargetPath>\Game\Binaries\Win64 /E /XD intermediate /XF *.pdb /MT:32
robocopy <WorkRoot>\Game\Plugins <TargetPath>\Game\Plugins /E /XD intermediate /XF *.pdb /MT:32
Cook & Stage(脚本在 //<BranchName>/Code/Engine/Build/BatchFiles/RunUAT.bat):
RunUAT.bat BuildCookRun -project="<UE4ProjectName>" -platform=<Platform> -clientconfig=<Configuration> -cook -CookAll -stage -skipdeploy
出包:
RunUAT.bat -ScriptsForProject=<UE4ProjectName> BuildCookRun -nop4 -project=<UE4ProjectName> -cook -stage -archive -archivedirectory=<PackageOutputDir> -package -clientconfig=<Configuration> -ue4exe=UE4Editor-Cmd.exe -pak -prereqs -nodebuginfo -targetplatform=<Platform> -build -utf8output -nocompileeditor -compile
Cook & Stage & 出包合一,-iterate 表示只 cook 过期项(不加则删 sandbox 全量重 cook):
RunUAT.bat BuildCookRun -project=<UE4ProjectName> -noP4 -clientconfig=<Configuration> -utf8output -platform=<Platform> -build -cook -map=allmap -pak -iterativecooking -SkipCookingEditorContent -stage -package -compressed -stagingdirectory=<stageOutputDir> -archive -archivedirectory=<PackageOutputDir> -compile
只烘焙静态光:
UE4Editor-Cmd.exe <.uprojectPath> -run=resavepackages -buildlighting -MapsOnly -ProjectOnly -AllowCommandletRendering -Messaging
IncrediBuild 装了就会默认启用。一条经验:工程早期做几次增量构建后跑一次干净构建,能暴露文件大小写不一致这类导致内容意外变化的底层问题。白天用增量构建保证 CI 速度,夜里跑干净构建保证数据干净。