{"id":1741,"date":"2022-04-04T07:44:40","date_gmt":"2022-04-04T07:44:40","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/?p=1741"},"modified":"2022-12-23T06:19:51","modified_gmt":"2022-12-23T06:19:51","slug":"svn-mirror-for-live-back-up-high-availability","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/svn-mirror-for-live-back-up-high-availability\/","title":{"rendered":"SVN Mirror for Live back-up &#038; SVN High Availability"},"content":{"rendered":"\n<p>Here are three ways to create a full mirror of a&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>&nbsp;repository:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Treat the repository like any other filesystem and recursively copy it to the mirror location.<\/li><li>Use&nbsp;<a href=\"http:\/\/svnbook.red-bean.com\/en\/1.2\/svn.ref.svnadmin.c.dump.html\" target=\"_blank\" rel=\"noopener\">svnadmin dump<\/a>&nbsp;and&nbsp;<a href=\"http:\/\/svnbook.red-bean.com\/en\/1.2\/svn.ref.svnadmin.c.load.html\" target=\"_blank\" rel=\"noopener\">svnadmin load<\/a>.<\/li><li>Use&nbsp;<a href=\"http:\/\/svnbook.red-bean.com\/en\/1.2\/svn.ref.svnadmin.c.hotcopy.html\" target=\"_blank\" rel=\"noopener\">svnadmin hotcopy<\/a>.<\/li><\/ol>\n\n\n\n<p>There are important differences between these three strategies.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"treating-the-repository-as-a-filesystem\">Treating the Repository as a Filesystem<\/h4>\n\n\n\n<p>You can of course:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cp -R PATH_TO_REPOS PATH_TO_MIRROR<\/pre>\n\n\n\n<p>This is a bad idea if the repository is in use \u2014 you\u2019re copying a moving target \u2014 so you\u2019ll have to take down the&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>&nbsp;server while making the mirror. If you\u2019re prepared to accept this downtime, netcat,&nbsp;<code>nc<\/code>, combined with&nbsp;<code>tar<\/code>&nbsp;is a neat way to recursively copy a directory across a network connection using TCP\/IP.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># On the destination \"mirror\" machine<br>nc -l -p 2345 | tar xv<br># On the source machine<br>tar c PATH_TO_REPOS &gt; \/dev\/tcp\/DOTTED.IP.OF.MIRROR\/2345<\/pre>\n\n\n\n<p>Here,&nbsp;<code>2345<\/code>&nbsp;has been chosen as a suitable port for the data transfer.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"using-svnadmin-dump-and-load\">Using Svnadmin Dump and Load<\/h4>\n\n\n\n<p>Perhaps the most obvious way to mirror a&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>&nbsp;repository is to combine&nbsp;<code>svnadmin dump<\/code>&nbsp;with&nbsp;<code>svadmin load<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">svnadmin dump PATH_TO_REPOS | svnadmin load PATH_TO_MIRROR<\/pre>\n\n\n\n<p>Run on its own,&nbsp;<code>svnadmin dump<\/code>&nbsp;is designed to create a portable repository dump. The resulting dumpfile can be loaded into a new&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>&nbsp;repository \u2014 even if the new repository is using a different database backend, or even a different revision of&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>.&nbsp;<code>Svnadmin dump<\/code>&nbsp;will happily run on a live repository (no need to take the server down).<\/p>\n\n\n\n<p>In short, combining&nbsp;<code>svnadmin dump<\/code>&nbsp;with&nbsp;<code>svnadmin load<\/code>&nbsp;is probably more powerful than we need if we just want to mirror our repository to a new location.&nbsp;<code>Svnadmin dump<\/code>&nbsp;\u2014 on its own \u2014 is the best way to fully backup a repository, since the dumpfile it creates is portable (as described above). If we replicate a repository by piping&nbsp;<code>svnadmin dump<\/code>&nbsp;to&nbsp;<code>svnadmin load<\/code>, we lose the dumpfile in the pipeline and do far more work than we need to.<\/p>\n\n\n\n<p>Actually, it\u2019s the computer which does the work \u2014 we just type a command and let it run. As a rough guideline, I have worked on a repository which occupies about 10Gb on disk, contains ~50K files and maybe a hundred branches. To dump and load this repository takes about 4 hours. A recursive copy completes in a few minutes.<\/p>\n\n\n\n<p>One more point:&nbsp;<code>svnadmin dump<\/code>&nbsp;does not dump your repository configuration files and hook scripts. If your backup strategy is based around these commands, you will need separate arrangements for backing up hook scripts and configuration files.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"using-svnadmin-hotcopy\">Using Svnadmin Hotcopy<\/h4>\n\n\n\n<p>The third option combines the best features of the previous two. Using&nbsp;<code>svnadmin hotcopy<\/code>&nbsp;doesn\u2019t require any server downtime, completes in minutes, and replicates server configuration and hook scripts.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">svnadmin hotcopy PATH_TO_REPOS PATH_TO_MIRROR<\/pre>\n\n\n\n<p>The command is disconcertingly silent \u2014 no indication of progress, no verbose option. As is usual in UNIX-world, however, no news is good news. I just ran:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">du -sh PATH_TO_REPOS PATH_TO_MIRROR<\/pre>\n\n\n\n<p>to confirm the hotcopy was running and to check on its progress.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"summary\">Summary<\/h4>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Method<\/th><th>Server<br>Downtime?<\/th><th>Replicates<br>Config?<\/th><th>Speed<\/th><\/tr><\/thead><tbody><tr><td>File Copy<\/td><td>Yes<\/td><td>Yes<\/td><td>Quickest<\/td><\/tr><tr><td>Dump\/Load<\/td><td>No<\/td><td>No<\/td><td>Slowest<\/td><\/tr><tr><td>Hotcopy<\/td><td>No<\/td><td>Yes<\/td><td>Quick<\/td><\/tr><tr><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"checking-the-mirror\">Checking the mirror<\/h4>\n\n\n\n<p>Svnadmin provides another option,&nbsp;<code>svnadmin verify<\/code>&nbsp;to check a repository. This basically iterates through all revisions in the repository by internally dumping all revisions and discarding the output \u2014 so it takes a while.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">svnadmin verify PATH_TO_MIRROR<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"mirroring\">Mirroring<\/h4>\n\n\n\n<p>Software developers don\u2019t feel secure unless their source repository is safely backed up \u2013 or at least they shouldn\u2019t \u2013 and they are reluctant to suffer repository downtime or excessive maintenance overheads. Live&nbsp;<a href=\"http:\/\/subversion.tigris.org\/\" target=\"_blank\" rel=\"noopener\">Subversion<\/a>&nbsp;repositories can be mirrored quickly and safely using a simple command. With a little extra effort, this command can be scheduled to run automatically, every week, say.<\/p>\n\n\n\n<p>As a next step, by using the Subversion\u00a0<a href=\"http:\/\/svnbook.red-bean.com\/en\/1.2\/svn.reposadmin.create.html#svn.reposadmin.create.hooks\" target=\"_blank\" rel=\"noopener\">post-commit<\/a>\u00a0hook every check-in to the repository can instantly and incrementally be copied to the repository mirror. I\u2019ll provide details of how to do this in my next post.<\/p>\n\n\n<a href=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2017\/12\/SVN-Mirror-for-Live-back-up-SVN-High-Availability.pdf\" class=\"pdfemb-viewer\" style=\"\" data-width=\"max\" data-height=\"max\" data-toolbar=\"both\" data-toolbar-fixed=\"on\">SVN-Mirror-for-Live-back-up-SVN-High-Availability<\/a>\n<p class=\"wp-block-pdfemb-pdf-embedder-viewer\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here are three ways to create a full mirror of a&nbsp;Subversion&nbsp;repository: Treat the repository like any other filesystem and recursively copy it to the mirror location. Use&nbsp;svnadmin dump&nbsp;and&nbsp;svnadmin load. Use&nbsp;svnadmin&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[395],"class_list":["post-1741","post","type-post","status-publish","format-standard","hentry","category-uncategorised","tag-svn"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/1741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=1741"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/1741\/revisions"}],"predecessor-version":[{"id":29460,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/1741\/revisions\/29460"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=1741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=1741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=1741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}