Daniel Shahaf wrote on Sat, Nov 13, 2010 at 14:08:12 +0200:
> Philip Martin wrote on Fri, Nov 12, 2010 at 11:02:14 +0000:
> > Daniel Shahaf <d.s_at_daniel.shahaf.name> writes:
> > > 3. What's a reasonable strategy to hotcopy the locks?
> > >
> > > I've started on a patch that uses walk_digest_files() (I modified
> > > that function today), but currently that patch simply does a walk
> > > starting at the digest file md5("/"), and consequently it misses
> > > copying the unreferenced digest file md5("/trunk").
> >
> > It appears you have to read/copy md5("/") and get a list of locks, then
> > read/copy each lock file that still exists, then reconstruct the
> > intermediate files for the locks that were copied.
> >
>
> So, for example:
>
> - read md5("/")
> * read md5("/trunk/A/mu")
> + compute md5("/trunk/A")
> + compute md5("/trunk")
> * read md5("/trunk/iota")
> + compute md5("/trunk")
>
> where the 'compute()' steps follow those of normal lock creation: read
> the digest file, update list of children, write it back.
Attached patch implements this. Comments?
http://people.apache.org/~danielsh/hot.logmsg
http://people.apache.org/~danielsh/hot.diff
[[[
FSFS: teach 'hotcopy' the semantics of the locks/ directory.
Found by: philip
* notes/fsfs:
Document another limitation of rsync-style backup, which 'hotcopy' lacks.
* subversion/libsvn_fs_fs/fs_fs.c
(svn_fs_fs__hotcopy):
Use svn_fs_fs__hotcopy_locks() instead of svn_io_copy_dir_recursively().
* subversion/libsvn_fs_fs/lock.c
(svn_fs_fs__hotcopy_locks): New declaration.
* subversion/libsvn_fs_fs/lock.c
(digest_dir_path_from_digest):
New, like svn_dirent_dirname(digest_path_from_digest()).
(hotcopy_walker): New callback.
(svn_fs_fs__hotcopy_locks): New definition.
]]]
[[[
Index: notes/fsfs
===================================================================
--- notes/fsfs (revision 1034745)
+++ notes/fsfs (working copy)
@@ -248,6 +248,11 @@ manually removed. "svnadmin hotcopy" does not cop
transactions from an FSFS repository, although that might need to
change if Subversion starts making use of long-lived transactions.
+Naively copying an FSFS repository might also copy an inconsistent view
+of the locks directory, if locks are being added or removed as the copy
+operation is running. "svnadmin hotcopy" copies and generates the locks
+digest files properly.
+
So, if you are using standard backup tools to make backups of a FSFS
repository, configure the software to copy the "current" file before
the numbered revision files, if possible, and configure it not to copy
Index: subversion/libsvn_fs_fs/fs_fs.c
===================================================================
--- subversion/libsvn_fs_fs/fs_fs.c (revision 1034745)
+++ subversion/libsvn_fs_fs/fs_fs.c (working copy)
@@ -1767,9 +1767,7 @@ svn_fs_fs__hotcopy(const char *src_path,
src_subdir = svn_dirent_join(src_path, PATH_LOCKS_DIR, pool);
SVN_ERR(svn_io_check_path(src_subdir, &kind, pool));
if (kind == svn_node_dir)
- SVN_ERR(svn_io_copy_dir_recursively(src_subdir, dst_path,
- PATH_LOCKS_DIR, TRUE, NULL,
- NULL, pool));
+ SVN_ERR(svn_fs_fs__hotcopy_locks(src_path, dst_path, pool));
/* Now copy the node-origins cache tree. */
src_subdir = svn_dirent_join(src_path, PATH_NODE_ORIGINS_DIR, pool);
Index: subversion/libsvn_fs_fs/lock.c
===================================================================
--- subversion/libsvn_fs_fs/lock.c (revision 1034756)
+++ subversion/libsvn_fs_fs/lock.c (working copy)
@@ -121,6 +121,19 @@ err_corrupt_lockfile(const char *fs_path, const ch
/*** Digest file handling functions. ***/
+/* Return the path of the lock/entries directory for which DIGEST is the
+ hashed repository relative path. */
+static const char *
+digest_dir_path_from_digest(const char *fs_path,
+ const char *digest,
+ apr_pool_t *pool)
+{
+ return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
+ apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
+ NULL);
+}
+
+
/* Return the path of the lock/entries file for which DIGEST is the
hashed repository relative path. */
static const char *
@@ -893,6 +906,65 @@ unlock_body(void *baton, apr_pool_t *pool)
}
+/*** Hotcopying locks. ***/
+
+/* Implements walk_digests_callback_t. */
+static svn_error_t *
+hotcopy_walker(void *baton,
+ const char *fs_path,
+ const char *digest_path,
+ apr_hash_t *children /* ignored */,
+ svn_lock_t *lock /* ignored */,
+ svn_boolean_t have_write_lock,
+ apr_pool_t *pool)
+{
+ const char *dst_fs_path = baton;
+ const char *digest;
+ const char *src_digest_dir, *dst_digest_dir;
+ const char *perms_reference = digest_path;
+
+ digest = svn_dirent_basename(digest_path, NULL);
+ src_digest_dir = svn_dirent_dirname(digest_path, pool);
+ dst_digest_dir = digest_dir_path_from_digest(dst_fs_path, digest, pool);
+
+ SVN_DBG(("Hotcopying fs='%s' dest='%s' digest='%s'\n",
+ fs_path, dst_fs_path, digest));
+
+ /* Copy the digest file. */
+ SVN_ERR(svn_fs_fs__ensure_dir_exists(dst_digest_dir, dst_fs_path, pool));
+ SVN_ERR(svn_io_dir_file_copy(src_digest_dir, dst_digest_dir, digest, pool));
+
+ /* Generate the ancestor digest files (e.g., /trunk/A and /trunk, if we
+ locked /trunk/A/mu). It will re-write DST_FS_PATH's digest_path, too.
+ */
+ if (lock)
+ SVN_ERR(set_lock(dst_fs_path, lock, perms_reference, pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__hotcopy_locks(const char *fs_path,
+ const char *dst_fs_path,
+ apr_pool_t *pool)
+{
+ /* md5("/") == 6666cd76f96956469e7be39d750cc7d9 */
+ const char *md5_root = make_digest("/", pool);
+
+ SVN_ERR(svn_fs_fs__ensure_dir_exists(
+ svn_dirent_join(dst_fs_path, PATH_LOCKS_DIR, pool),
+ dst_fs_path,
+ pool));
+
+ SVN_ERR(walk_digest_files(fs_path,
+ digest_path_from_digest(fs_path, md5_root, pool),
+ hotcopy_walker, (void *)dst_fs_path,
+ FALSE /* have_write_lock */,
+ pool));
+ return SVN_NO_ERROR;
+}
+
+
/*** Public API implementations ***/
svn_error_t *
Index: subversion/libsvn_fs_fs/lock.h
===================================================================
--- subversion/libsvn_fs_fs/lock.h (revision 1034745)
+++ subversion/libsvn_fs_fs/lock.h (working copy)
@@ -96,6 +96,12 @@ svn_error_t *svn_fs_fs__allow_locked_operation(con
svn_boolean_t have_write_lock,
apr_pool_t *pool);
+/* Copy the locks hierarchy from the live FS at FS_PATH to DST_SUBDIR. */
+svn_error_t *
+svn_fs_fs__hotcopy_locks(const char *fs_path,
+ const char *dst_subdir,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
]]]
Received on 2010-11-13 15:25:56 CET