C#使用SharpSVN时SVN Clean up执行条件与工作副本锁检测方法
什么时候需要在C# SharpSVN逻辑中执行SVN Clean up
满足以下任意一种情况时再执行Clean up即可,不要把Clean up当成每次操作前的必走流程,会平白增加操作耗时:
- 任意SVN操作(更新、提交、切换分支、合并、加解锁、属性修改等)抛出
SvnException,且错误码匹配工作副本锁相关类型、或异常文本包含working copy path locked、previous operation has not finished、database is locked内容时 - 程序执行SVN操作过程中出现非预期中断(进程崩溃、系统掉电、网络异常导致操作中途退出),重启后首次操作工作副本前
- 排查确认没有任何进程(包括自己程序的其他线程、外部SVN客户端如TortoiseSVN)正在占用工作副本文件,但SVN操作持续返回路径被占用、无法执行的错误时
- 工作副本状态查询返回条目错乱、时间戳不匹配的异常,排除文件被业务进程手动篡改的场景时
执行Clean up时记得把对应参数开全,否则可能清不掉残留锁,示例调用:
using (var client = new SvnClient()) { SvnCleanUpArgs cleanArgs = new SvnCleanUpArgs { BreakLocks = true, // 强制清除残留锁 ClearDavCache = true, // 清理网络操作缓存 FixTimestamps = true, // 修复文件时间戳异常 IncludeExternals = true, // 递归处理外部引用目录 VacuumPristines = true // 清理无用的原始版本缓存 }; client.CleanUp(wcPath, cleanArgs); }
如何正确检测工作目录的锁定异常状态
不要靠匹配文件夹下有没有lock文件这类非官方方法,按以下步骤检测可以覆盖99%的场景,还能避免误判:
- 先排除正常锁场景:SVN执行操作时本身会加临时锁,这时候的锁是正常的,不需要Clean up。检测时先尝试以独占读写方式打开工作副本下的
.svn/wc.db文件,如果打开时抛出IO占用异常,说明有其他SVN进程/线程正在操作该工作副本,等待操作完成锁会自动释放,不属于异常锁定。 - 用原生接口做轻量探测:调用
SvnClient.GetStatus()方法,将探测深度设为SvnDepth.Empty(只查根目录状态,不递归所有文件,速度极快),如果调用时抛出SvnException,匹配以下错误码即可判定为异常锁定:SvnErrorCode.SVN_ERR_WC_LOCKED:工作副本被残留锁标记占用SvnErrorCode.SVN_ERR_SQLITE_BUSY:工作副本元数据库被残留锁占用SvnErrorCode.SVN_ERR_WC_CORRUPT:锁标记导致元数据损坏
- 不要用全量更新、全量状态扫描这类重操作做检测,会浪费大量时间,轻量探测耗时一般在10ms以内。
对应的检测代码示例:
/// <summary> /// 检测工作副本是否存在异常锁定 /// </summary> /// <param name="wcPath">工作副本路径</param> /// <param name="isOtherProcessRunning">是否有其他进程正在执行SVN操作(此时锁为正常状态)</param> /// <returns>存在异常锁定需要Clean up时返回true</returns> public bool IsWcHasAbnormalLock(string wcPath, out bool isOtherProcessRunning) { isOtherProcessRunning = false; string wcDbPath = Path.Combine(wcPath, ".svn", "wc.db"); // 第一步:检测是否有其他进程占用元数据库 try { using (var fs = File.Open(wcDbPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { fs.Close(); } } catch (IOException) { isOtherProcessRunning = true; return false; } // 第二步:轻量调用SVN接口探测状态 using (var client = new SvnClient()) { var statusArgs = new SvnStatusArgs { Depth = SvnDepth.Empty, RetrieveAllEntries = false }; try { client.GetStatus(wcPath, statusArgs, out _); return false; } catch (SvnException ex) { if (ex.SubversionErrorCode is SvnErrorCode.SVN_ERR_WC_LOCKED or SvnErrorCode.SVN_ERR_SQLITE_BUSY or SvnErrorCode.SVN_ERR_WC_CORRUPT) { return true; } // 其他错误不属于锁异常,直接抛出由上层业务处理 throw; } } }
内容的提问来源于stack exchange,提问作者Ankush
相关产品推荐
相关产品推荐

