Subversion原理

Subversion(svn)通过版本号管理文件,每次commit产生新的全局版本号。存储包括结点表示文件或目录,使用Bubble-Up模型处理文件更新,通过Ancestor Node记录文件历史,差值存储节省空间。目录结构的变更以PLAIN或Delta形式存储,特别是Tree Delta用于目录结构变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


版本号

Subversion(以下简称svn)是使用版本号来区分不同的文件版本的。对于其来说,每一次commit都会生成一个新的版本号并且是全局的,为了保障这个性质,svn要求每一次数据操作都是原子的。如图:



这些文件者存在$repoBase$/repos/db/revs/ 目前下。

存储结点

Svn使用结点表示每一个文件或目录,其数据存储结构类似于文件系统但有又不一样的地方。

比如我们在svn里存了这么一个目录结构,版本为r1:

/

/project

/project/fileA.java

那么其在svn里的样子是:


fileA.java结点里存储的就是文件最终的值。这些结点满足以下条件:

1、 每个结点(node)只能是Directory或File;

2、 与linux不同,一个文件可以有多个parent,见下图;

3、 对于Directory里面存储的是指向下一级的指针,这些指针都存储在一个指针表(NodeTable)里;

4、 对于File里面是存储的文件数据;

5、 每一个node将会存储一个称为“先前版本序列(AncestorNode)”的这么一个文件

 

Bubble-Up模型

这里我们以文件更新为例。假设我们有一个工程,其目录结构如下:

/

/project

/project/sourceA.java

/project/sourceB.java

 


即里面有两个名为sourceA.java与sourceB.java的源文件。那么当我们初次commit时,svn里存储的结构如下:

 

我们可以看到,一个版本号在svn中对应的是整个目录的状态。现在假设我们对sourceA.java进行一些更改并提交上去,svn将会做如下工作:


而对于没有修改的文件,只需存储一个指上向一个版本的指针即可。那么最后得到的结果就是:


其它增加、删除操作也同理。从这里的结构我们可以看出,这种设计对于想找到某个文件的某个版本非常,只需要定位到对应的全局版本号即可。

Ancestor Node

现在我们着重来说一下“先前版本序列(Ancestor Node)”,以下简称AN。假如说文件经过3次更改提交后到版本4,那个它的AN里存储的数据则应该是:(R1,R2,R3),表明其是经过3个版本演进而来的。现在假设自版本1后,branch了一个分支,并提交了R4,R5,那么当branch合并(merge)后,AN应该是以下样子:


如果在R1同时还开了一个分支2,当分支1没合时,分支2合并时,trunk里AN存储的内容为:


 

如此一来,我们就可以很容易地知道某个文件的历史了。这样做还有一个好处,就是可以避免重复版本的合并问题。假如分支B1有R2,B2还有R2,那么在B1合并以后B2再合并就没有必须把B2的R2合进去了。svn的全局版本号会保证B1与B2的R2是绝对一样的。

差值存储

这里需要注意的是sourceB.java里并不是存的新版sourceB.java的全文件,而是delta值(就是差值)。Svn针对文件的类型使用了三种计算方法,即:

·        Text Delta:用于纯文件,例如源代码,使用的是V.Delta算法。具体算法可以参看:http://pdf.aminer.org/000/578/273/an_empirical_study_of_delta_algorithms.pdf中的3.4节

·        Property Delta:用于key-value类型的property文件

·        Tree Delta:用于目录结构

这里着重来说一下TreeDelta。注意:svn使用不同的文件系统(FSFSBerkeley DB)会有不同的结果。自svn1.2后,FSFS就成了默认的存储文件系统了,所以这里我们以FSFS来说明。我们还是用例子来说明,这样更容易理解。假设有下列目录结构:

/

/project/

/project/java

/project/resource

那么当我们将其提交到svn上后,treedelta里存的内容为:

<tree-delta>

  <open name='project'>

    <directory>

      <tree-delta>

        <open name='java'>

         <directory></directory>

        </open>

        <openname='resource'>

         <directory></directory>

        </open>

      </tree-delta>

    </directory>

  </open>

</tree-delta>

 

其中的意思我想都应该很明白,open标签即是表示新开一个结点的意思。除了open以外,还存在delete、add标签,相应的都比较容易理解。

这里需要对Delta值说明一下,svn里的delta只能用于从源文件A生成目标文件B,不能反过来。如图:

 

 

从上图我们可以知道,svn不是支持二进制文件delta值的,这种情况下,存的就是全新的文件了。

来看看svn实际存储的值

 上面说了几种delta,需要注意的是,一般对目录的添加、修改,svn并不是存的treedelta,而是存的PLAIN格式,至少svn1.6是这样的。举个例子:

首先我们创建一个空的repo,理所当然的里面只有根目录,即“/”,那么r0存的内容是:

PLAIN

END

ENDREP

id: 0.0.r0/17

type: dir

count: 0

text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e

cpath: /

17 107

那么这就是svn数据里的一个结点(node),也就是说r0版本只有一个dir,叫“/”,也就是根。现在我们添加

/project/

/project/java

/project/resource

三个目录,则r1里存储的为:

PLAIN

K 14

bugtraq:number

V 4

true

END

ENDREP

id: 0-1.0.r1/46

type: dir

count: 0

props: 1 0 33 0 47292cf701b9dafc4b652bbcff41d55d

cpath: /java

copyroot: 0 /

 

PLAIN

K 14

bugtraq:number

V 4

true

END

ENDREP

id: 2-1.0.r1/204

type: dir

count: 0

props: 1 158 33 0 47292cf701b9dafc4b652bbcff41d55d

cpath: /resources

copyroot: 0 /

 

PLAIN

K 4

java

V 15

dir 0-1.0.r1/46

K 9

resources

V 16

dir 2-1.0.r1/204

END

ENDREP

id: 0.0.r1/407

type: dir

pred: 0.0.r0/17

count: 1

text: 1 324 70 70 4f979dc380d411aa56da7a2152951989

cpath: /

copyroot: 0 /

 

_0.0.t0-0 add-dir false true /java

 

_2.0.t0-0 add-dir false true /resources

 

407 532

从上面可以清楚看出,最后一条结点记录了“/”添加了“java”与“resource”两个目录(红色部分), 而前面两个记录则记录了java与resource文件夹的信,第三个结点的pred即AN(AncestorNode)下一次,所以AN在这里是以链表的形式存储的。总的来说这里也非常符合上面的bubble-up模型。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值