先啰嗦下为什么要使用svndumpfilter…

svn库用久了以后就会越来越大,进行整体文件打包备份的时候,发现压力山大…尤其是美术团队也在使用svn进行重要美术资源管理的时候…….几百g的资源同步备份的盛况对于机器来说是难以承受的压力,尤其是当存在多种备份方式(比如本地多机器拷贝、远程机器上传备份)。几十kb的速度去承担几百g的备份是痛苦的事情。

公司的运维又不给力,围观了下他们部署在我们服务器的批处理备份代码,就一个简单的对svn的仓库目录直接用winrar压缩,然后用rsync同步,这是多么粗糙的方案,当然也不是说错误,只是说过于暴力了点,且可控性太差,当想要过滤某些文件的时候就无法实现了。

一开始我想的方案也是压缩打包,用python实现,这样过滤文件的时候,可以在逻辑上加处理,这样可以屏蔽下想要过滤的东西,代码如下:

#-*- coding=gbk -*-

import tarfile
import os
import time
import threading
import datetime
import shutil
import subprocess
from myEmail import Mailer ignoreNames = ["ArtGroup", ".svn"]
TargetDir = "D:\\02_ucgame_Svn_Repositories"
BackUp = "svn_backup_%s.tar.gz"
ShareDir = "z:\\backup"
mailTitle = "[UCCDTest] svn backup analyze %s"
receivers = [
"account@qq.com",
"account@qq.com", "account@qq.com", "account@qq.com", ]
def delShareFile():
# 删除共享文件夹里的备份文件
# 该文件夹路径为z:\\backup,里面均是压缩文件包
# 故,删除策略为反向排序,取文件的修改时间作为排序的关键字处理
# 删除时,保留最新的3个文件
files = [os.path.join(ShareDir, x) for x in os.listdir(ShareDir)]
if len(files) > 2:
sorted(files, key = lambda file:os.stat(file).st_mtime, reverse = True)
DelFiles = files[:-2]
for nfile in DelFiles:
os.remove(nfile) def delLocalFile():
# 删除本地文件夹里的备份文件
# 该文件夹路径为当前脚本所在路径,里面均是压缩文件包
# 故,删除策略为反向排序,取文件的修改时间作为排序的关键字处理
# 删除时,保留最新的1个文件(不删除该文件的目的是,避免误操作的文件丢失,同时,为后续操作保留一个缓存文件)
files = [os.path.join(os.getcwd(), x) for x in os.listdir(".") if "svn_backup" in x]
if len(files) > 1:
sorted(files, key = lambda file:os.stat(file).st_mtime, reverse = True)
DelFiles = files[:-1]
for nfile in DelFiles:
os.remove(nfile) def addFile(tf, files, root):
# 往压缩包里面添加文件,在添加时,均处理过文件的地址,添加了替换的replace方法的目的是相对路径时,避免出现多余的符号
st = time.time()
length = len(files)
for ids, nfile in enumerate(files):
if time.time() - st >= 3:
print "\radding file at root [%s]: [%s / %s], package is [%s MB]" % (root, ids, length, os.stat(tarPackage).st_size / (1024 * 1024))
st = time.time()
fp = os.path.join(root, nfile).replace(".\\","")
key = root.split("\\")
if len(key) > 1:
key = key[1]
if key not in ret:
ret[key] = os.stat(fp).st_size
else:
ret[key] += os.stat(fp).st_size
tf.add(fp) def checkDir(Names):
# 检测需要过滤得文件名或路径名,这里主要用来过滤svn主路径下的特殊文件夹名字
for nName in ignoreNames:
if nName not in Names:
pass
else:
return False
return True def maketar(dist, tar):
# 扫描缓存文件夹,对待处理的文件夹进行过滤,并调用添加方法,将待压缩文件添加到压缩包内
st = time.time()
cur = os.getcwd()
os.chdir(dist) for root, dir, files in os.walk("."):
if not checkDir(root):
continue
addFile(tar, files, root)
tar.close()
os.chdir(cur) def uploadFile(tar):
args = ["rsync","-avzPu", "--password-file=passwd.pd","<p.txt", "svn_backup_*", "cwRsync@127.0.0.0::mysvnbackup"]
os.system("".join(args))
#p = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
#print p.communicate()[1]
#print p.stderr.read() def getMailBody(rd):
msg = '<table border=""><tr><th>RootDirName</th><th>PackageSize</th></tr>' for nk in sorted(rd.items(), key = lambda pair: pair[1], reverse = True):
if nk[1] < 1024:
msg += '<tr><td>%s</td><td>%.2fByte</td></tr>' % (nk[0], float(nk[1]))
elif nk[1] < 1024 * 1024:
msg += '<tr><td>%s</td><td>%.2fKB</td></tr>' % (nk[0], float(nk[1]) / 1024)
elif nk[1] < 1024 * 1024 *1024:
msg += '<tr><td>%s</td><td>%.2fMB</td></tr>' % (nk[0], float(nk[1]) / ( 1024 * 1024 ))
else:
msg += '<tr><td>%s</td><td><font color="red">%.2fGB</font></td></tr>' % (nk[0], float(nk[1]) / ( 1024 * 1024 * 1024 )) msg+= '</table>'
return msg global ret
ret = {}
# 获取时间参数,用来评估多线程实现的模块的性能,暂时无用,详见makeTar_multipleThreads.py
st = time.time()
# 获取当前日期,用于生成压缩包的名字
ts = datetime.datetime.now().strftime("%Y-%m-%d")
mailTitle = mailTitle % ts
# 开始打包 print "start making package."
tarPackage = os.path.join(os.getcwd(), BackUp % ts)
tar = tarfile.open(tarPackage, "w:gz")
maketar(TargetDir, tar)
print "finished making package. used time - %s" % (time.time() - st)
# 分析文件夹状态,发送邮件
mailer = Mailer()
msg = getMailBody(ret)
for nmail in receivers:
mailer.send(nmail, mailTitle, msg)
print "send mail to ", nmail # 删除z盘的备份文件
delShareFile()
# 上传备份文件到z盘
shutil.copy(tarPackage, ShareDir)
uploadFile(tarPackage)
# 删除本地的文件
delLocalFile()

仅仅实现了过滤备份并不靠谱,因为svn里面的资源和版本其实仍然在,直接找到svn文件夹,删除文件当然也可以,但是会导致svn库里面出现空版本或其他问题,所以还是要利用svn本身的管理工具去处理。搜索了半天,发现了svndumpfilter,可以利用他的exclude指令去过滤文件,然后把过滤后的文件结构导入svn即可,但实际按网又介绍的又各种出错,一般都是什么错误的文件头,如下图

反复研究和google尝试(baidu查不到的只能找google了)后,终于确认下列的流程是可以操作的:

1. 使用svnadmin把整个要处理的svn库的项目导出来

命令为:svnadmin dump repos1 > repos1.dump

repos1 为你的对应库名,repos1.dump为导出的文件名,可以随意命名,只要自己记得。

2. 使用svndumpfilter exclude命令过滤项目中废弃的文件夹,可以填写多个文件路径,该命令是根据路径名字过滤的。

命令为:svndumpfilter exlude directory1 directory2 directory3 <repos1.dump> filtered-repos1.dump

如上,路径可以随意填写,但一定要正确存在,比如你导出的是/test/test1,你要过滤的是test1下面的test2,那么这里的directory1应该写为test1/test2,如果还有其他要一并过滤的,可以空格添加其他directory2,directory3即可。

注意,路径中如果包含有空格等,需要用双引号包起来。避免识别错误。

路径配置完成后,一定要用<>把之前第一步导出来的备份dump文件括起来,表示过滤是在该文件的结构中进行。

而最后一个filtered-repos1.dump文件就很好理解了,就是过滤出来的新的结构备份文件。

过滤后的效果如下图:

3. 之后再新建一个库,导进去即可,如果要继续使用原来的库名,将原来的库删除后重建,导入即可,导入命令用svnadmin load。

当然备份打包还可以用svn推荐的svnadmin dump或svnadmin hotcopy文件备份,但速度太慢,还是直接整体文件拷贝比较快,虽然不够合理,但如果选择完全没人操作的时间还是可以的,这样恢复也快。对于我们的项目来说,目前还是选用文件打包备份快点,也可以和运维那边的管理方式结合起来,省的麻烦。。

使用svndumpfilter exclude来清理svn库的废弃文件实现差别备份的更多相关文章

  1. SVN库迁移整理方法总结

    有时候需要从一台机器迁移svn存储库到另外一台机器,如果数据量非常大的话,没有好的方法是很不方便的,其实迁移svn跟迁移mysql差不多,也有导出导入的方案 以下是subversion官方推荐的备份方 ...

  2. SVN库迁移整理方法----官方推荐方式

    以下是subversion官方推荐的备份方式. 关闭所有运行的进程,并确认没有程序在访问存储库(如 httpd.svnserve 或本地用户在直接访问). 备份svn存储库 #压缩备份 svnadmi ...

  3. 彻底删除SVN版本库中部分文件或文件夹

    例:假设SVN库路径为E:/svn/project,库中的目录结构为 QA/Trunk Software/Tags/test.exe 删除Software/Tags/目录下的test.exe文件 操作 ...

  4. 在Eclipse中导入SVN库里的Maven项目

    长期使用Intellij 对于Eclipse的东西都生疏了... 做了个小教程说明Eclipse下导入Maven工程的步骤以备不时之需 1. 安装maven插件 a) 下载maven http://m ...

  5. SVN库实时同步设置

    为了安全起见,SVN服务器除了做定时全量备份和增量备份以外,如条件允许,可做实时备份. 这需要2台机器,一台是master server,另一台做mirror server.master做主服务,mi ...

  6. SVN库迁移过程总结

    一.背景:老SVN是安装在32位服务器上:现在64位服务器上安装了新版本SVN服务,所以需要将SVN从老服务器上迁移到新服务器上. 1.SVN Server下载:https://www.visuals ...

  7. SVN库迁移

    最后库迁移.机会主义的,在源库资源,然后上传到目标库,最后client更新url地址.的库被组长一眼识破,由于新库中没有大家的操作日志. 这次吸取上次的教训,用dump和load完毕SVN库迁移. 整 ...

  8. 通过重建清理SVN服务器无用目录,不丢失其他目录修改记录

    1.主要时有时间希望调整一些文件的目录结构,或者移除一个大量占用空间的文件节省服务器磁盘,但是又不希望调整后,对应的修改记录丢失.这时可以通过服务器目录重建实现. 2.重建后只是被排除掉的目录的修改记 ...

  9. 清理svn.bat

     @echo on  color 2f  mode con: cols=80 lines=25  @REM  @echo 正在清理SVN文件,请稍候......  @rem 循环删除当前目录及子目录下 ...

随机推荐

  1. 2019-7-22-Roslyn-获得-sln-文件所在的文件夹

    title author date CreateTime categories Roslyn 获得 sln 文件所在的文件夹 lindexi 2019-07-22 08:57:14 +0800 201 ...

  2. keep-alive vue组件缓存避免多次加载相应的组件

    keep-alive vue组件缓存避免多次加载相应的组件

  3. vscode golang vue配置

    { "files.autoSave": "off", "window.title": "${dirty}${activeEdito ...

  4. behavior planning——14.implement a cost function in C++

    n most situations, a single cost function will not be sufficient to produce complex vehicle behavior ...

  5. Project Euler Problem 16-Power digit sum

    直接python搞过.没啥好办法.看了下别人做的,多数也是大数乘法搞过. 如果用大数做的话,c++写的话,fft优化大数乘法,然后快速幂一下就好了.

  6. settTimeout vs setInterval

    setTimeout:过一段固定的时间后,将代码提交到代码队列中排队. setInterval:每隔一段固定的时间,执行一次代码. 他们两都接受两个参数,第一个参数是字符串或者函数,第二个参数是设定的 ...

  7. Object类型的创建和访问

    创建Object实例的方式有两种: 1.使用new操作符后跟object构造函数 var person=new Object(); person.name='Nicholas'; person.age ...

  8. Python--day63--单表的增删改查/GET和POST/request相关知识点回顾

  9. HDU 3746 Cyclic Nacklace(kmp next数组运用)

    Cyclic Nacklace Problem Description CC always becomes very depressed at the end of this month, he ha ...

  10. Spring Boot实战之单元测试

    Spring Boot实战之单元测试 本文介绍使用Spring测试框架提供的MockMvc对象,对Restful API进行单元测试 Spring测试框架提供MockMvc对象,可以在不需要客户端-服 ...