Due largely to the simplicity of the overall design of the Subversion repository and the technologies on which it relies, creating and configuring a repository are fairly straightforward tasks. There are a few preliminary decisions you'll want to make, but the actual work involved in any given setup of a Subversion repository is pretty basic, tending toward mindless repetition if you find yourself setting up multiples of these things.
下面是一些你需要预先考虑的事情:
你的版本库将要存放什么数据(或多个版本库),这些数据如何组织?
版本库存放在哪里,如何被访问?
你需要什么类型的访问控制和版本库事件报告?
你希望使用哪种数据存储方式?
在本节,我们要尝试帮你回答这些问题。
While Subversion allows you to move around versioned files and directories without any loss of information, and even provides ways of moving whole sets of versioned history from one repository to another, doing so can greatly disrupt the workflow of those who access the repository often and come to expect things to be at certain locations. So before creating a new repository, try to peer into the future a bit; plan ahead before placing your data under version control. By conscientiously “laying out” your repository or repositories and their versioned contents ahead of time, you can prevent many future headaches.
Let's assume that as repository administrator, you will be responsible for supporting the version control system for several projects. Your first decision is whether to use a single repository for multiple projects, or to give each project its own repository, or some compromise of these two.
There are benefits to using a single repository for multiple projects, most obviously the lack of duplicated maintenance. A single repository means that there is one set of hook programs, one thing to routinely back up, one thing to dump and load if Subversion releases an incompatible new version, and so on. Also, you can move data between projects easily, without losing any historical versioning information.
The downside of using a single repository is that different projects may have different requirements in terms of the repository event triggers, such as needing to send commit notification emails to different mailing lists, or having different definitions about what does and does not constitute a legitimate commit. These aren't insurmountable problems, of course—it just means that all of your hook scripts have to be sensitive to the layout of your repository rather than assuming that the whole repository is associated with a single group of people. Also, remember that Subversion uses repository-global revision numbers. While those numbers don't have any particular magical powers, some folks still don't like the fact that even though no changes have been made to their project lately, the youngest revision number for the repository keeps climbing because other projects are actively adding new revisions.[31]
A middle-ground approach can be taken, too. For example, projects can be grouped by how well they relate to each other. You might have a few repositories with a handful of projects in each repository. That way, projects that are likely to want to share data can do so easily, and as new revisions are added to the repository, at least the developers know that those new revisions are at least remotely related to everyone who uses that repository.
After deciding how to organize your
projects with respect to repositories, you'll probably want to think about
directory hierarchies within the repositories themselves. Because
Subversion uses regular directory copies for branching and tagging (see
第 4 章 分支与合并), the Subversion community recommends that
you choose a repository location for each project root—the
“topmost” directory that contains data related to that
project—and then create three subdirectories beneath that root:
trunk
, meaning the directory under which the main
project development occurs; branches
, which is a
directory in which to create various named branches of the main development
line; and tags
, which is a collection of tree snapshots
that are created, and perhaps destroyed, but never changed.[32]
举个例子,你的版本库可能如下布局:
/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ spreadsheet/ trunk/ tags/ branches/ …
Note that it doesn't matter where in your repository each project root is. If you have only one project per repository, the logical place to put each project root is at the root of that project's respective repository. If you have multiple projects, you might want to arrange them in groups inside the repository, perhaps putting projects with similar goals or shared code in the same subdirectory, or maybe just grouping them alphabetically. Such an arrangement might look like this:
/ utils/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ … office/ spreadsheet/ trunk/ tags/ branches/ …
Lay out your repository in whatever way you see fit. Subversion does not expect or enforce a particular layout—in its eyes, a directory is a directory is a directory. Ultimately, you should choose the repository arrangement that meets the needs of the people who work on the projects that live there.
In the name of full disclosure, though, we'll mention another very common
layout. In this layout, the trunk
,
tags
, and branches
directories
live in the root directory of your repository, and your projects are in
subdirectories beneath those, like so:
/ trunk/ calc/ calendar/ spreadsheet/ … tags/ calc/ calendar/ spreadsheet/ … branches/ calc/ calendar/ spreadsheet/ …
There's nothing particularly incorrect about such a layout, but it may or may not seem as intuitive for your users. Especially in large, multiproject situations with many users, those users may tend to be familiar with only one or two of the projects in the repository. But the projects-as-branch-siblings approach tends to deemphasize project individuality and focus on the entire set of projects as a single entity. That's a social issue, though. We like our originally suggested arrangement for purely practical reasons—it's easier to ask about (or modify, or migrate elsewhere) the entire history of a single project when there's a single repository path that holds the entire history—past, present, tagged, and branched—for that project and that project alone.
Before creating your Subversion repository, an obvious question you'll need to answer is where the thing is going to live. This is strongly connected to myriad other questions involving how the repository will be accessed (via a Subversion server or directly), by whom (users behind your corporate firewall or the whole world out on the open Internet), what other services you'll be providing around Subversion (repository browsing interfaces, email-based commit notification, etc.), your data backup strategy, and so on.
We cover server choice and configuration in 第 6 章 服务配置, but the point we'd like to briefly make here is simply that the answers to some of these other questions might have implications that force your hand when deciding where your repository will live. For example, certain deployment scenarios might require accessing the repository via a remote filesystem from multiple computers, in which case (as you'll read in the next section) your choice of a repository backend data store turns out not to be a choice at all because only one of the available backends will work in this scenario.
Addressing each possible way to deploy Subversion is both impossible and outside the scope of this book. We simply encourage you to evaluate your options using these pages and other sources as your reference material and to plan ahead.
Subversion provides two options for the type of underlying data store—often referred to as “the backend” or, somewhat confusingly, “the (versioned) filesystem”—that each repository uses. One type of data store keeps everything in a Berkeley DB (or BDB) database environment; repositories that use this type are often referred to as being “BDB-backed.” The other type stores data in ordinary flat files, using a custom format. Subversion developers have adopted the habit of referring to this latter data storage mechanism as FSFS[33]—a versioned filesystem implementation that uses the native OS filesystem directly—rather than via a database library or some other abstraction layer—to store data.
表 5.1 “版本库数据存储对照表” gives a comparative overview of Berkeley DB and FSFS repositories.
表 5.1. 版本库数据存储对照表
分类 | 特性 | Berkeley DB | FSFS |
---|---|---|---|
可靠性 | 数据完整性 | 当正确部署时非常可靠;Berkeley DB 4.4 支持自动恢复 | 较老的版本有较少被证实的数据毁坏 bug |
对操作中断的敏感 | Very; crashes and permission problems can leave the database “wedged,” requiring journaled recovery procedures | 十分迟钝 | |
可用性 | 可只读加载 | 否 | 是 |
存储平台无关 | 否 | 是 | |
可从网络文件系统访问 | 通常,不 | 是 | |
组访问权处理 | 对于用户的 umask 设置十分敏感;最好只由一个用户访问 | umask 问题的解决方案 | |
伸缩性 | 版本库磁盘使用情况 | 较大(特别是没有清除日志时) | 较小 |
修订版本树的数量 | 数据库;没有问题 | Some older native filesystems don't scale well with thousands of entries in a single directory | |
有很多文件的目录 | 较慢 | 较快 | |
性能 | 检出最新的代码 | 没有任何有意义的差异 | 没有任何有意义的差异 |
大的提交 | 整体较慢,但是在整个提交周期中消耗被分摊 | 较快,但是最后较长的延时可能会导致客户端操作超时 |
There are advantages and disadvantages to each of these two backend types. Neither of them is more “official” than the other, though the newer FSFS is the default data store as of Subversion 1.2. Both are reliable enough to trust with your versioned data. But as you can see in 表 5.1 “版本库数据存储对照表”, the FSFS backend provides quite a bit more flexibility in terms of its supported deployment scenarios. More flexibility means you have to work a little harder to find ways to deploy it incorrectly. Those reasons—plus the fact that not using Berkeley DB means there's one fewer component in the system—largely explain why today almost everyone uses the FSFS backend when creating new repositories.
Fortunately, most programs that access Subversion repositories are blissfully ignorant of which backend data store is in use. And you aren't even necessarily stuck with your first choice of a data store—in the event that you change your mind later, Subversion provides ways of migrating your repository's data into another repository that uses a different backend data store. We talk more about that later in this chapter.
下面的小节提供了数据存储类型更加详细的介绍。
When the initial design phase of Subversion was in progress, the developers decided to use Berkeley DB for a variety of reasons, including its open source license, transaction support, reliability, performance, API simplicity, thread safety, support for cursors, and so on.
Berkeley DB provides real transaction support—perhaps its most powerful feature. Multiple processes accessing your Subversion repositories don't have to worry about accidentally clobbering each other's data. The isolation provided by the transaction system is such that for any given operation, the Subversion repository code sees a static view of the database—not a database that is constantly changing at the hand of some other process—and can make decisions based on that view. If the decision made happens to conflict with what another process is doing, the entire operation is rolled back as though it never happened, and Subversion gracefully retries the operation against a new, updated (and yet still static) view of the database.
Another great feature of Berkeley DB is hot backups—the ability to back up the database environment without taking it “offline.” We'll discuss how to back up your repository later in this chapter (in 第 4.8 节 “版本库备份”), but the benefits of being able to make fully functional copies of your repositories without any downtime should be obvious.
Berkeley DB is also a very reliable database system when properly used. Subversion uses Berkeley DB's logging facilities, which means that the database first writes to on-disk logfiles a description of any modifications it is about to make, and then makes the modification itself. This is to ensure that if anything goes wrong, the database system can back up to a previous checkpoint—a location in the logfiles known not to be corrupt—and replay transactions until the data is restored to a usable state. See 第 4.3 节 “管理磁盘空间” later in this chapter for more about Berkeley DB logfiles.
But every rose has its thorn, and so we must note some known limitations of Berkeley DB. First, Berkeley DB environments are not portable. You cannot simply copy a Subversion repository that was created on a Unix system onto a Windows system and expect it to work. While much of the Berkeley DB database format is architecture-independent, other aspects of the environment are not. Second, Subversion uses Berkeley DB in a way that will not operate on Windows 95/98 systems—if you need to house a BDB-backed repository on a Windows machine, stick with Windows 2000 or later.
While Berkeley DB promises to behave correctly on network shares that meet a particular set of specifications,[34] most networked filesystem types and appliances do not actually meet those requirements. And in no case can you allow a BDB-backed repository that resides on a network share to be accessed by multiple clients of that share at once (which quite often is the whole point of having the repository live on a network share in the first place).
警告 | |
---|---|
If you attempt to use Berkeley DB on a noncompliant remote filesystem, the results are unpredictable—you may see mysterious errors right away, or it may be months before you discover that your repository database is subtly corrupted. You should strongly consider using the FSFS data store for repositories that need to live on a network share. |
Finally, because Berkeley DB is a library linked directly into Subversion, it's more sensitive to interruptions than a typical relational database system. Most SQL systems, for example, have a dedicated server process that mediates all access to tables. If a program accessing the database crashes for some reason, the database daemon notices the lost connection and cleans up any mess left behind. And because the database daemon is the only process accessing the tables, applications don't need to worry about permission conflicts. These things are not the case with Berkeley DB, however. Subversion (and programs using Subversion libraries) access the database tables directly, which means that a program crash can leave the database in a temporarily inconsistent, inaccessible state. When this happens, an administrator needs to ask Berkeley DB to restore to a checkpoint, which is a bit of an annoyance. Other things can cause a repository to “wedge” besides crashed processes, such as programs conflicting over ownership and permissions on the database files.
注意 | |
---|---|
Berkeley DB 4.4 brings (to Subversion 1.4 and later) the ability for Subversion to automatically and transparently recover Berkeley DB environments in need of such recovery. When a Subversion process attaches to a repository's Berkeley DB environment, it uses some process accounting mechanisms to detect any unclean disconnections by previous processes, performs any necessary recovery, and then continues on as though nothing happened. This doesn't completely eliminate instances of repository wedging, but it does drastically reduce the amount of human interaction required to recover from them. |
So while a Berkeley DB repository is quite fast and scalable, it's best used
by a single server process running as one user—such as Apache's
httpd or svnserve (see 第 6 章 服务配置)—rather than accessing it as many
different users via file://
or
svn+ssh://
URLs. If you're accessing a Berkeley DB
repository directly as multiple users, be sure to read 第 7 节 “支持多种版本库访问方法” later in this chapter.
In mid-2004, a second type of repository storage system—one that doesn't use a database at all—came into being. An FSFS repository stores the changes associated with a revision in a single file, and so all of a repository's revisions can be found in a single subdirectory full of numbered files. Transactions are created in separate subdirectories as individual files. When complete, the transaction file is renamed and moved into the revisions directory, thus guaranteeing that commits are atomic. And because a revision file is permanent and unchanging, the repository also can be backed up while “hot,” just like a BDB-backed repository.
The FSFS revision files describe a revision's directory structure, file contents, and deltas against files in other revision trees. Unlike a Berkeley DB database, this storage format is portable across different operating systems and isn't sensitive to CPU architecture. Because no journaling or shared-memory files are being used, the repository can be safely accessed over a network filesystem and examined in a read-only environment. The lack of database overhead also means the overall repository size is a bit smaller.
FSFS has different performance characteristics, too. When committing a directory with a huge number of files, FSFS is able to more quickly append directory entries. On the other hand, FSFS has a longer delay when finalizing a commit while it performs tasks that the BDB backend amortizes across the lifetime of the commit, which could in extreme cases cause clients to time out while waiting for a response.
The most important distinction, however, is FSFS's imperviousness to wedging when something goes wrong. If a process using a Berkeley DB database runs into a permissions problem or suddenly crashes, the database can be left in an unusable state until an administrator recovers it. If the same scenarios happen to a process using an FSFS repository, the repository isn't affected at all. At worst, some transaction data is left behind.
[31] 无论是在忽略情况下建立或很少考虑过如何产生正确的软件开发矩阵,都不应该愚蠢的担心全局的修订版本号码,这不应该成为安排项目和版本库的理由。
[32] The trunk
, tags
, and
branches
trio is sometimes referred to as “the
TTB directories.”
[33] Often pronounced “fuzz-fuzz,” if Jack Repenning has anything to say about it. (This book, however, assumes that the reader is thinking “eff-ess-eff-ess.”)
[34] Berkeley DB需要底层的文件系统实现严格的POSIX锁定语法,更重要的是,将文件直接映射到内存的能力。