subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1502964 - in /subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs: fs_fs.c fs_fs.h lock.c pack.c util.c util.h
Date Sun, 14 Jul 2013 12:34:50 GMT
Author: stefan2
Date: Sun Jul 14 12:34:49 2013
New Revision: 1502964

URL: http://svn.apache.org/r1502964
Log:
On the fsfs-improvements branch:  Move more of the commonly used file and
path utilities from fs_fs.* to utils.*.  Again, we add the svn_fs_fs__
prefix to everything in utils.h.

Also make all path getters that didn't do so before return a const char*
instead of an svn_error_t *.

* subversion/libsvn_fs_fs/util.h
  (SVN_FS_FS__RECOVERABLE_RETRY_COUNT): declare private API constant
  (svn_fs_fs__is_packed_revprop,
   svn_fs_fs__path_rev_shard,
   svn_fs_fs__path_rev,
   svn_fs_fs__path_revprop_generation,
   svn_fs_fs__path_revprops_pack_shard,
   svn_fs_fs__path_revprops_shard,
   svn_fs_fs__path_revprops,
   svn_fs_fs__path_rev_absolute,
   svn_fs_fs__check_file_buffer_numeric,
   svn_fs_fs__update_min_unpacked_rev,
   svn_fs_fs__try_stringbuf_from_file,
   svn_fs_fs__read_content,
   svn_fs_fs__move_into_place): declare private API taken from fs_fs.*
  (svn_fs_fs__path_rev_absolute): ditto; change return type

* subversion/libsvn_fs_fs/util.c
  (svn_fs_fs__is_packed_revprop,
   svn_fs_fs__path_rev_shard,
   svn_fs_fs__path_rev,
   svn_fs_fs__path_revprop_generation,
   svn_fs_fs__path_revprops_pack_shard,
   svn_fs_fs__path_revprops_shard,
   svn_fs_fs__path_revprops,
   svn_fs_fs__path_rev_absolute,
   svn_fs_fs__check_file_buffer_numeric,
   svn_fs_fs__update_min_unpacked_rev,
   svn_fs_fs__try_stringbuf_from_file,
   svn_fs_fs__read_content,
   svn_fs_fs__move_into_place): rename; code taken from fs_fs.c
  (svn_fs_fs__path_rev_absolute): ditto; change return type

* subversion/libsvn_fs_fs/fs_fs.h
  (svn_fs_fs__path_rev_absolute): remove here, moved to utils.h

* subversion/libsvn_fs_fs/fs_fs.c
  (RECOVERABLE_RETRY_COUNT): renamed and moved to utils.h
  (is_packed_revprop,
   path_revprop_generation,
   path_rev_shard,
   path_rev,
   svn_fs_fs__path_rev_absolute,
   path_revprops_shard,
   path_revprops_pack_shard,
   path_revprops,
   check_file_buffer_numeric,
   update_min_unpacked_rev,
   try_stringbuf_from_file,
   read_content,
   move_into_place): renamed and moved to utils.c
  (with_some_lock_file,
   check_format_file_buffer_numeric,
   svn_fs_fs__open,
   get_youngest,
   open_pack_or_rev_file,
   read_revprop_generation_file,
   write_revprop_generation_file,
   read_non_packed_revprop,
   get_revprop_packname,
   read_pack_revprop,
   get_revision_proplist,
   write_non_packed_revprop,
   set_revision_proplist,
   get_and_increment_txn_key_body,
   get_next_revision_ids,
   commit_body,
   write_revision_zero,
   svn_fs_fs__create,
   packed_revprop_available,
   recover_body,
   hotcopy_update_current,
   hotcopy_body,
   hotcopy_create_empty_dest): update callers
  (get_root_changes_offset): update docstring

* subversion/libsvn_fs_fs/lock.c
  (delete_lock, 
   lock_body): update callers

* subversion/libsvn_fs_fs/pack.c
  (pack_body): update docstring

Modified:
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/lock.c
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.c
    subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.h

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c Sun Jul 14 12:34:49 2013
@@ -135,9 +135,6 @@ static txn_vtable_t txn_vtable = {
 /* Declarations. */
 
 static svn_error_t *
-update_min_unpacked_rev(svn_fs_t *fs, apr_pool_t *pool);
-
-static svn_error_t *
 get_youngest(svn_revnum_t *youngest_p, const char *fs_path, apr_pool_t *pool);
 
 static svn_error_t *
@@ -148,18 +145,6 @@ verify_walker(representation_t *rep,
 
 /* Pathname helper functions */
 
-/* Return TRUE is REV is packed in FS, FALSE otherwise. */
-static svn_boolean_t
-is_packed_revprop(svn_fs_t *fs, svn_revnum_t rev)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* rev 0 will not be packed */
-  return (rev < ffd->min_unpacked_rev)
-      && (rev != 0)
-      && (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT);
-}
-
 static const char *
 path_format(svn_fs_t *fs, apr_pool_t *pool)
 {
@@ -196,103 +181,6 @@ path_lock(svn_fs_t *fs, apr_pool_t *pool
   return svn_dirent_join(fs->path, PATH_LOCK_FILE, pool);
 }
 
-static const char *
-path_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
-{
-  return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool);
-}
-
-static const char *
-path_rev_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  assert(ffd->max_files_per_dir);
-  return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR,
-                              apr_psprintf(pool, "%ld",
-                                                 rev / ffd->max_files_per_dir),
-                              NULL);
-}
-
-static const char *
-path_rev(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  assert(! svn_fs_fs__is_packed_rev(fs, rev));
-
-  if (ffd->max_files_per_dir)
-    {
-      return svn_dirent_join(path_rev_shard(fs, rev, pool),
-                             apr_psprintf(pool, "%ld", rev),
-                             pool);
-    }
-
-  return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR,
-                              apr_psprintf(pool, "%ld", rev), NULL);
-}
-
-svn_error_t *
-svn_fs_fs__path_rev_absolute(const char **path,
-                             svn_fs_t *fs,
-                             svn_revnum_t rev,
-                             apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT
-      || ! svn_fs_fs__is_packed_rev(fs, rev))
-    {
-      *path = path_rev(fs, rev, pool);
-    }
-  else
-    {
-      *path = svn_fs_fs__path_rev_packed(fs, rev, PATH_PACKED, pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-static const char *
-path_revprops_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  assert(ffd->max_files_per_dir);
-  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
-                              apr_psprintf(pool, "%ld",
-                                           rev / ffd->max_files_per_dir),
-                              NULL);
-}
-
-static const char *
-path_revprops_pack_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  assert(ffd->max_files_per_dir);
-  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
-                              apr_psprintf(pool, "%ld" PATH_EXT_PACKED_SHARD,
-                                           rev / ffd->max_files_per_dir),
-                              NULL);
-}
-
-static const char *
-path_revprops(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  if (ffd->max_files_per_dir)
-    {
-      return svn_dirent_join(path_revprops_shard(fs, rev, pool),
-                             apr_psprintf(pool, "%ld", rev),
-                             pool);
-    }
-
-  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
-                              apr_psprintf(pool, "%ld", rev), NULL);
-}
-
 static APR_INLINE const char *
 path_txn_dir(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
 {
@@ -583,7 +471,7 @@ with_some_lock_file(svn_fs_t *fs,
       /* nobody else will modify the repo state
          => read HEAD & pack info once */
       if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
-        SVN_ERR(update_min_unpacked_rev(fs, pool));
+        SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, pool));
       SVN_ERR(get_youngest(&ffd->youngest_rev_cache, fs->path,
                            pool));
       err = body(baton, subpool);
@@ -879,28 +767,6 @@ get_file_offset(apr_off_t *offset_p, apr
 }
 
 
-/* Check that BUF, a nul-terminated buffer of text from file PATH,
-   contains only digits at OFFSET and beyond, raising an error if not.
-   TITLE contains a user-visible description of the file, usually the
-   short file name.
-
-   Uses POOL for temporary allocation. */
-static svn_error_t *
-check_file_buffer_numeric(const char *buf, apr_off_t offset,
-                          const char *path, const char *title,
-                          apr_pool_t *pool)
-{
-  const char *p;
-
-  for (p = buf + offset; *p; p++)
-    if (!svn_ctype_isdigit(*p))
-      return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
-        _("%s file '%s' contains unexpected non-digit '%c' within '%s'"),
-        title, svn_dirent_local_style(path, pool), *p, buf);
-
-  return SVN_NO_ERROR;
-}
-
 /* Check that BUF, a nul-terminated buffer of text from format file PATH,
    contains only digits at OFFSET and beyond, raising an error if not.
 
@@ -909,7 +775,8 @@ static svn_error_t *
 check_format_file_buffer_numeric(const char *buf, apr_off_t offset,
                                  const char *path, apr_pool_t *pool)
 {
-  return check_file_buffer_numeric(buf, offset, path, "Format", pool);
+  return svn_fs_fs__check_file_buffer_numeric(buf, offset, path, "Format",
+                                              pool);
 }
 
 /* Read the format number and maximum number of files per directory
@@ -1282,16 +1149,6 @@ write_config(svn_fs_t *fs,
                             fsfs_conf_contents, pool);
 }
 
-static svn_error_t *
-update_min_unpacked_rev(svn_fs_t *fs, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT);
-
-  return svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs, pool);
-}
-
 svn_error_t *
 svn_fs_fs__open(svn_fs_t *fs, const char *path, apr_pool_t *pool)
 {
@@ -1324,7 +1181,7 @@ svn_fs_fs__open(svn_fs_t *fs, const char
 
   /* Read the min unpacked revision. */
   if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
-    SVN_ERR(update_min_unpacked_rev(fs, pool));
+    SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, pool));
 
   /* Read the configuration file. */
   SVN_ERR(read_config(ffd, fs->path, pool));
@@ -1591,118 +1448,6 @@ svn_fs_fs__upgrade(svn_fs_t *fs,
   return svn_fs_fs__with_write_lock(fs, upgrade_body, (void *)&baton, pool);
 }
 
-
-/* Functions for dealing with recoverable errors on mutable files
- *
- * Revprops, current, and txn-current files are mutable; that is, they
- * change as part of normal fsfs operation, in constrat to revs files, or
- * the format file, which are written once at create (or upgrade) time.
- * When more than one host writes to the same repository, we will
- * sometimes see these recoverable errors when accesssing these files.
- *
- * These errors all relate to NFS, and thus we only use this retry code if
- * ESTALE is defined.
- *
- ** ESTALE
- *
- * In NFS v3 and under, the server doesn't track opened files.  If you
- * unlink(2) or rename(2) a file held open by another process *on the
- * same host*, that host's kernel typically renames the file to
- * .nfsXXXX and automatically deletes that when it's no longer open,
- * but this behavior is not required.
- *
- * For obvious reasons, this does not work *across hosts*.  No one
- * knows about the opened file; not the server, and not the deleting
- * client.  So the file vanishes, and the reader gets stale NFS file
- * handle.
- *
- ** EIO, ENOENT
- *
- * Some client implementations (at least the 2.6.18.5 kernel that ships
- * with Ubuntu Dapper) sometimes give spurious ENOENT (only on open) or
- * even EIO errors when trying to read these files that have been renamed
- * over on some other host.
- *
- ** Solution
- *
- * Try open and read of such files in try_stringbuf_from_file().  Call
- * this function within a loop of RECOVERABLE_RETRY_COUNT iterations
- * (though, realistically, the second try will succeed).
- */
-
-#define RECOVERABLE_RETRY_COUNT 10
-
-/* Read the file at PATH and return its content in *CONTENT. *CONTENT will
- * not be modified unless the whole file was read successfully.
- *
- * ESTALE, EIO and ENOENT will not cause this function to return an error
- * unless LAST_ATTEMPT has been set.  If MISSING is not NULL, indicate
- * missing files (ENOENT) there.
- *
- * Use POOL for allocations.
- */
-static svn_error_t *
-try_stringbuf_from_file(svn_stringbuf_t **content,
-                        svn_boolean_t *missing,
-                        const char *path,
-                        svn_boolean_t last_attempt,
-                        apr_pool_t *pool)
-{
-  svn_error_t *err = svn_stringbuf_from_file2(content, path, pool);
-  if (missing)
-    *missing = FALSE;
-
-  if (err)
-    {
-      *content = NULL;
-
-      if (APR_STATUS_IS_ENOENT(err->apr_err))
-        {
-          if (!last_attempt)
-            {
-              svn_error_clear(err);
-              if (missing)
-                *missing = TRUE;
-              return SVN_NO_ERROR;
-            }
-        }
-#ifdef ESTALE
-      else if (APR_TO_OS_ERROR(err->apr_err) == ESTALE
-                || APR_TO_OS_ERROR(err->apr_err) == EIO)
-        {
-          if (!last_attempt)
-            {
-              svn_error_clear(err);
-              return SVN_NO_ERROR;
-            }
-        }
-#endif
-    }
-
-  return svn_error_trace(err);
-}
-
-/* Read the 'current' file FNAME and store the contents in *BUF.
-   Allocations are performed in POOL. */
-static svn_error_t *
-read_content(svn_stringbuf_t **content, const char *fname, apr_pool_t *pool)
-{
-  int i;
-  *content = NULL;
-
-  for (i = 0; !*content && (i < RECOVERABLE_RETRY_COUNT); ++i)
-    SVN_ERR(try_stringbuf_from_file(content, NULL,
-                                    fname, i + 1 < RECOVERABLE_RETRY_COUNT,
-                                    pool));
-
-  if (!*content)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Can't read '%s'"),
-                             svn_dirent_local_style(fname, pool));
-
-  return SVN_NO_ERROR;
-}
-
 /* Find the youngest revision in a repository at path FS_PATH and
    return it in *YOUNGEST_P.  Perform temporary allocations in
    POOL. */
@@ -1712,8 +1457,10 @@ get_youngest(svn_revnum_t *youngest_p,
              apr_pool_t *pool)
 {
   svn_stringbuf_t *buf;
-  SVN_ERR(read_content(&buf, svn_dirent_join(fs_path, PATH_CURRENT, pool),
-                       pool));
+  SVN_ERR(svn_fs_fs__read_content(&buf,
+                                  svn_dirent_join(fs_path, PATH_CURRENT,
+                                                  pool),
+                                  pool));
 
   *youngest_p = SVN_STR_TO_REV(buf->data);
 
@@ -1789,9 +1536,9 @@ svn_fs_fs__revision_exists(svn_revnum_t 
    file doesn't exist.
 
    TODO: Consider returning an indication of whether this is a packed rev
-         file, so the caller need not rely on is_packed_rev() which in turn
-         relies on the cached FFD->min_unpacked_rev value not having changed
-         since the rev file was opened.
+         file, so the caller need not rely on svn_fs_fs__is_packed_rev()
+         which in turn relies on the cached FFD->min_unpacked_rev value not
+         having changed since the rev file was opened.
 
    Use POOL for allocations. */
 static svn_error_t *
@@ -1807,7 +1554,7 @@ open_pack_or_rev_file(apr_file_t **file,
 
   do
     {
-      err = svn_fs_fs__path_rev_absolute(&path, fs, rev, pool);
+      path = svn_fs_fs__path_rev_absolute(fs, rev, pool);
 
       /* open the revision file in buffered r/o mode */
       if (! err)
@@ -1828,7 +1575,7 @@ open_pack_or_rev_file(apr_file_t **file,
                                          _("No such revision %ld"), rev);
 
               /* We failed for the first time. Refresh cache & retry. */
-              SVN_ERR(update_min_unpacked_rev(fs, pool));
+              SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, pool));
 
               retry = TRUE;
             }
@@ -2180,10 +1927,10 @@ get_fs_id_at_offset(svn_fs_id_t **id_p,
 
    If PACKED is true, REV_FILE should be a packed shard file.
    ### There is currently no such parameter.  This function assumes that
-       is_packed_rev(FS, REV) will indicate whether REV_FILE is a packed
-       file.  Therefore FS->fsap_data->min_unpacked_rev must not have been
-       refreshed since REV_FILE was opened if there is a possibility that
-       revision REV may have become packed since then.
+       svn_fs_fs__is_packed_rev(FS, REV) will indicate whether REV_FILE is
+       a packed file.  Therefore FS->fsap_data->min_unpacked_rev must not
+       have been refreshed since REV_FILE was opened if there is a
+       possibility that revision REV may have become packed since then.
        TODO: Take an IS_PACKED parameter instead, in order to remove this
        requirement.
 
@@ -2256,69 +2003,6 @@ get_root_changes_offset(apr_off_t *root_
   return SVN_NO_ERROR;
 }
 
-/* Move a file into place from OLD_FILENAME in the transactions
-   directory to its final location NEW_FILENAME in the repository.  On
-   Unix, match the permissions of the new file to the permissions of
-   PERMS_REFERENCE.  Temporary allocations are from POOL.
-
-   This function almost duplicates svn_io_file_move(), but it tries to
-   guarantee a flush. */
-static svn_error_t *
-move_into_place(const char *old_filename,
-                const char *new_filename,
-                const char *perms_reference,
-                apr_pool_t *pool)
-{
-  svn_error_t *err;
-
-  SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
-
-  /* Move the file into place. */
-  err = svn_io_file_rename(old_filename, new_filename, pool);
-  if (err && APR_STATUS_IS_EXDEV(err->apr_err))
-    {
-      apr_file_t *file;
-
-      /* Can't rename across devices; fall back to copying. */
-      svn_error_clear(err);
-      err = SVN_NO_ERROR;
-      SVN_ERR(svn_io_copy_file(old_filename, new_filename, TRUE, pool));
-
-      /* Flush the target of the copy to disk. */
-      SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ,
-                               APR_OS_DEFAULT, pool));
-      /* ### BH: Does this really guarantee a flush of the data written
-         ### via a completely different handle on all operating systems?
-         ###
-         ### Maybe we should perform the copy ourselves instead of making
-         ### apr do that and flush the real handle? */
-      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
-      SVN_ERR(svn_io_file_close(file, pool));
-    }
-  if (err)
-    return svn_error_trace(err);
-
-#ifdef __linux__
-  {
-    /* Linux has the unusual feature that fsync() on a file is not
-       enough to ensure that a file's directory entries have been
-       flushed to disk; you have to fsync the directory as well.
-       On other operating systems, we'd only be asking for trouble
-       by trying to open and fsync a directory. */
-    const char *dirname;
-    apr_file_t *file;
-
-    dirname = svn_dirent_dirname(new_filename, pool);
-    SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
-                             pool));
-    SVN_ERR(svn_io_file_flush_to_disk(file, pool));
-    SVN_ERR(svn_io_file_close(file, pool));
-  }
-#endif
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_fs_fs__rev_get_root(svn_fs_id_t **root_id_p,
                         svn_fs_t *fs,
@@ -2419,7 +2103,7 @@ read_revprop_generation_file(apr_int64_t
   apr_file_t *file;
   char buf[80];
   apr_size_t len;
-  const char *path = path_revprop_generation(fs, pool);
+  const char *path = svn_fs_fs__path_revprop_generation(fs, pool);
 
   err = svn_io_file_open(&file, path,
                          APR_READ | APR_BUFFERED,
@@ -2437,8 +2121,8 @@ read_revprop_generation_file(apr_int64_t
   SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
 
   /* Check that the first line contains only digits. */
-  SVN_ERR(check_file_buffer_numeric(buf, 0, path,
-                                    "Revprop Generation", pool));
+  SVN_ERR(svn_fs_fs__check_file_buffer_numeric(buf, 0, path,
+                                               "Revprop Generation", pool));
   SVN_ERR(svn_cstring_atoi64(current, buf));
 
   return svn_io_file_close(file, pool);
@@ -2455,7 +2139,7 @@ write_revprop_generation_file(svn_fs_t *
   apr_size_t len = svn__i64toa(buf, current);
   buf[len] = '\n';
 
-  SVN_ERR(svn_io_write_atomic(path_revprop_generation(fs, pool),
+  SVN_ERR(svn_io_write_atomic(svn_fs_fs__path_revprop_generation(fs, pool),
                               buf, len + 1,
                               NULL /* copy_perms */, pool));
 
@@ -2857,14 +2541,16 @@ read_non_packed_revprop(apr_hash_t **pro
   svn_boolean_t missing = FALSE;
   int i;
 
-  for (i = 0; i < RECOVERABLE_RETRY_COUNT && !missing && !content; ++i)
+  for (i = 0;
+       i < SVN_FS_FS__RECOVERABLE_RETRY_COUNT && !missing && !content;
+       ++i)
     {
       svn_pool_clear(iterpool);
-      SVN_ERR(try_stringbuf_from_file(&content,
-                                      &missing,
-                                      path_revprops(fs, rev, iterpool),
-                                      i + 1 < RECOVERABLE_RETRY_COUNT,
-                                      iterpool));
+      SVN_ERR(svn_fs_fs__try_stringbuf_from_file(&content,
+                              &missing,
+                              svn_fs_fs__path_revprops(fs, rev, iterpool),
+                              i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT,
+                              iterpool));
     }
 
   if (content)
@@ -2892,10 +2578,12 @@ get_revprop_packname(svn_fs_t *fs,
   int idx;
 
   /* read content of the manifest file */
-  revprops->folder = path_revprops_pack_shard(fs, revprops->revision, pool);
-  manifest_file_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
+  revprops->folder
+    = svn_fs_fs__path_revprops_pack_shard(fs, revprops->revision, pool);
+  manifest_file_path
+    = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
 
-  SVN_ERR(read_content(&content, manifest_file_path, pool));
+  SVN_ERR(svn_fs_fs__read_content(&content, manifest_file_path, pool));
 
   /* parse the manifest. Every line is a file name */
   revprops->manifest = apr_array_make(pool, ffd->max_files_per_dir,
@@ -3048,10 +2736,10 @@ read_pack_revprop(packed_revprops_t **re
   int i;
 
   /* someone insisted that REV is packed. Double-check if necessary */
-  if (!is_packed_revprop(fs, rev))
-     SVN_ERR(update_min_unpacked_rev(fs, iterpool));
+  if (!svn_fs_fs__is_packed_revprop(fs, rev))
+     SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, iterpool));
 
-  if (!is_packed_revprop(fs, rev))
+  if (!svn_fs_fs__is_packed_revprop(fs, rev))
     return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
                               _("No such packed revision %ld"), rev);
 
@@ -3062,7 +2750,9 @@ read_pack_revprop(packed_revprops_t **re
 
   /* try to read the packed revprops. This may require retries if we have
    * concurrent writers. */
-  for (i = 0; i < RECOVERABLE_RETRY_COUNT && !result->packed_revprops; ++i)
+  for (i = 0;
+       i < SVN_FS_FS__RECOVERABLE_RETRY_COUNT && !result->packed_revprops;
+       ++i)
     {
       const char *file_path;
 
@@ -3073,11 +2763,11 @@ read_pack_revprop(packed_revprops_t **re
       file_path  = svn_dirent_join(result->folder,
                                    result->filename,
                                    iterpool);
-      SVN_ERR(try_stringbuf_from_file(&result->packed_revprops,
-                                      &missing,
-                                      file_path,
-                                      i + 1 < RECOVERABLE_RETRY_COUNT,
-                                      pool));
+      SVN_ERR(svn_fs_fs__try_stringbuf_from_file(&result->packed_revprops,
+                                &missing,
+                                file_path,
+                                i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT,
+                                pool));
 
       /* If we could not find the file, there was a write.
        * So, we should refresh our revprop generation info as well such
@@ -3145,7 +2835,7 @@ get_revision_proplist(apr_hash_t **propl
   /* if REV had not been packed when we began, try reading it from the
    * non-packed shard.  If that fails, we will fall through to packed
    * shard reads. */
-  if (!is_packed_revprop(fs, rev))
+  if (!svn_fs_fs__is_packed_revprop(fs, rev))
     {
       svn_error_t *err = read_non_packed_revprop(proplist_p, fs, rev,
                                                  generation, pool);
@@ -3195,7 +2885,7 @@ write_non_packed_revprop(const char **fi
                          apr_pool_t *pool)
 {
   svn_stream_t *stream;
-  *final_path = path_revprops(fs, rev, pool);
+  *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
 
   /* ### do we have a directory sitting around already? we really shouldn't
      ### have to get the dirname here. */
@@ -3232,7 +2922,8 @@ switch_to_new_revprop(svn_fs_t *fs,
   if (bump_generation)
     SVN_ERR(begin_revprop_change(fs, pool));
 
-  SVN_ERR(move_into_place(tmp_path, final_path, perms_reference, pool));
+  SVN_ERR(svn_fs_fs__move_into_place(tmp_path, final_path, perms_reference,
+                                     pool));
 
   /* Indicate that the update (if relevant) has been completed. */
   if (bump_generation)
@@ -3591,7 +3282,7 @@ set_revision_proplist(svn_fs_t *fs,
   SVN_ERR(ensure_revision_exists(fs, rev, pool));
 
   /* this info will not change while we hold the global FS write lock */
-  is_packed = is_packed_revprop(fs, rev);
+  is_packed = svn_fs_fs__is_packed_revprop(fs, rev);
 
   /* Test whether revprops already exist for this revision.
    * Only then will we need to bump the revprop generation. */
@@ -3604,7 +3295,8 @@ set_revision_proplist(svn_fs_t *fs,
       else
         {
           svn_node_kind_t kind;
-          SVN_ERR(svn_io_check_path(path_revprops(fs, rev, pool), &kind,
+          SVN_ERR(svn_io_check_path(svn_fs_fs__path_revprops(fs, rev, pool),
+                                    &kind,
                                     pool));
           bump_generation = kind != svn_node_none;
         }
@@ -3623,7 +3315,7 @@ set_revision_proplist(svn_fs_t *fs,
    * file won't exist and therefore can't serve as its own reference.
    * (Whereas the rev file should already exist at this point.)
    */
-  SVN_ERR(svn_fs_fs__path_rev_absolute(&perms_reference, fs, rev, pool));
+  perms_reference = svn_fs_fs__path_rev_absolute(fs, rev, pool);
 
   /* Now, switch to the new revprop data. */
   SVN_ERR(switch_to_new_revprop(fs, final_path, tmp_path, perms_reference,
@@ -5509,7 +5201,7 @@ get_and_increment_txn_key_body(void *bat
   apr_size_t len;
 
   svn_stringbuf_t *buf;
-  SVN_ERR(read_content(&buf, txn_current_filename, cb->pool));
+  SVN_ERR(svn_fs_fs__read_content(&buf, txn_current_filename, cb->pool));
 
   /* remove trailing newlines */
   svn_stringbuf_strip_whitespace(buf);
@@ -6670,7 +6362,9 @@ get_next_revision_ids(const char **node_
   char *str;
   svn_stringbuf_t *content;
 
-  SVN_ERR(read_content(&content, svn_fs_fs__path_current(fs, pool), pool));
+  SVN_ERR(svn_fs_fs__read_content(&content,
+                                  svn_fs_fs__path_current(fs, pool),
+                                  pool));
   buf = content->data;
 
   str = svn_cstring_tokenize(" ", &buf);
@@ -7510,8 +7204,10 @@ commit_body(void *baton, apr_pool_t *poo
     {
       /* Create the revs shard. */
         {
-          const char *new_dir = path_rev_shard(cb->fs, new_rev, pool);
-          svn_error_t *err = svn_io_dir_make(new_dir, APR_OS_DEFAULT, pool);
+          const char *new_dir
+            = svn_fs_fs__path_rev_shard(cb->fs, new_rev, pool);
+          svn_error_t *err
+            = svn_io_dir_make(new_dir, APR_OS_DEFAULT, pool);
           if (err && !APR_STATUS_IS_EEXIST(err->apr_err))
             return svn_error_trace(err);
           svn_error_clear(err);
@@ -7522,10 +7218,12 @@ commit_body(void *baton, apr_pool_t *poo
         }
 
       /* Create the revprops shard. */
-      SVN_ERR_ASSERT(! is_packed_revprop(cb->fs, new_rev));
+      SVN_ERR_ASSERT(! svn_fs_fs__is_packed_revprop(cb->fs, new_rev));
         {
-          const char *new_dir = path_revprops_shard(cb->fs, new_rev, pool);
-          svn_error_t *err = svn_io_dir_make(new_dir, APR_OS_DEFAULT, pool);
+          const char *new_dir
+            = svn_fs_fs__path_revprops_shard(cb->fs, new_rev, pool);
+          svn_error_t *err
+            = svn_io_dir_make(new_dir, APR_OS_DEFAULT, pool);
           if (err && !APR_STATUS_IS_EEXIST(err->apr_err))
             return svn_error_trace(err);
           svn_error_clear(err);
@@ -7537,12 +7235,11 @@ commit_body(void *baton, apr_pool_t *poo
     }
 
   /* Move the finished rev file into place. */
-  SVN_ERR(svn_fs_fs__path_rev_absolute(&old_rev_filename,
-                                       cb->fs, old_rev, pool));
-  rev_filename = path_rev(cb->fs, new_rev, pool);
+  old_rev_filename = svn_fs_fs__path_rev_absolute(cb->fs, old_rev, pool);
+  rev_filename = svn_fs_fs__path_rev(cb->fs, new_rev, pool);
   proto_filename = path_txn_proto_rev(cb->fs, cb->txn->id, pool);
-  SVN_ERR(move_into_place(proto_filename, rev_filename, old_rev_filename,
-                          pool));
+  SVN_ERR(svn_fs_fs__move_into_place(proto_filename, rev_filename,
+                                     old_rev_filename, pool));
 
   /* Now that we've moved the prototype revision file out of the way,
      we can unlock it (since further attempts to write to the file
@@ -7558,11 +7255,11 @@ commit_body(void *baton, apr_pool_t *poo
                                      &date, pool));
 
   /* Move the revprops file into place. */
-  SVN_ERR_ASSERT(! is_packed_revprop(cb->fs, new_rev));
+  SVN_ERR_ASSERT(! svn_fs_fs__is_packed_revprop(cb->fs, new_rev));
   revprop_filename = path_txn_props(cb->fs, cb->txn->id, pool);
-  final_revprop = path_revprops(cb->fs, new_rev, pool);
-  SVN_ERR(move_into_place(revprop_filename, final_revprop,
-                          old_rev_filename, pool));
+  final_revprop = svn_fs_fs__path_revprops(cb->fs, new_rev, pool);
+  SVN_ERR(svn_fs_fs__move_into_place(revprop_filename, final_revprop,
+                                     old_rev_filename, pool));
 
   /* Update the 'current' file. */
   SVN_ERR(verify_as_revision_before_current_plus_plus(cb->fs, new_rev, pool));
@@ -7686,7 +7383,7 @@ svn_fs_fs__reserve_copy_id(const char **
 static svn_error_t *
 write_revision_zero(svn_fs_t *fs)
 {
-  const char *path_revision_zero = path_rev(fs, 0, fs->pool);
+  const char *path_revision_zero = svn_fs_fs__path_rev(fs, 0, fs->pool);
   apr_hash_t *proplist;
   svn_string_t date;
 
@@ -7739,7 +7436,9 @@ svn_fs_fs__create(svn_fs_t *fs,
 
   /* Create the revision data directories. */
   if (ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(path_rev_shard(fs, 0, pool), pool));
+    SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_rev_shard(fs, 0,
+                                                                  pool),
+                                        pool));
   else
     SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(path, PATH_REVS_DIR,
                                                         pool),
@@ -7747,7 +7446,8 @@ svn_fs_fs__create(svn_fs_t *fs,
 
   /* Create the revprops directory. */
   if (ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(path_revprops_shard(fs, 0, pool),
+    SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_revprops_shard(fs, 0,
+                                                                       pool),
                                         pool));
   else
     SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(path,
@@ -8054,14 +7754,16 @@ packed_revprop_available(svn_boolean_t *
   svn_stringbuf_t *content = NULL;
 
   /* try to read the manifest file */
-  const char *folder = path_revprops_pack_shard(fs, revision, pool);
-  const char *manifest_path = svn_dirent_join(folder, PATH_MANIFEST, pool);
-
-  svn_error_t *err = try_stringbuf_from_file(&content,
-                                             missing,
-                                             manifest_path,
-                                             FALSE,
-                                             pool);
+  const char *folder
+    = svn_fs_fs__path_revprops_pack_shard(fs, revision, pool);
+  const char *manifest_path
+    = svn_dirent_join(folder, PATH_MANIFEST, pool);
+
+  svn_error_t *err = svn_fs_fs__try_stringbuf_from_file(&content,
+                                                        missing,
+                                                        manifest_path,
+                                                        FALSE,
+                                                        pool);
 
   /* if the manifest cannot be read, consider the pack files inaccessible
    * even if the file itself exists. */
@@ -8223,7 +7925,7 @@ recover_body(void *baton, apr_pool_t *po
 
   /* Before setting current, verify that there is a revprops file
      for the youngest revision.  (Issue #2992) */
-  SVN_ERR(svn_io_check_path(path_revprops(fs, max_rev, pool),
+  SVN_ERR(svn_io_check_path(svn_fs_fs__path_revprops(fs, max_rev, pool),
                             &youngest_revprops_kind, pool));
   if (youngest_revprops_kind == svn_node_none)
     {
@@ -9492,7 +9194,7 @@ hotcopy_update_current(svn_revnum_t *dst
       apr_file_t *rev_file;
 
       if (dst_ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
-        SVN_ERR(update_min_unpacked_rev(dst_fs, scratch_pool));
+        SVN_ERR(svn_fs_fs__update_min_unpacked_rev(dst_fs, scratch_pool));
 
       SVN_ERR(open_pack_or_rev_file(&rev_file, dst_fs, new_youngest,
                                     scratch_pool));
@@ -9806,7 +9508,8 @@ hotcopy_body(void *baton, apr_pool_t *po
 
       /* Now that all revisions have moved into the pack, the original
        * rev dir can be removed. */
-      err = svn_io_remove_dir2(path_rev_shard(dst_fs, rev, iterpool),
+      err = svn_io_remove_dir2(svn_fs_fs__path_rev_shard(dst_fs, rev,
+                                                         iterpool),
                                TRUE, cancel_func, cancel_baton, iterpool);
       if (err)
         {
@@ -9857,7 +9560,7 @@ hotcopy_body(void *baton, apr_pool_t *po
                *
                * If the youngest revision ended up being packed, don't try
                * to be smart and work around this. Just abort the hotcopy. */
-              SVN_ERR(update_min_unpacked_rev(src_fs, pool));
+              SVN_ERR(svn_fs_fs__update_min_unpacked_rev(src_fs, pool));
               if (svn_fs_fs__is_packed_rev(src_fs, rev))
                 {
                   if (svn_fs_fs__is_packed_rev(src_fs, src_youngest))
@@ -9958,7 +9661,7 @@ hotcopy_body(void *baton, apr_pool_t *po
    * reset it to zero (since this is on a different path, it will not
    * overlap with data already in cache).  Also, clean up stale files
    * used for the named atomics implementation. */
-  SVN_ERR(svn_io_check_path(path_revprop_generation(src_fs, pool),
+  SVN_ERR(svn_io_check_path(svn_fs_fs__path_revprop_generation(src_fs, pool),
                             &kind, pool));
   if (kind == svn_node_file)
     SVN_ERR(write_revprop_generation_file(dst_fs, 0, pool));
@@ -10007,7 +9710,8 @@ hotcopy_create_empty_dest(svn_fs_t *src_
 
   /* Create the revision data directories. */
   if (dst_ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(path_rev_shard(dst_fs, 0, pool),
+    SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_rev_shard(dst_fs,
+                                                                  0, pool),
                                         pool));
   else
     SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path,
@@ -10016,8 +9720,9 @@ hotcopy_create_empty_dest(svn_fs_t *src_
 
   /* Create the revprops directory. */
   if (src_ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(path_revprops_shard(dst_fs, 0, pool),
-                                        pool));
+    SVN_ERR(svn_io_make_dir_recursively(
+                          svn_fs_fs__path_revprops_shard(dst_fs, 0, pool),
+                          pool));
   else
     SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path,
                                                         PATH_REVPROPS_DIR,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h Sun Jul 14 12:34:49 2013
@@ -408,20 +408,6 @@ svn_error_t *svn_fs_fs__txn_changes_fetc
                                           apr_pool_t *pool);
 
 
-/* Set *PATH to the path of REV in FS, whether in a pack file or not.
-   Allocate *PATH in POOL.
-
-   Note: If the caller does not have the write lock on FS, then the path is
-   not guaranteed to be correct or to remain correct after the function
-   returns, because the revision might become packed before or after this
-   call.  If a file exists at that path, then it is correct; if not, then
-   the caller should call update_min_unpacked_rev() and re-try once. */
-svn_error_t *
-svn_fs_fs__path_rev_absolute(const char **path,
-                             svn_fs_t *fs,
-                             svn_revnum_t rev,
-                             apr_pool_t *pool);
-
 /* Return the path to the 'current' file in FS.
    Perform allocation in POOL. */
 const char *

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/lock.c?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/lock.c Sun Jul 14 12:34:49 2013
@@ -37,6 +37,7 @@
 #include "lock.h"
 #include "tree.h"
 #include "fs_fs.h"
+#include "util.h"
 #include "../libsvn_fs/fs-loader.h"
 
 #include "private/svn_fs_util.h"
@@ -456,8 +457,7 @@ delete_lock(svn_fs_t *fs,
         }
       else
         {
-          const char *rev_0_path;
-          SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
+          const char *rev_0_path = svn_fs_fs__path_rev_absolute(fs, 0, pool);
           SVN_ERR(write_digest_file(this_children, this_lock, fs->path,
                                     digest_path, rev_0_path, subpool));
         }
@@ -864,7 +864,7 @@ lock_body(void *baton, apr_pool_t *pool)
   lock->is_dav_comment = lb->is_dav_comment;
   lock->creation_date = apr_time_now();
   lock->expiration_date = lb->expiration_date;
-  SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, lb->fs, 0, pool));
+  rev_0_path = svn_fs_fs__path_rev_absolute(lb->fs, 0, pool);
   SVN_ERR(set_lock(lb->fs->path, lock, rev_0_path, pool));
   *lb->lock_p = lock;
 

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c Sun Jul 14 12:34:49 2013
@@ -360,7 +360,7 @@ struct pack_baton
      extension, on not having to use a retry when calling
      svn_fs_fs__path_rev_absolute() and friends).  If you add a call
      to this function, consider whether you have to call
-     update_min_unpacked_rev().
+     svn_fs_fs__update_min_unpacked_rev().
      See this thread: http://thread.gmane.org/1291206765.3782.3309.camel@edith
  */
 static svn_error_t *

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.c?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.c Sun Jul 14 12:34:49 2013
@@ -22,6 +22,7 @@
 
 #include <assert.h>
 
+#include "svn_ctype.h"
 #include "svn_dirent_uri.h"
 #include "private/svn_string_private.h"
 
@@ -41,6 +42,25 @@ svn_fs_fs__is_packed_rev(svn_fs_t *fs,
   return (rev < ffd->min_unpacked_rev);
 }
 
+svn_boolean_t
+svn_fs_fs__is_packed_revprop(svn_fs_t *fs,
+                             svn_revnum_t rev)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  /* rev 0 will not be packed */
+  return (rev < ffd->min_unpacked_rev)
+      && (rev != 0)
+      && (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT);
+}
+
+const char *
+svn_fs_fs__path_revprop_generation(svn_fs_t *fs,
+                                   apr_pool_t *pool)
+{
+  return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool);
+}
+
 const char *
 svn_fs_fs__path_rev_packed(svn_fs_t *fs,
                            svn_revnum_t rev,
@@ -60,6 +80,95 @@ svn_fs_fs__path_rev_packed(svn_fs_t *fs,
 }
 
 const char *
+svn_fs_fs__path_rev_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  assert(ffd->max_files_per_dir);
+  return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR,
+                              apr_psprintf(pool, "%ld",
+                                                 rev / ffd->max_files_per_dir),
+                              NULL);
+}
+
+const char *
+svn_fs_fs__path_rev(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  assert(! svn_fs_fs__is_packed_rev(fs, rev));
+
+  if (ffd->max_files_per_dir)
+    {
+      return svn_dirent_join(svn_fs_fs__path_rev_shard(fs, rev, pool),
+                             apr_psprintf(pool, "%ld", rev),
+                             pool);
+    }
+
+  return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR,
+                              apr_psprintf(pool, "%ld", rev), NULL);
+}
+
+const char *
+svn_fs_fs__path_rev_absolute(svn_fs_t *fs,
+                             svn_revnum_t rev,
+                             apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  return (   ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT
+          || ! svn_fs_fs__is_packed_rev(fs, rev))
+       ? svn_fs_fs__path_rev(fs, rev, pool)
+       : svn_fs_fs__path_rev_packed(fs, rev, PATH_PACKED, pool);
+}
+
+const char *
+svn_fs_fs__path_revprops_shard(svn_fs_t *fs,
+                               svn_revnum_t rev,
+                               apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  assert(ffd->max_files_per_dir);
+  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
+                              apr_psprintf(pool, "%ld",
+                                           rev / ffd->max_files_per_dir),
+                              NULL);
+}
+
+const char *
+svn_fs_fs__path_revprops_pack_shard(svn_fs_t *fs,
+                                    svn_revnum_t rev,
+                                    apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  assert(ffd->max_files_per_dir);
+  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
+                              apr_psprintf(pool, "%ld" PATH_EXT_PACKED_SHARD,
+                                           rev / ffd->max_files_per_dir),
+                              NULL);
+}
+
+const char *
+svn_fs_fs__path_revprops(svn_fs_t *fs,
+                         svn_revnum_t rev,
+                         apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  if (ffd->max_files_per_dir)
+    {
+      return svn_dirent_join(svn_fs_fs__path_revprops_shard(fs, rev, pool),
+                             apr_psprintf(pool, "%ld", rev),
+                             pool);
+    }
+
+  return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR,
+                              apr_psprintf(pool, "%ld", rev), NULL);
+}
+
+const char *
 svn_fs_fs__path_min_unpacked_rev(svn_fs_t *fs,
                                  apr_pool_t *pool)
 {
@@ -67,6 +176,24 @@ svn_fs_fs__path_min_unpacked_rev(svn_fs_
 }
 
 svn_error_t *
+svn_fs_fs__check_file_buffer_numeric(const char *buf,
+                                     apr_off_t offset,
+                                     const char *path,
+                                     const char *title,
+                                     apr_pool_t *pool)
+{
+  const char *p;
+
+  for (p = buf + offset; *p; p++)
+    if (!svn_ctype_isdigit(*p))
+      return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
+        _("%s file '%s' contains unexpected non-digit '%c' within '%s'"),
+        title, svn_dirent_local_style(path, pool), *p, buf);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_fs__read_min_unpacked_rev(svn_revnum_t *min_unpacked_rev,
                                  svn_fs_t *fs,
                                  apr_pool_t *pool)
@@ -89,6 +216,17 @@ svn_fs_fs__read_min_unpacked_rev(svn_rev
 }
 
 svn_error_t *
+svn_fs_fs__update_min_unpacked_rev(svn_fs_t *fs,
+                                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT);
+
+  return svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs, pool);
+}
+
+svn_error_t *
 svn_fs_fs__write_revnum_file(svn_fs_t *fs,
                              svn_revnum_t revnum,
                              apr_pool_t *scratch_pool)
@@ -107,6 +245,68 @@ svn_fs_fs__write_revnum_file(svn_fs_t *f
 }
 
 svn_error_t *
+svn_fs_fs__try_stringbuf_from_file(svn_stringbuf_t **content,
+                                   svn_boolean_t *missing,
+                                   const char *path,
+                                   svn_boolean_t last_attempt,
+                                   apr_pool_t *pool)
+{
+  svn_error_t *err = svn_stringbuf_from_file2(content, path, pool);
+  if (missing)
+    *missing = FALSE;
+
+  if (err)
+    {
+      *content = NULL;
+
+      if (APR_STATUS_IS_ENOENT(err->apr_err))
+        {
+          if (!last_attempt)
+            {
+              svn_error_clear(err);
+              if (missing)
+                *missing = TRUE;
+              return SVN_NO_ERROR;
+            }
+        }
+#ifdef ESTALE
+      else if (APR_TO_OS_ERROR(err->apr_err) == ESTALE
+                || APR_TO_OS_ERROR(err->apr_err) == EIO)
+        {
+          if (!last_attempt)
+            {
+              svn_error_clear(err);
+              return SVN_NO_ERROR;
+            }
+        }
+#endif
+    }
+
+  return svn_error_trace(err);
+}
+
+svn_error_t *
+svn_fs_fs__read_content(svn_stringbuf_t **content,
+                        const char *fname,
+                        apr_pool_t *pool)
+{
+  int i;
+  *content = NULL;
+
+  for (i = 0; !*content && (i < SVN_FS_FS__RECOVERABLE_RETRY_COUNT); ++i)
+    SVN_ERR(svn_fs_fs__try_stringbuf_from_file(content, NULL,
+                        fname, i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT,
+                        pool));
+
+  if (!*content)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Can't read '%s'"),
+                             svn_dirent_local_style(fname, pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_fs__read_number_from_stream(apr_int64_t *result,
                                    svn_boolean_t *hit_eof,
                                    svn_stream_t *stream,
@@ -135,3 +335,59 @@ svn_fs_fs__read_number_from_stream(apr_i
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__move_into_place(const char *old_filename,
+                           const char *new_filename,
+                           const char *perms_reference,
+                           apr_pool_t *pool)
+{
+  svn_error_t *err;
+
+  SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
+
+  /* Move the file into place. */
+  err = svn_io_file_rename(old_filename, new_filename, pool);
+  if (err && APR_STATUS_IS_EXDEV(err->apr_err))
+    {
+      apr_file_t *file;
+
+      /* Can't rename across devices; fall back to copying. */
+      svn_error_clear(err);
+      err = SVN_NO_ERROR;
+      SVN_ERR(svn_io_copy_file(old_filename, new_filename, TRUE, pool));
+
+      /* Flush the target of the copy to disk. */
+      SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ,
+                               APR_OS_DEFAULT, pool));
+      /* ### BH: Does this really guarantee a flush of the data written
+         ### via a completely different handle on all operating systems?
+         ###
+         ### Maybe we should perform the copy ourselves instead of making
+         ### apr do that and flush the real handle? */
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+    }
+  if (err)
+    return svn_error_trace(err);
+
+#ifdef __linux__
+  {
+    /* Linux has the unusual feature that fsync() on a file is not
+       enough to ensure that a file's directory entries have been
+       flushed to disk; you have to fsync the directory as well.
+       On other operating systems, we'd only be asking for trouble
+       by trying to open and fsync a directory. */
+    const char *dirname;
+    apr_file_t *file;
+
+    dirname = svn_dirent_dirname(new_filename, pool);
+    SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+                             pool));
+    SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+    SVN_ERR(svn_io_file_close(file, pool));
+  }
+#endif
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.h?rev=1502964&r1=1502963&r2=1502964&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/util.h Sun Jul 14 12:34:49 2013
@@ -26,11 +26,72 @@
 #include "svn_fs.h"
 #include "id.h"
 
+/* Functions for dealing with recoverable errors on mutable files
+ *
+ * Revprops, current, and txn-current files are mutable; that is, they
+ * change as part of normal fsfs operation, in constrat to revs files, or
+ * the format file, which are written once at create (or upgrade) time.
+ * When more than one host writes to the same repository, we will
+ * sometimes see these recoverable errors when accesssing these files.
+ *
+ * These errors all relate to NFS, and thus we only use this retry code if
+ * ESTALE is defined.
+ *
+ ** ESTALE
+ *
+ * In NFS v3 and under, the server doesn't track opened files.  If you
+ * unlink(2) or rename(2) a file held open by another process *on the
+ * same host*, that host's kernel typically renames the file to
+ * .nfsXXXX and automatically deletes that when it's no longer open,
+ * but this behavior is not required.
+ *
+ * For obvious reasons, this does not work *across hosts*.  No one
+ * knows about the opened file; not the server, and not the deleting
+ * client.  So the file vanishes, and the reader gets stale NFS file
+ * handle.
+ *
+ ** EIO, ENOENT
+ *
+ * Some client implementations (at least the 2.6.18.5 kernel that ships
+ * with Ubuntu Dapper) sometimes give spurious ENOENT (only on open) or
+ * even EIO errors when trying to read these files that have been renamed
+ * over on some other host.
+ *
+ ** Solution
+ *
+ * Try open and read of such files in try_stringbuf_from_file().  Call
+ * this function within a loop of SVN_FS_FS__RECOVERABLE_RETRY_COUNT
+ * iterations (though, realistically, the second try will succeed).
+ */
+
+#define SVN_FS_FS__RECOVERABLE_RETRY_COUNT 10
+
 /* Return TRUE is REV is packed in FS, FALSE otherwise. */
 svn_boolean_t
 svn_fs_fs__is_packed_rev(svn_fs_t *fs,
                          svn_revnum_t rev);
 
+/* Return TRUE is REV's props have been packed in FS, FALSE otherwise. */
+svn_boolean_t
+svn_fs_fs__is_packed_revprop(svn_fs_t *fs,
+                             svn_revnum_t rev);
+
+/* Return the full path of the rev shard directory that will contain
+ * revision REV in FS.  Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_rev_shard(svn_fs_t *fs,
+                          svn_revnum_t rev,
+                          apr_pool_t *pool);
+
+/* Return the full path of the non-packed rev file containing revision REV
+ * in FS.  Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_rev(svn_fs_t *fs,
+                    svn_revnum_t rev,
+                    apr_pool_t *pool);
+
 /* Return the path of the pack-related file that for revision REV in FS.
  * KIND specifies the file name base, e.g. "manifest" or "pack".
  * The result will be allocated in POOL.
@@ -41,6 +102,52 @@ svn_fs_fs__path_rev_packed(svn_fs_t *fs,
                            const char *kind,
                            apr_pool_t *pool);
 
+/* Return the full path of the revprop generation file in FS.
+ * Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_revprop_generation(svn_fs_t *fs,
+                                   apr_pool_t *pool);
+
+/* Return the full path of the revision properties pack shard directory
+ * that will contain the packed properties of revision REV in FS.
+ * Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_revprops_pack_shard(svn_fs_t *fs,
+                                    svn_revnum_t rev,
+                                    apr_pool_t *pool);
+
+/* Set *PATH to the path of REV in FS, whether in a pack file or not.
+   Allocate *PATH in POOL.
+
+   Note: If the caller does not have the write lock on FS, then the path is
+   not guaranteed to be correct or to remain correct after the function
+   returns, because the revision might become packed before or after this
+   call.  If a file exists at that path, then it is correct; if not, then
+   the caller should call update_min_unpacked_rev() and re-try once. */
+const char *
+svn_fs_fs__path_rev_absolute(svn_fs_t *fs,
+                             svn_revnum_t rev,
+                             apr_pool_t *pool);
+
+/* Return the full path of the revision properties shard directory that
+ * will contain the properties of revision REV in FS.
+ * Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_revprops_shard(svn_fs_t *fs,
+                               svn_revnum_t rev,
+                               apr_pool_t *pool);
+
+/* Return the full path of the non-packed revision properties file that
+ * contains the props for revision REV in FS.  Allocate the result in POOL.
+ */
+const char *
+svn_fs_fs__path_revprops(svn_fs_t *fs,
+                         svn_revnum_t rev,
+                         apr_pool_t *pool);
+
 /* Return the path of the file storing the oldest non-packed revision in FS.
  * The result will be allocated in POOL.
  */
@@ -57,6 +164,26 @@ svn_fs_fs__read_min_unpacked_rev(svn_rev
                                  svn_fs_t *fs,
                                  apr_pool_t *pool);
 
+/* Check that BUF, a nul-terminated buffer of text from file PATH,
+   contains only digits at OFFSET and beyond, raising an error if not.
+   TITLE contains a user-visible description of the file, usually the
+   short file name.
+
+   Uses POOL for temporary allocation. */
+svn_error_t *
+svn_fs_fs__check_file_buffer_numeric(const char *buf,
+                                     apr_off_t offset,
+                                     const char *path,
+                                     const char *title,
+                                     apr_pool_t *pool);
+
+/* Re-read the MIN_UNPACKED_REV member of FS from disk.
+ * Use POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__update_min_unpacked_rev(svn_fs_t *fs,
+                                   apr_pool_t *pool);
+
 /* Write a file FILENAME in directory FS_PATH, containing a single line
  * with the number REVNUM in ASCII decimal.  Move the file into place
  * atomically, overwriting any existing file.
@@ -67,6 +194,29 @@ svn_fs_fs__write_revnum_file(svn_fs_t *f
                              svn_revnum_t revnum,
                              apr_pool_t *scratch_pool);
 
+/* Read the file at PATH and return its content in *CONTENT. *CONTENT will
+ * not be modified unless the whole file was read successfully.
+ *
+ * ESTALE, EIO and ENOENT will not cause this function to return an error
+ * unless LAST_ATTEMPT has been set.  If MISSING is not NULL, indicate
+ * missing files (ENOENT) there.
+ *
+ * Use POOL for allocations.
+ */
+svn_error_t *
+svn_fs_fs__try_stringbuf_from_file(svn_stringbuf_t **content,
+                                   svn_boolean_t *missing,
+                                   const char *path,
+                                   svn_boolean_t last_attempt,
+                                   apr_pool_t *pool);
+
+/* Read the file FNAME and store the contents in *BUF.
+   Allocations are performed in POOL. */
+svn_error_t *
+svn_fs_fs__read_content(svn_stringbuf_t **content,
+                        const char *fname,
+                        apr_pool_t *pool);
+
 /* Reads a line from STREAM and converts it to a 64 bit integer to be
  * returned in *RESULT.  If we encounter eof, set *HIT_EOF and leave
  * *RESULT unchanged.  If HIT_EOF is NULL, EOF causes an "corrupt FS"
@@ -79,4 +229,17 @@ svn_fs_fs__read_number_from_stream(apr_i
                                    svn_stream_t *stream,
                                    apr_pool_t *scratch_pool);
 
+/* Move a file into place from OLD_FILENAME in the transactions
+   directory to its final location NEW_FILENAME in the repository.  On
+   Unix, match the permissions of the new file to the permissions of
+   PERMS_REFERENCE.  Temporary allocations are from POOL.
+
+   This function almost duplicates svn_io_file_move(), but it tries to
+   guarantee a flush. */
+svn_error_t *
+svn_fs_fs__move_into_place(const char *old_filename,
+                           const char *new_filename,
+                           const char *perms_reference,
+                           apr_pool_t *pool);
+
 #endif
\ No newline at end of file



Mime
View raw message