You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/03/09 11:08:53 UTC

svn commit: r1575685 [7/13] - in /subversion/branches/fsfs-ucsnorm: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/cgi/ contrib/client-side/emacs/ contrib/client-side/svn2cl/ contrib/hook-scripts/ contrib/server-side/svn...

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/pack.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/pack.c Sun Mar  9 10:08:46 2014
@@ -225,7 +225,7 @@ typedef struct pack_context_t
    * each revision range. */
   apr_array_header_t *rev_offsets;
 
-  /* temp file receiving all items referenced by REPS_INFOS.
+  /* temp file receiving all items referenced by REPS.
    * Will be filled in phase 2 and be cleared after each revision range.*/
   apr_file_t *reps_file;
 
@@ -247,14 +247,14 @@ initialize_pack_context(pack_context_t *
                         const char *pack_file_dir,
                         const char *shard_dir,
                         svn_revnum_t shard_rev,
-                        apr_size_t max_items,
+                        int max_items,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   const char *temp_dir;
-  apr_size_t max_revs = MIN(ffd->max_files_per_dir, (int)max_items);
+  int max_revs = MIN(ffd->max_files_per_dir, max_items);
   
   SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT);
   SVN_ERR_ASSERT(shard_rev % ffd->max_files_per_dir == 0);
@@ -325,7 +325,7 @@ initialize_pack_context(pack_context_t *
   context->paths = svn_prefix_tree__create(context->info_pool);
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Clean up / free all revision range specific data and files in CONTEXT.
  * Use POOL for temporary allocations.
@@ -350,7 +350,7 @@ reset_pack_context(pack_context_t *conte
   svn_pool_clear(context->info_pool);
   
   return SVN_NO_ERROR;
-};
+}
 
 /* Call this after the last revision range.  It will finalize all index files
  * for CONTEXT and close any open files.  Use POOL for temporary allocations.
@@ -391,7 +391,7 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_file_close(context->pack_file, pool));
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Efficiently copy SIZE bytes from SOURCE to DEST.  Invoke the CANCEL_FUNC
  * from CONTEXT at regular intervals.  Use POOL for allocations.
@@ -491,7 +491,7 @@ copy_item_to_temp(pack_context_t *contex
   return SVN_NO_ERROR;
 }
 
-/* Return the offset within CONTEXT->REPS_INFOS that corresponds to item
+/* Return the offset within CONTEXT->REPS that corresponds to item
  * ITEM_INDEX in  REVISION.
  */
 static int
@@ -617,7 +617,7 @@ compare_dir_entries_format7(const svn_so
   if (lhs->kind != rhs->kind)
     return lhs->kind == svn_node_dir ? -1 : 1;
 
-  return 0 - strcmp(lhs->name, rhs->name);
+  return strcmp(lhs->name, rhs->name);
 }
 
 /* Directories entries sorted by revision (decreasing - to max cache hits)
@@ -884,7 +884,6 @@ sort_reps_range(pack_context_t *context,
         {
           /* next path */
           path = path_order[i]->path;
-          rep_id = path_order[i]->rep_id;
 
           /* Pick roundest non-linear deltified node. */
           if (roundness(path_order[best]->predecessor_count)
@@ -921,6 +920,15 @@ sort_reps_range(pack_context_t *context,
   for (i = first; i < last; ++i)
     if (path_order[i])
       {
+        /* This is the first path we still have to handle. */
+        path = path_order[i]->path;
+        rep_id = path_order[i]->rep_id;
+        break;
+      }
+
+  for (i = first; i < last; ++i)
+    if (path_order[i])
+      {
         /* New path? */
         if (svn_prefix_string__compare(path, path_order[i]->path))
           {
@@ -984,16 +992,9 @@ sort_reps(pack_context_t *context)
         context->references->elt_size,
         (int (*)(const void *, const void *))compare_references);
 
-  /* Re-order noderevs like this:
-   * (1) Directories are already in front; sort directories section and
-   *     files section separately according to (2)-(4).
-   * (2) Most likely to be referenced by future pack files, in path order.
-   * (3) highest revision rep per path + dependency chain
-   * (4) Remaining reps in path, rev order
-   *
-   * We simply pick & chose from the existing path, rev order.
+  /* Directories are already in front; sort directories section and files
+   * section separately but use the same heuristics (see sub-function).
    */
-
   temp_pool = svn_pool_create(context->info_pool);
   count = context->path_order->nelts;
   temp = apr_pcalloc(temp_pool, count * sizeof(*temp));
@@ -1515,13 +1516,21 @@ pack_log_addressed(svn_fs_t *fs,
                    + 6 * sizeof(void*)
     };
 
-  apr_size_t max_items = max_mem / PER_ITEM_MEM;
+  int max_items;
   apr_array_header_t *max_ids;
   pack_context_t context = { 0 };
   int i;
   apr_size_t item_count = 0;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
+  /* Prevent integer overflow.  We use apr arrays to process the items so
+   * the maximum number of items is INT_MAX. */
+    {
+      apr_size_t temp = max_mem / PER_ITEM_MEM;
+      SVN_ERR_ASSERT(temp <= INT_MAX);
+      max_items = (int)temp;
+    }
+
   /* set up a pack context */
   SVN_ERR(initialize_pack_context(&context, fs, pack_file_dir, shard_dir,
                                   shard_rev, max_items, cancel_func,
@@ -1768,105 +1777,96 @@ pack_rev_shard(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* In the file system at FS_PATH, pack the SHARD in REVS_DIR and
- * REVPROPS_DIR containing exactly MAX_FILES_PER_DIR revisions, using POOL
- * for allocations.  REVPROPS_DIR will be NULL if revprop packing is not
- * supported.  COMPRESSION_LEVEL and MAX_PACK_SIZE will be ignored in that
- * case.
- *
- * CANCEL_FUNC and CANCEL_BATON are what you think they are; similarly
- * NOTIFY_FUNC and NOTIFY_BATON.
- *
- * If for some reason we detect a partial packing already performed, we
- * remove the pack file and start again.
- */
-static svn_error_t *
-pack_shard(const char *revs_dir,
-           const char *revsprops_dir,
-           svn_fs_t *fs,
-           apr_int64_t shard,
-           int max_files_per_dir,
-           apr_off_t max_pack_size,
-           int compression_level,
-           svn_fs_pack_notify_t notify_func,
-           void *notify_baton,
-           svn_cancel_func_t cancel_func,
-           void *cancel_baton,
-           apr_pool_t *pool)
+/* Baton struct used by pack_body(), pack_shard() and synced_pack_shard().
+   These calls are nested and for every level additional fields will be
+   available. */
+struct pack_baton
 {
-  fs_fs_data_t *ffd = fs->fsap_data;
-  const char *rev_shard_path, *rev_pack_file_dir;
-  const char *revprops_shard_path, *revprops_pack_file_dir;
+  /* Valid when entering pack_body(). */
+  svn_fs_t *fs;
+  svn_fs_pack_notify_t notify_func;
+  void *notify_baton;
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
 
-  /* Notify caller we're starting to pack this shard. */
-  if (notify_func)
-    SVN_ERR(notify_func(notify_baton, shard, svn_fs_pack_notify_start,
-                        pool));
+  /* Additional entries valid when entering pack_shard(). */
+  const char *revs_dir;
+  const char *revsprops_dir;
+  apr_int64_t shard;
 
-  /* Some useful paths. */
-  rev_pack_file_dir = svn_dirent_join(revs_dir,
-                  apr_psprintf(pool,
-                               "%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
-                               shard),
-                  pool);
-  rev_shard_path = svn_dirent_join(revs_dir,
-                           apr_psprintf(pool, "%" APR_INT64_T_FMT, shard),
-                           pool);
+  /* Additional entries valid when entering synced_pack_shard(). */
+  const char *rev_shard_path;
+};
 
-  /* pack the revision content */
-  SVN_ERR(pack_rev_shard(fs, rev_pack_file_dir, rev_shard_path,
-                         shard, max_files_per_dir, DEFAULT_MAX_MEM,
-                         cancel_func, cancel_baton, pool));
+
+/* Part of the pack process that requires global (write) synchronization.
+ * We pack the revision properties of the shard described by BATON and
+ * In the file system at FS_PATH, pack the SHARD in REVS_DIR and replace
+ * the non-packed revprop & rev shard folder(s) with the packed ones.
+ * The packed rev folder has been created prior to calling this function.
+ */
+static svn_error_t *
+synced_pack_shard(void *baton,
+                  apr_pool_t *pool)
+{
+  struct pack_baton *pb = baton;
+  fs_fs_data_t *ffd = pb->fs->fsap_data;
+  const char *revprops_shard_path, *revprops_pack_file_dir;
 
   /* if enabled, pack the revprops in an equivalent way */
-  if (revsprops_dir)
+  if (pb->revsprops_dir)
     {
-      revprops_pack_file_dir = svn_dirent_join(revsprops_dir,
+      revprops_pack_file_dir = svn_dirent_join(pb->revsprops_dir,
                    apr_psprintf(pool,
                                 "%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
-                                shard),
+                                pb->shard),
                    pool);
-      revprops_shard_path = svn_dirent_join(revsprops_dir,
-                           apr_psprintf(pool, "%" APR_INT64_T_FMT, shard),
-                           pool);
+      revprops_shard_path = svn_dirent_join(pb->revsprops_dir,
+                    apr_psprintf(pool, "%" APR_INT64_T_FMT, pb->shard),
+                    pool);
 
       SVN_ERR(svn_fs_fs__pack_revprops_shard(revprops_pack_file_dir,
                                              revprops_shard_path,
-                                             shard, max_files_per_dir,
-                                             (int)(0.9 * max_pack_size),
-                                             compression_level,
-                                             cancel_func, cancel_baton,
+                                             pb->shard,
+                                             ffd->max_files_per_dir,
+                                             (int)(0.9*ffd->revprop_pack_size),
+                                             ffd->compress_packed_revprops
+                                               ? SVN__COMPRESSION_ZLIB_DEFAULT
+                                               : SVN__COMPRESSION_NONE,
+                                             pb->cancel_func,
+                                             pb->cancel_baton,
                                              pool));
     }
 
   /* Update the min-unpacked-rev file to reflect our newly packed shard. */
-  SVN_ERR(svn_fs_fs__write_min_unpacked_rev(fs,
-                          (svn_revnum_t)((shard + 1) * max_files_per_dir),
-                          pool));
-  ffd->min_unpacked_rev = (svn_revnum_t)((shard + 1) * max_files_per_dir);
+  SVN_ERR(svn_fs_fs__write_min_unpacked_rev(pb->fs,
+                    (svn_revnum_t)((pb->shard + 1) * ffd->max_files_per_dir),
+                    pool));
+  ffd->min_unpacked_rev
+    = (svn_revnum_t)((pb->shard + 1) * ffd->max_files_per_dir);
 
   /* Finally, remove the existing shard directories.
    * For revprops, clean up older obsolete shards as well as they might
    * have been left over from an interrupted FS upgrade. */
-  SVN_ERR(svn_io_remove_dir2(rev_shard_path, TRUE,
-                             cancel_func, cancel_baton, pool));
-  if (revsprops_dir)
+  SVN_ERR(svn_io_remove_dir2(pb->rev_shard_path, TRUE,
+                             pb->cancel_func, pb->cancel_baton, pool));
+  if (pb->revsprops_dir)
     {
       svn_node_kind_t kind = svn_node_dir;
-      apr_int64_t to_cleanup = shard;
+      apr_int64_t to_cleanup = pb->shard;
       do
         {
           SVN_ERR(svn_fs_fs__delete_revprops_shard(revprops_shard_path,
                                                    to_cleanup,
-                                                   max_files_per_dir,
-                                                   cancel_func,
-                                                   cancel_baton,
+                                                   ffd->max_files_per_dir,
+                                                   pb->cancel_func,
+                                                   pb->cancel_baton,
                                                    pool));
 
           /* If the previous shard exists, clean it up as well.
              Don't try to clean up shard 0 as it we can't tell quickly
              whether it actually needs cleaning up. */
-          revprops_shard_path = svn_dirent_join(revsprops_dir,
+          revprops_shard_path = svn_dirent_join(pb->revsprops_dir,
                       apr_psprintf(pool, "%" APR_INT64_T_FMT, --to_cleanup),
                       pool);
           SVN_ERR(svn_io_check_path(revprops_shard_path, &kind, pool));
@@ -1874,23 +1874,60 @@ pack_shard(const char *revs_dir,
       while (kind == svn_node_dir && to_cleanup > 0);
     }
 
-  /* Notify caller we're starting to pack this shard. */
-  if (notify_func)
-    SVN_ERR(notify_func(notify_baton, shard, svn_fs_pack_notify_end,
-                        pool));
-
   return SVN_NO_ERROR;
 }
 
-struct pack_baton
+/* Pack the shard described by BATON.
+ *
+ * If for some reason we detect a partial packing already performed,
+ * we remove the pack file and start again.
+ */
+static svn_error_t *
+pack_shard(struct pack_baton *baton,
+           apr_pool_t *pool)
 {
-  svn_fs_t *fs;
-  svn_fs_pack_notify_t notify_func;
-  void *notify_baton;
-  svn_cancel_func_t cancel_func;
-  void *cancel_baton;
-};
+  fs_fs_data_t *ffd = baton->fs->fsap_data;
+  const char *rev_pack_file_dir;
 
+  /* Notify caller we're starting to pack this shard. */
+  if (baton->notify_func)
+    SVN_ERR(baton->notify_func(baton->notify_baton, baton->shard,
+                               svn_fs_pack_notify_start, pool));
+
+  /* Some useful paths. */
+  rev_pack_file_dir = svn_dirent_join(baton->revs_dir,
+                  apr_psprintf(pool,
+                               "%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
+                               baton->shard),
+                  pool);
+  baton->rev_shard_path = svn_dirent_join(baton->revs_dir,
+                                          apr_psprintf(pool,
+                                                       "%" APR_INT64_T_FMT,
+                                                       baton->shard),
+                                          pool);
+
+  /* pack the revision content */
+  SVN_ERR(pack_rev_shard(baton->fs, rev_pack_file_dir, baton->rev_shard_path,
+                         baton->shard, ffd->max_files_per_dir,
+                         DEFAULT_MAX_MEM, baton->cancel_func,
+                         baton->cancel_baton, pool));
+
+  /* For newer repo formats, we only acquired the pack lock so far.
+     Before modifying the repo state by switching over to the packed
+     data, we need to acquire the global (write) lock. */
+  if (ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT)
+    SVN_ERR(svn_fs_fs__with_write_lock(baton->fs, synced_pack_shard, baton,
+                                       pool));
+  else
+    SVN_ERR(synced_pack_shard(baton, pool));
+
+  /* Notify caller we're starting to pack this shard. */
+  if (baton->notify_func)
+    SVN_ERR(baton->notify_func(baton->notify_baton, baton->shard,
+                               svn_fs_pack_notify_end, pool));
+
+  return SVN_NO_ERROR;
+}
 
 /* The work-horse for svn_fs_fs__pack, called with the FS write lock.
    This implements the svn_fs_fs__with_write_lock() 'body' callback
@@ -1913,11 +1950,8 @@ pack_body(void *baton,
   struct pack_baton *pb = baton;
   fs_fs_data_t *ffd = pb->fs->fsap_data;
   apr_int64_t completed_shards;
-  apr_int64_t i;
   svn_revnum_t youngest;
   apr_pool_t *iterpool;
-  const char *rev_data_path;
-  const char *revprops_data_path = NULL;
 
   /* If the repository isn't a new enough format, we don't support packing.
      Return a friendly error to that effect. */
@@ -1940,29 +1974,22 @@ pack_body(void *baton,
   if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
     return SVN_NO_ERROR;
 
-  rev_data_path = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, pool);
+  pb->revs_dir = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, pool);
   if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
-    revprops_data_path = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR,
-                                         pool);
+    pb->revsprops_dir = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR,
+                                        pool);
 
   iterpool = svn_pool_create(pool);
-  for (i = ffd->min_unpacked_rev / ffd->max_files_per_dir;
-       i < completed_shards;
-       i++)
+  for (pb->shard = ffd->min_unpacked_rev / ffd->max_files_per_dir;
+       pb->shard < completed_shards;
+       pb->shard++)
     {
       svn_pool_clear(iterpool);
 
       if (pb->cancel_func)
         SVN_ERR(pb->cancel_func(pb->cancel_baton));
 
-      SVN_ERR(pack_shard(rev_data_path, revprops_data_path,
-                         pb->fs, i, ffd->max_files_per_dir,
-                         ffd->revprop_pack_size,
-                         ffd->compress_packed_revprops
-                           ? SVN__COMPRESSION_ZLIB_DEFAULT
-                           : SVN__COMPRESSION_NONE,
-                         pb->notify_func, pb->notify_baton,
-                         pb->cancel_func, pb->cancel_baton, iterpool));
+      SVN_ERR(pack_shard(pb, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -1978,10 +2005,33 @@ svn_fs_fs__pack(svn_fs_t *fs,
                 apr_pool_t *pool)
 {
   struct pack_baton pb = { 0 };
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_error_t *err;
+
   pb.fs = fs;
   pb.notify_func = notify_func;
   pb.notify_baton = notify_baton;
   pb.cancel_func = cancel_func;
   pb.cancel_baton = cancel_baton;
-  return svn_fs_fs__with_write_lock(fs, pack_body, &pb, pool);
+
+  if (ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT)
+    {
+      /* Newer repositories provide a pack operation specific lock.
+         Acquire it to prevent concurrent packs. */
+      apr_pool_t *subpool = svn_pool_create(pool);
+      const char *lock_path = svn_dirent_join(fs->path, PATH_PACK_LOCK_FILE,
+                                              subpool);
+      err = svn_fs_fs__get_lock_on_filesystem(lock_path, subpool);
+      if (!err)
+        err = pack_body(&pb, subpool);
+
+      svn_pool_destroy(subpool);
+    }
+  else
+    {
+      /* Use the global write lock for older repos. */
+      err = svn_fs_fs__with_write_lock(fs, pack_body, &pb, pool);
+    }
+
+  return svn_error_trace(err);
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/recovery.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/recovery.c Sun Mar  9 10:08:46 2014
@@ -276,6 +276,51 @@ recover_find_max_ids(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Part of the recovery procedure.  Given an open non-packed revision file
+   REV_FILE for REV, locate the trailer that specifies the offset to the root
+   node-id and store this offset in *ROOT_OFFSET.  Do temporary allocations in
+   POOL. */
+static svn_error_t *
+recover_get_root_offset(apr_off_t *root_offset,
+                        svn_revnum_t rev,
+                        svn_fs_fs__revision_file_t *rev_file,
+                        apr_pool_t *pool)
+{
+  char buffer[64];
+  svn_stringbuf_t *trailer;
+  apr_off_t start;
+  apr_off_t end;
+  apr_size_t len;
+
+  SVN_ERR_ASSERT(!rev_file->is_packed);
+
+  /* We will assume that the last line containing the two offsets (to the root
+     node-id and to the changed path information) will never be longer than 64
+     characters. */
+  end = 0;
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_END, &end, pool));
+
+  if (end < sizeof(buffer))
+    {
+      len = (apr_size_t)end;
+      start = 0;
+    }
+  else
+    {
+      len = sizeof(buffer);
+      start = end - sizeof(buffer);
+    }
+
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &start, pool));
+  SVN_ERR(svn_io_file_read_full2(rev_file->file, buffer, len,
+                                 NULL, NULL, pool));
+
+  trailer = svn_stringbuf_ncreate(buffer, len, pool);
+  SVN_ERR(svn_fs_fs__parse_revision_trailer(root_offset, NULL, trailer, rev));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_fs__find_max_ids(svn_fs_t *fs,
                         svn_revnum_t youngest,
@@ -286,16 +331,12 @@ svn_fs_fs__find_max_ids(svn_fs_t *fs,
   fs_fs_data_t *ffd = fs->fsap_data;
   apr_off_t root_offset;
   svn_fs_fs__revision_file_t *rev_file;
-  svn_fs_id_t *root_id;
 
   /* call this function for old repo formats only */
   SVN_ERR_ASSERT(ffd->format < SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT);
 
-  SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, youngest, pool));
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, youngest, pool));
-  SVN_ERR(svn_fs_fs__item_offset(&root_offset, fs, rev_file, youngest, NULL,
-                                 svn_fs_fs__id_item(root_id), pool));
-
+  SVN_ERR(recover_get_root_offset(&root_offset, youngest, rev_file, pool));
   SVN_ERR(recover_find_max_ids(fs, youngest, rev_file, root_offset,
                                max_node_id, max_copy_id, pool));
   SVN_ERR(svn_fs_fs__close_revision_file(rev_file));

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/structure?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/structure Sun Mar  9 10:08:46 2014
@@ -60,6 +60,7 @@ repository) is:
   current             File specifying current revision and next node/copy id
   fs-type             File identifying this filesystem as an FSFS filesystem
   write-lock          Empty file, locked to serialise writers
+  pack-lock           Empty file, locked to serialise 'svnadmin pack' (f. 7+)
   txn-current-lock    Empty file, locked to serialise 'txn-current'
   uuid                File containing the UUID of the repository
   format              File containing the format number of this filesystem
@@ -86,9 +87,19 @@ The "write-lock" file is an empty file w
 final stage of a commit and unlocked after the new "current" file has
 been moved into place to indicate that a new revision is present.  It
 is also locked during a revprop propchange while the revprop file is
-read in, mutated, and written out again.  Note that readers are never
-blocked by any operation - writers must ensure that the filesystem is
-always in a consistent state.
+read in, mutated, and written out again.  Furthermore, it will be used
+to serialize the repository structure changes during 'svnadmin pack'
+(see also next section).  Note that readers are never blocked by any
+operation - writers must ensure that the filesystem is always in a
+consistent state.
+
+The "pack-lock" file is an empty file which is locked before an 'svnadmin
+pack' operation commences.  Thus, only one process may attempt to modify
+the repository structure at a time while other processes may still read
+and write (commit) to the repository during most of the pack procedure.
+It is only available with format 7 and newer repositories.  Older formats
+use the global write-lock instead which disables commits completely
+for the duration of the pack process.
 
 The "txn-current" file is a file with a single line of text that
 contains only a base-36 number.  The current value will be used in the

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c Sun Mar  9 10:08:46 2014
@@ -147,11 +147,12 @@ serialize_representation(svn_temp_serial
                                 sizeof(*rep));
 }
 
-/* auxilliary structure representing the content of a directory array */
+/* auxiliary structure representing the content of a directory array */
 typedef struct dir_data_t
 {
-  /* number of entries in the directory */
-  apr_size_t count;
+  /* number of entries in the directory
+   * (it's int because the directory is an APR array) */
+  int count;
 
   /* number of unused dir entry buckets in the index */
   apr_size_t over_provision;
@@ -216,13 +217,13 @@ serialize_dir(apr_array_header_t *entrie
   svn_temp_serializer__context_t *context;
 
   /* calculate sizes */
-  apr_size_t count = entries->nelts;
+  int count = entries->nelts;
   apr_size_t over_provision = 2 + count / 4;
   apr_size_t entries_len =
     (count + over_provision) * sizeof(svn_fs_fs__dirent_t);
   apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
 
-  /* copy the hash entries to an auxilliary struct of known layout */
+  /* copy the hash entries to an auxiliary struct of known layout */
   dir_data.count = count;
   dir_data.over_provision = over_provision;
   dir_data.operations = 0;
@@ -483,7 +484,7 @@ svn_fs_fs__deserialize_manifest(void **o
   return SVN_NO_ERROR;
 }
 
-/* Auxilliary structure representing the content of a properties hash.
+/* Auxiliary structure representing the content of a properties hash.
    This structure is much easier to (de-)serialize than an apr_hash.
  */
 typedef struct properties_data_t
@@ -553,7 +554,7 @@ svn_fs_fs__serialize_properties(void **d
   svn_stringbuf_t *serialized;
   apr_size_t i;
 
-  /* create our auxilliary data structure */
+  /* create our auxiliary data structure */
   properties.count = apr_hash_count(hash);
   properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
   properties.values = apr_palloc(pool, sizeof(const char*) * properties.count);
@@ -594,7 +595,7 @@ svn_fs_fs__deserialize_properties(void *
   properties_data_t *properties = (properties_data_t *)data;
   size_t i;
 
-  /* de-serialize our auxilliary data structure */
+  /* de-serialize our auxiliary data structure */
   svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
   svn_temp_deserializer__resolve(properties, (void**)&properties->values);
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.h Sun Mar  9 10:08:46 2014
@@ -52,7 +52,7 @@ svn_fs_fs__noderev_deserialize(void *buf
 
 /**
  * #svn_txdelta_window_t is not sufficient for caching the data it
- * represents because data read process needs auxilliary information.
+ * represents because data read process needs auxiliary information.
  */
 typedef struct
 {

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/transaction.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/transaction.c Sun Mar  9 10:08:46 2014
@@ -317,26 +317,10 @@ unlock_proto_rev(svn_fs_t *fs,
   return with_txnlist_lock(fs, unlock_proto_rev_body, &b, pool);
 }
 
-/* Same as unlock_proto_rev(), but requires that the transaction list
-   lock is already held. */
-static svn_error_t *
-unlock_proto_rev_list_locked(svn_fs_t *fs,
-                             const svn_fs_fs__id_part_t *txn_id,
-                             void *lockcookie,
-                             apr_pool_t *pool)
-{
-  struct unlock_proto_rev_baton b;
-
-  b.txn_id = *txn_id;
-  b.lockcookie = lockcookie;
-  return unlock_proto_rev_body(fs, &b, pool);
-}
-
 /* A structure used by get_writable_proto_rev() and
    get_writable_proto_rev_body(), which see. */
 struct get_writable_proto_rev_baton
 {
-  apr_file_t **file;
   void **lockcookie;
   svn_fs_fs__id_part_t txn_id;
 };
@@ -346,9 +330,7 @@ static svn_error_t *
 get_writable_proto_rev_body(svn_fs_t *fs, const void *baton, apr_pool_t *pool)
 {
   const struct get_writable_proto_rev_baton *b = baton;
-  apr_file_t **file = b->file;
   void **lockcookie = b->lockcookie;
-  svn_error_t *err;
   fs_fs_shared_txn_data_t *txn = get_shared_txn(fs, &b->txn_id, TRUE);
 
   /* First, ensure that no thread in this process (including this one)
@@ -410,10 +392,37 @@ get_writable_proto_rev_body(svn_fs_t *fs
   /* We've successfully locked the transaction; mark it as such. */
   txn->being_written = TRUE;
 
+  return SVN_NO_ERROR;
+}
+
+/* Get a handle to the prototype revision file for transaction TXN_ID in
+   filesystem FS, and lock it for writing.  Return FILE, a file handle
+   positioned at the end of the file, and LOCKCOOKIE, a cookie that
+   should be passed to unlock_proto_rev() to unlock the file once FILE
+   has been closed.
+
+   If the prototype revision file is already locked, return error
+   SVN_ERR_FS_REP_BEING_WRITTEN.
+
+   Perform all allocations in POOL. */
+static svn_error_t *
+get_writable_proto_rev(apr_file_t **file,
+                       void **lockcookie,
+                       svn_fs_t *fs,
+                       const svn_fs_fs__id_part_t *txn_id,
+                       apr_pool_t *pool)
+{
+  struct get_writable_proto_rev_baton b;
+  svn_error_t *err;
+
+  b.lockcookie = lockcookie;
+  b.txn_id = *txn_id;
+
+  SVN_ERR(with_txnlist_lock(fs, get_writable_proto_rev_body, &b, pool));
 
   /* Now open the prototype revision file and seek to the end. */
   err = svn_io_file_open(file,
-                         svn_fs_fs__path_txn_proto_rev(fs, &b->txn_id, pool),
+                         svn_fs_fs__path_txn_proto_rev(fs, txn_id, pool),
                          APR_READ | APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT,
                          pool);
 
@@ -434,7 +443,7 @@ get_writable_proto_rev_body(svn_fs_t *fs
     {
       err = svn_error_compose_create(
               err,
-              unlock_proto_rev_list_locked(fs, &b->txn_id, *lockcookie, pool));
+              unlock_proto_rev(fs, txn_id, *lockcookie, pool));
 
       *lockcookie = NULL;
     }
@@ -442,32 +451,6 @@ get_writable_proto_rev_body(svn_fs_t *fs
   return svn_error_trace(err);
 }
 
-/* Get a handle to the prototype revision file for transaction TXN_ID in
-   filesystem FS, and lock it for writing.  Return FILE, a file handle
-   positioned at the end of the file, and LOCKCOOKIE, a cookie that
-   should be passed to unlock_proto_rev() to unlock the file once FILE
-   has been closed.
-
-   If the prototype revision file is already locked, return error
-   SVN_ERR_FS_REP_BEING_WRITTEN.
-
-   Perform all allocations in POOL. */
-static svn_error_t *
-get_writable_proto_rev(apr_file_t **file,
-                       void **lockcookie,
-                       svn_fs_t *fs,
-                       const svn_fs_fs__id_part_t *txn_id,
-                       apr_pool_t *pool)
-{
-  struct get_writable_proto_rev_baton b;
-
-  b.file = file;
-  b.lockcookie = lockcookie;
-  b.txn_id = *txn_id;
-
-  return with_txnlist_lock(fs, get_writable_proto_rev_body, &b, pool);
-}
-
 /* Callback used in the implementation of purge_shared_txn(). */
 static svn_error_t *
 purge_shared_txn_body(svn_fs_t *fs, const void *baton, apr_pool_t *pool)
@@ -1790,7 +1773,7 @@ fnv1a_checksum_finalize(apr_uint32_t *di
 
   SVN_ERR(svn_checksum_final(&checksum, context, scratch_pool));
   SVN_ERR_ASSERT(checksum->kind == svn_checksum_fnv1a_32x4);
-  *digest =  *(apr_uint32_t *)(checksum->digest);
+  *digest = ntohl(*(apr_uint32_t *)(checksum->digest));
 
   return SVN_NO_ERROR;
 }
@@ -1874,7 +1857,7 @@ shards_spanned(int *spanned,
   int shard_size = ffd->max_files_per_dir ? ffd->max_files_per_dir : 1;
 
   int count = 0;
-  int shard, last_shard = ffd->youngest_rev_cache / shard_size;
+  svn_revnum_t shard, last_shard = ffd->youngest_rev_cache / shard_size;
   while (walk-- && noderev->predecessor_count)
     {
       SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs,
@@ -2021,7 +2004,7 @@ rep_write_cleanup(void *data)
   err = svn_io_file_trunc(b->file, b->rep_offset, b->pool);
   err = svn_error_compose_create(err, svn_io_file_close(b->file, b->pool));
 
-  /* Remove our lock regardless of any preceeding errors so that the
+  /* Remove our lock regardless of any preceding errors so that the
      being_written flag is always removed and stays consistent with the
      file lock which will be removed no matter what since the pool is
      going away. */
@@ -3564,7 +3547,7 @@ fnv1a_checksum_on_file_range(apr_uint32_
   return SVN_NO_ERROR;
 }
 
-/* qsort()-compatible comparision function sorting svn_fs_fs__p2l_entry_t
+/* qsort()-compatible comparison function sorting svn_fs_fs__p2l_entry_t
  * by offset.
  */
 static int

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/tree.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/tree.c Sun Mar  9 10:08:46 2014
@@ -550,18 +550,18 @@ dag_node_cache_set(svn_fs_root_t *root,
 }
 
 
-/* Baton for find_descendents_in_cache. */
+/* Baton for find_descendants_in_cache. */
 struct fdic_baton {
   const char *path;
   apr_array_header_t *list;
   apr_pool_t *pool;
 };
 
-/* If the given item is a descendent of BATON->PATH, push
+/* If the given item is a descendant of BATON->PATH, push
  * it onto BATON->LIST (copying into BATON->POOL).  Implements
  * the svn_iter_apr_hash_cb_t prototype. */
 static svn_error_t *
-find_descendents_in_cache(void *baton,
+find_descendants_in_cache(void *baton,
                           const void *key,
                           apr_ssize_t klen,
                           void *val,
@@ -596,16 +596,16 @@ dag_node_cache_invalidate(svn_fs_root_t 
   locate_cache(&cache, NULL, root, NULL, b.pool);
 
 
-  SVN_ERR(svn_cache__iter(NULL, cache, find_descendents_in_cache,
+  SVN_ERR(svn_cache__iter(NULL, cache, find_descendants_in_cache,
                           &b, b.pool));
 
   iterpool = svn_pool_create(b.pool);
 
   for (i = 0; i < b.list->nelts; i++)
     {
-      const char *descendent = APR_ARRAY_IDX(b.list, i, const char *);
+      const char *descendant = APR_ARRAY_IDX(b.list, i, const char *);
       svn_pool_clear(iterpool);
-      SVN_ERR(svn_cache__set(cache, descendent, NULL, iterpool));
+      SVN_ERR(svn_cache__set(cache, descendant, NULL, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -860,7 +860,7 @@ get_copy_inheritance(copy_id_inherit_t *
   SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, FALSE, pool));
   copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
 
-  if (svn_fs_fs__id_compare(copyroot_id, child_id) == -1)
+  if (svn_fs_fs__id_compare(copyroot_id, child_id) == svn_fs_node_unrelated)
     return SVN_NO_ERROR;
 
   /* Determine if we are looking at the child via its original path or
@@ -1350,9 +1350,8 @@ fs_node_relation(svn_fs_node_relation_t 
   svn_boolean_t b_is_root_dir
     = (path_b[0] == '\0') || ((path_b[0] == '/') && (path_b[1] == '\0'));
 
-  /* Root paths are never related to non-root paths and path from different
-   * repository are always unrelated. */
-  if (a_is_root_dir ^ b_is_root_dir || root_a->fs != root_b->fs)
+  /* Path from different repository are always unrelated. */
+  if (root_a->fs != root_b->fs)
     {
       *relation = svn_fs_node_unrelated;
       return SVN_NO_ERROR;
@@ -1368,11 +1367,11 @@ fs_node_relation(svn_fs_node_relation_t 
 
   /* Are both (!) root paths? Then, they are related and we only test how
    * direct the relation is. */
-  if (a_is_root_dir)
+  if (a_is_root_dir && b_is_root_dir)
     {
       *relation = root_a->rev == root_b->rev
                 ? svn_fs_node_same
-                : svn_fs_node_common_anchestor;
+                : svn_fs_node_common_ancestor;
       return SVN_NO_ERROR;
     }
 
@@ -1391,7 +1390,7 @@ fs_node_relation(svn_fs_node_relation_t 
   if (svn_fs_fs__id_part_eq(&rev_item_a, &rev_item_b))
     *relation = svn_fs_node_same;
   else if (svn_fs_fs__id_part_eq(&node_id_a, &node_id_b))
-    *relation = svn_fs_node_common_anchestor;
+    *relation = svn_fs_node_common_ancestor;
   else
     *relation = svn_fs_node_unrelated;
 
@@ -1618,6 +1617,7 @@ fs_props_changed(svn_boolean_t *changed_
                  const char *path1,
                  svn_fs_root_t *root2,
                  const char *path2,
+                 svn_boolean_t strict,
                  apr_pool_t *pool)
 {
   dag_node_t *node1, *node2;
@@ -1631,7 +1631,7 @@ fs_props_changed(svn_boolean_t *changed_
   SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
   SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
   return svn_fs_fs__dag_things_different(changed_p, NULL,
-                                         node1, node2);
+                                         node1, node2, strict, pool);
 }
 
 
@@ -1868,6 +1868,7 @@ merge(svn_stringbuf_t *conflict_p,
   */
   {
     node_revision_t *tgt_nr, *anc_nr, *src_nr;
+    svn_boolean_t same;
 
     /* Get node revisions for our id's. */
     SVN_ERR(svn_fs_fs__get_node_revision(&tgt_nr, fs, target_id, pool));
@@ -1876,16 +1877,15 @@ merge(svn_stringbuf_t *conflict_p,
 
     /* Now compare the prop-keys of the skels.  Note that just because
        the keys are different -doesn't- mean the proplists have
-       different contents.  But merge() isn't concerned with contents;
-       it doesn't do a brute-force comparison on textual contents, so
-       it won't do that here either.  Checking to see if the propkey
-       atoms are `equal' is enough. */
-    if (! svn_fs_fs__noderev_same_rep_key(src_nr->prop_rep, anc_nr->prop_rep))
+       different contents. */
+    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, src_nr, anc_nr, TRUE, pool));
+    if (! same)
       return conflict_err(conflict_p, target_path);
 
     /* The directory entries got changed in the repository but the directory
        properties did not. */
-    if (! svn_fs_fs__noderev_same_rep_key(tgt_nr->prop_rep, anc_nr->prop_rep))
+    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, tgt_nr, anc_nr, TRUE, pool));
+    if (! same)
       {
         /* There is an incoming prop change for this directory.
            We will accept it only if the directory changes were mere updates
@@ -1957,7 +1957,7 @@ merge(svn_stringbuf_t *conflict_p,
                                                s_entry->id,
                                                s_entry->kind,
                                                txn_id,
-                                               iterpool));
+                                               pool));
             }
           else
             {
@@ -3343,6 +3343,7 @@ fs_contents_changed(svn_boolean_t *chang
                     const char *path1,
                     svn_fs_root_t *root2,
                     const char *path2,
+                    svn_boolean_t strict,
                     apr_pool_t *pool)
 {
   dag_node_t *node1, *node2;
@@ -3371,7 +3372,7 @@ fs_contents_changed(svn_boolean_t *chang
   SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
   SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
   return svn_fs_fs__dag_things_different(NULL, changed_p,
-                                         node1, node2);
+                                         node1, node2, strict, pool);
 }
 
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/verify.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/verify.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/verify.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/verify.c Sun Mar  9 10:08:46 2014
@@ -469,7 +469,7 @@ expected_streamed_checksum(apr_file_t *f
 
   SVN_ERR(svn_checksum_final(&checksum, context, pool));
   SVN_ERR(expected_checksum(file, entry,
-                            *(apr_uint32_t *)checksum->digest,
+                            ntohl(*(apr_uint32_t *)checksum->digest),
                             pool));
 
   return SVN_NO_ERROR;

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_util/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -7,5 +7,5 @@ Debug
 *.o
 *~
 .*~
-
-
+libsvn_fs_util.pc.in
+libsvn_fs_util.pc

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_util/fs-util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_util/fs-util.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_util/fs-util.c Sun Mar  9 10:08:46 2014
@@ -286,3 +286,40 @@ svn_fs__compatible_version(svn_version_t
   *compatible_version = version;
   return SVN_NO_ERROR;
 }
+
+svn_boolean_t
+svn_fs__prop_lists_equal(apr_hash_t *a,
+                         apr_hash_t *b,
+                         apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+
+  /* Quick checks and special cases. */
+  if (a == b)
+    return TRUE;
+
+  if (a == NULL)
+    return apr_hash_count(b) == 0;
+  if (b == NULL)
+    return apr_hash_count(a) == 0;
+
+  if (apr_hash_count(a) != apr_hash_count(b))
+    return FALSE;
+
+  /* Compare prop by prop. */
+  for (hi = apr_hash_first(pool, a); hi; hi = apr_hash_next(hi))
+    {
+      const char *key;
+      apr_ssize_t klen;
+      svn_string_t *val_a, *val_b;
+
+      apr_hash_this(hi, (const void **)&key, &klen, (void **)&val_a);
+      val_b = apr_hash_get(b, key, klen);
+
+      if (!val_b || !svn_string_compare(val_a, val_b))
+        return FALSE;
+    }
+
+  /* No difference found. */
+  return TRUE;
+}

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -9,3 +9,5 @@ Release
 .*~
 rep-cache-db.h
 revprops-db.h
+libsvn_fs_x.pc.in
+libsvn_fs_x.pc

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/libsvn_fs_x:r1568883-1575684

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/cached_data.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/cached_data.c Sun Mar  9 10:08:46 2014
@@ -2033,43 +2033,38 @@ parse_dir_entries(apr_hash_t **entries_p
 }
 
 /* Return the cache object in FS responsible to storing the directory the
- * NODEREV plus the corresponding *KEY.  If no cache exists, return NULL.
- * PAIR_KEY must point to some key struct, which does not need to be
- * initialized.  We use it to avoid dynamic allocation.
+ * NODEREV plus the corresponding pre-allocated *KEY.
  */
 static svn_cache__t *
 locate_dir_cache(svn_fs_t *fs,
-                 const void **key,
-                 pair_cache_key_t *pair_key,
+                 svn_fs_x__id_part_t *key,
                  node_revision_t *noderev,
                  apr_pool_t *pool)
 {
   fs_x_data_t *ffd = fs->fsap_data;
   if (svn_fs_x__id_is_txn(noderev->id))
     {
-      /* data in txns requires the expensive fs_id-based addressing mode */
-      *key = svn_fs_x__id_unparse(noderev->id, pool)->data;
-      return ffd->txn_dir_cache;
+      /* data in txns must be addressed by ID since the representation has
+         not been created, yet. */
+      *key = *svn_fs_x__id_noderev_id(noderev->id);
     }
   else
     {
       /* committed data can use simple rev,item pairs */
       if (noderev->data_rep)
         {
-          pair_key->revision
-            = svn_fs_x__get_revnum(noderev->data_rep->id.change_set);
-          pair_key->second = noderev->data_rep->id.number;
-          *key = pair_key;
+          *key = noderev->data_rep->id;
         }
       else
         {
           /* no data rep -> empty directory.
-             A NULL key causes a cache miss. */
-          *key = NULL;
+             Use a key that does definitely not clash with non-NULL reps. */
+          key->change_set = SVN_FS_X__INVALID_CHANGE_SET;
+          key->number = SVN_FS_X__ITEM_INDEX_UNUSED;
         }
-
-      return ffd->dir_cache;
     }
+
+  return ffd->dir_cache;
 }
 
 svn_error_t *
@@ -2078,17 +2073,16 @@ svn_fs_x__rep_contents_dir(apr_hash_t **
                            node_revision_t *noderev,
                            apr_pool_t *pool)
 {
-  pair_cache_key_t pair_key = { 0 };
-  const void *key;
+  svn_fs_x__id_part_t key;
   apr_hash_t *unparsed_entries, *parsed_entries;
 
   /* find the cache we may use */
-  svn_cache__t *cache = locate_dir_cache(fs, &key, &pair_key, noderev, pool);
+  svn_cache__t *cache = locate_dir_cache(fs, &key, noderev, pool);
   if (cache)
     {
       svn_boolean_t found;
 
-      SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, key, pool));
+      SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, &key, pool));
       if (found)
         return SVN_NO_ERROR;
     }
@@ -2101,7 +2095,7 @@ svn_fs_x__rep_contents_dir(apr_hash_t **
 
   /* Update the cache, if we are to use one. */
   if (cache)
-    SVN_ERR(svn_cache__set(cache, key, parsed_entries, pool));
+    SVN_ERR(svn_cache__set(cache, &key, parsed_entries, pool));
 
   *entries_p = parsed_entries;
   return SVN_NO_ERROR;
@@ -2118,17 +2112,15 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
   svn_boolean_t found = FALSE;
 
   /* find the cache we may use */
-  pair_cache_key_t pair_key = { 0 };
-  const void *key;
-  svn_cache__t *cache = locate_dir_cache(fs, &key, &pair_key, noderev,
-                                         scratch_pool);
+  svn_fs_x__id_part_t key;
+  svn_cache__t *cache = locate_dir_cache(fs, &key, noderev, scratch_pool);
   if (cache)
     {
       /* Cache lookup. */
       SVN_ERR(svn_cache__get_partial((void **)dirent,
                                      &found,
                                      cache,
-                                     key,
+                                     &key,
                                      svn_fs_x__extract_dir_entry,
                                      (void*)name,
                                      result_pool));
@@ -2144,7 +2136,7 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
       /* read the dir from the file system. It will probably be put it
          into the cache for faster lookup in future calls. */
       SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev,
-                                          scratch_pool));
+                                         scratch_pool));
 
       /* find desired entry and return a copy in POOL, if found */
       entry = svn_hash_gets(entries, name);

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/caching.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/caching.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/caching.c Sun Mar  9 10:08:46 2014
@@ -469,7 +469,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
                        1024, 8,
                        svn_fs_x__serialize_dir_entries,
                        svn_fs_x__deserialize_dir_entries,
-                       sizeof(pair_cache_key_t),
+                       sizeof(svn_fs_x__id_part_t),
                        apr_pstrcat(pool, prefix, "DIR", SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
                        fs,
@@ -754,114 +754,3 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
 
   return SVN_NO_ERROR;
 }
-
-/* Baton to be used for the remove_txn_cache() pool cleanup function, */
-struct txn_cleanup_baton_t
-{
-  /* the cache to reset */
-  svn_cache__t *txn_cache;
-
-  /* the position where to reset it */
-  svn_cache__t **to_reset;
-};
-
-/* APR pool cleanup handler that will reset the cache pointer given in
-   BATON_VOID. */
-static apr_status_t
-remove_txn_cache(void *baton_void)
-{
-  struct txn_cleanup_baton_t *baton = baton_void;
-
-  /* be careful not to hurt performance by resetting newer txn's caches. */
-  if (*baton->to_reset == baton->txn_cache)
-    {
-     /* This is equivalent to calling svn_fs_x__reset_txn_caches(). */
-      *baton->to_reset  = NULL;
-    }
-
-  return  APR_SUCCESS;
-}
-
-/* This function sets / registers the required callbacks for a given
- * transaction-specific *CACHE object, if CACHE is not NULL and a no-op
- * otherwise. In particular, it will ensure that *CACHE gets reset to NULL
- * upon POOL destruction latest.
- */
-static void
-init_txn_callbacks(svn_cache__t **cache,
-                   apr_pool_t *pool)
-{
-  if (*cache != NULL)
-    {
-      struct txn_cleanup_baton_t *baton;
-
-      baton = apr_palloc(pool, sizeof(*baton));
-      baton->txn_cache = *cache;
-      baton->to_reset = cache;
-
-      apr_pool_cleanup_register(pool,
-                                baton,
-                                remove_txn_cache,
-                                apr_pool_cleanup_null);
-    }
-}
-
-svn_error_t *
-svn_fs_x__initialize_txn_caches(svn_fs_t *fs,
-                                const char *txn_id,
-                                apr_pool_t *pool)
-{
-  fs_x_data_t *ffd = fs->fsap_data;
-
-  /* Transaction content needs to be carefully prefixed to virtually
-     eliminate any chance for conflicts. The (repo, txn_id) pair
-     should be unique but if a transaction fails, it might be possible
-     to start a new transaction later that receives the same id.
-     Therefore, throw in a uuid as well - just to be sure. */
-  const char *prefix = apr_pstrcat(pool,
-                                   "fsx:", fs->uuid,
-                                   "/", fs->path,
-                                   ":", txn_id,
-                                   ":", svn_uuid_generate(pool), ":",
-                                   SVN_VA_NULL);
-
-  /* We don't support caching for concurrent transactions in the SAME
-   * FSX session. Maybe, you forgot to clean POOL. */
-  if (ffd->txn_dir_cache != NULL || ffd->concurrent_transactions)
-    {
-      ffd->txn_dir_cache = NULL;
-      ffd->concurrent_transactions = TRUE;
-
-      return SVN_NO_ERROR;
-    }
-
-  /* create a txn-local directory cache */
-  SVN_ERR(create_cache(&ffd->txn_dir_cache,
-                       NULL,
-                       svn_cache__get_global_membuffer_cache(),
-                       1024, 8,
-                       svn_fs_x__serialize_dir_entries,
-                       svn_fs_x__deserialize_dir_entries,
-                       APR_HASH_KEY_STRING,
-                       apr_pstrcat(pool, prefix, "TXNDIR",
-                                   SVN_VA_NULL),
-                       0,
-                       fs,
-                       TRUE,
-                       pool));
-
-  /* reset the transaction-specific cache if the pool gets cleaned up. */
-  init_txn_callbacks(&(ffd->txn_dir_cache), pool);
-
-  return SVN_NO_ERROR;
-}
-
-void
-svn_fs_x__reset_txn_caches(svn_fs_t *fs)
-{
-  /* we can always just reset the caches. This may degrade performance but
-   * can never cause in incorrect behavior. */
-
-  fs_x_data_t *ffd = fs->fsap_data;
-  ffd->txn_dir_cache = NULL;
-}

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.c Sun Mar  9 10:08:46 2014
@@ -1258,29 +1258,37 @@ svn_error_t *
 svn_fs_x__dag_things_different(svn_boolean_t *props_changed,
                                svn_boolean_t *contents_changed,
                                dag_node_t *node1,
-                               dag_node_t *node2)
+                               dag_node_t *node2,
+                               svn_boolean_t strict,
+                               apr_pool_t *pool)
 {
   node_revision_t *noderev1, *noderev2;
+  svn_fs_t *fs;
+  svn_boolean_t same;
 
   /* If we have no place to store our results, don't bother doing
      anything. */
   if (! props_changed && ! contents_changed)
     return SVN_NO_ERROR;
 
+  fs = svn_fs_x__dag_get_fs(node1);
+
   /* The node revision skels for these two nodes. */
   SVN_ERR(get_node_revision(&noderev1, node1));
   SVN_ERR(get_node_revision(&noderev2, node2));
 
   /* Compare property keys. */
   if (props_changed != NULL)
-    *props_changed = (! svn_fs_x__noderev_same_rep_key(noderev1->prop_rep,
-                                                       noderev2->prop_rep));
+    {
+      SVN_ERR(svn_fs_x__prop_rep_equal(&same, fs, noderev1, noderev2,
+                                       strict, pool));
+      *props_changed = !same;
+    }
 
   /* Compare contents keys. */
   if (contents_changed != NULL)
-    *contents_changed =
-      (! svn_fs_x__noderev_same_rep_key(noderev1->data_rep,
-                                        noderev2->data_rep));
+    *contents_changed = !svn_fs_x__file_text_rep_equal(noderev1->data_rep,
+                                                       noderev2->data_rep);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/dag.h Sun Mar  9 10:08:46 2014
@@ -532,27 +532,25 @@ svn_error_t *svn_fs_x__dag_copy(dag_node
 
 /* Comparison */
 
-/* Find out what is the same between two nodes.
+/* Find out what is the same between two nodes.  If STRICT is FALSE,
+   this function may report false positives, i.e. report changes even
+   if the resulting contents / props are equal.
 
    If PROPS_CHANGED is non-null, set *PROPS_CHANGED to 1 if the two
    nodes have different property lists, or to 0 if same.
 
    If CONTENTS_CHANGED is non-null, set *CONTENTS_CHANGED to 1 if the
-   two nodes have different contents, or to 0 if same.  For files,
-   file contents are compared; for directories, the entries lists are
-   compared.  If one is a file and the other is a directory, the one's
-   contents will be compared to the other's entries list.  (Not
-   terribly useful, I suppose, but that's the caller's business.)
-
-   ### todo: This function only compares rep keys at the moment.  This
-   may leave us with a slight chance of a false positive, though I
-   don't really see how that would happen in practice.  Nevertheless,
-   it should probably be fixed.
+   two nodes have different contents, or to 0 if same.  NODE1 and NODE2
+   must refer to files from the same filesystem.
+
+   Use POOL for temporary allocations.
  */
 svn_error_t *svn_fs_x__dag_things_different(svn_boolean_t *props_changed,
                                             svn_boolean_t *contents_changed,
                                             dag_node_t *node1,
-                                            dag_node_t *node2);
+                                            dag_node_t *node2,
+                                            svn_boolean_t strict,
+                                            apr_pool_t *pool);
 
 
 /* Set *REV and *PATH to the copyroot revision and path of node NODE, or

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs.h Sun Mar  9 10:08:46 2014
@@ -204,11 +204,11 @@ typedef struct pair_cache_key_t
   apr_uint64_t second;
 } pair_cache_key_t;
 
-/* Key type that identifies a represenation / rep header. */
+/* Key type that identifies a representation / rep header. */
 typedef struct representation_cache_key_t
 {
   /* Revision that contains the representation */
-  apr_uint32_t revision;
+  svn_revnum_t revision;
 
   /* Packed or non-packed representation? */
   svn_boolean_t is_packed;
@@ -363,13 +363,6 @@ typedef struct fs_x_data_t
   /* TRUE while the we hold a lock on the write lock file. */
   svn_boolean_t has_write_lock;
 
-  /* If set, there are or have been more than one concurrent transaction */
-  svn_boolean_t concurrent_transactions;
-
-  /* Temporary cache for changed directories yet to be committed; maps from
-     unparsed FS ID to ###x.  NULL outside transactions. */
-  svn_cache__t *txn_dir_cache;
-
   /* Data shared between all svn_fs_t objects for a given filesystem. */
   fs_x_shared_data_t *shared;
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.c Sun Mar  9 10:08:46 2014
@@ -638,19 +638,88 @@ svn_fs_x__file_length(svn_filesize_t *le
 }
 
 svn_boolean_t
-svn_fs_x__noderev_same_rep_key(representation_t *a,
-                               representation_t *b)
+svn_fs_x__file_text_rep_equal(representation_t *a,
+                              representation_t *b)
 {
-  if (a == b)
+  svn_boolean_t a_empty = a == NULL || a->expanded_size == 0;
+  svn_boolean_t b_empty = b == NULL || b->expanded_size == 0;
+
+  /* This makes sure that neither rep will be NULL later on */
+  if (a_empty && b_empty)
     return TRUE;
 
-  if (a == NULL || b == NULL)
+  if (a_empty != b_empty)
     return FALSE;
 
-  return svn_fs_x__id_part_eq(&a->id, &b->id);
+  /* Same physical representation?  Note that these IDs are always up-to-date
+     instead of e.g. being set lazily. */
+  if (svn_fs_x__id_part_eq(&a->id, &b->id))
+    return TRUE;
+
+  /* Contents are equal if the checksums match.  These are also always known.
+   */
+  return memcmp(a->md5_digest, b->md5_digest, sizeof(a->md5_digest)) == 0
+      && memcmp(a->sha1_digest, b->sha1_digest, sizeof(a->sha1_digest)) == 0;
 }
 
 svn_error_t *
+svn_fs_x__prop_rep_equal(svn_boolean_t *equal,
+                         svn_fs_t *fs,
+                         node_revision_t *a,
+                         node_revision_t *b,
+                         svn_boolean_t strict,
+                         apr_pool_t *scratch_pool)
+{
+  representation_t *rep_a = a->prop_rep;
+  representation_t *rep_b = b->prop_rep;
+  apr_hash_t *proplist_a;
+  apr_hash_t *proplist_b;
+
+  /* Mainly for a==b==NULL */
+  if (rep_a == rep_b)
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  /* Committed property lists can be compared quickly */
+  if (   rep_a && rep_b
+      && svn_fs_x__is_revision(rep_a->id.change_set)
+      && svn_fs_x__is_revision(rep_b->id.change_set))
+    {
+      /* MD5 must be given. Having the same checksum is good enough for
+         accepting the prop lists as equal. */
+      *equal = memcmp(rep_a->md5_digest, rep_b->md5_digest,
+                      sizeof(rep_a->md5_digest)) == 0;
+      return SVN_NO_ERROR;
+    }
+
+  /* Same path in same txn? */
+  if (svn_fs_x__id_eq(a->id, b->id))
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  /* Skip the expensive bits unless we are in strict mode.
+     Simply assume that there is a different. */
+  if (!strict)
+    {
+      *equal = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  /* At least one of the reps has been modified in a txn.
+     Fetch and compare them. */
+  SVN_ERR(svn_fs_x__get_proplist(&proplist_a, fs, a, scratch_pool));
+  SVN_ERR(svn_fs_x__get_proplist(&proplist_b, fs, b, scratch_pool));
+
+  *equal = svn_fs__prop_lists_equal(proplist_a, proplist_b, scratch_pool);
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_fs_x__file_checksum(svn_checksum_t **checksum,
                         node_revision_t *noderev,
                         svn_checksum_kind_t kind,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/fs_x.h Sun Mar  9 10:08:46 2014
@@ -88,10 +88,21 @@ svn_error_t *svn_fs_x__file_length(svn_f
                                    node_revision_t *noderev,
                                    apr_pool_t *pool);
 
-/* Return TRUE if the representation keys in A and B both point to the
-   same representation, else return FALSE. */
-svn_boolean_t svn_fs_x__noderev_same_rep_key(representation_t *a,
-                                             representation_t *b);
+/* Return TRUE if the representations in A and B have equal contents, else
+   return FALSE. */
+svn_boolean_t svn_fs_x__file_text_rep_equal(representation_t *a,
+                                            representation_t *b);
+
+/* Set *EQUAL to TRUE if the property representations in A and B within FS
+   have equal contents, else set it to FALSE.  If STRICT is not set, allow
+   for false negatives.
+   Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *svn_fs_x__prop_rep_equal(svn_boolean_t *equal,
+                                      svn_fs_t *fs,
+                                      node_revision_t *a,
+                                      node_revision_t *b,
+                                      svn_boolean_t strict,
+                                      apr_pool_t *scratch_pool);
 
 
 /* Return a copy of the representation REP allocated from POOL. */
@@ -214,20 +225,4 @@ svn_fs_x__get_node_origin(const svn_fs_i
 svn_error_t *
 svn_fs_x__initialize_caches(svn_fs_t *fs, apr_pool_t *pool);
 
-/* Initialize all transaction-local caches in FS according to the global
-   cache settings and make TXN_ID part of their key space. Use POOL for
-   allocations.
-
-   Please note that it is permissible for this function to set some or all
-   of these caches to NULL, regardless of any setting. */
-svn_error_t *
-svn_fs_x__initialize_txn_caches(svn_fs_t *fs,
-                                const char *txn_id,
-                                apr_pool_t *pool);
-
-/* Resets the svn_cache__t structures local to the current transaction in FS.
-   Calling it more than once per txn or from outside any txn is allowed. */
-void
-svn_fs_x__reset_txn_caches(svn_fs_t *fs);
-
 #endif

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/hotcopy.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/hotcopy.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/hotcopy.c Sun Mar  9 10:08:46 2014
@@ -491,7 +491,7 @@ struct hotcopy_body_baton {
   svn_boolean_t incremental;
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
-} hotcopy_body_baton;
+};
 
 /* Perform a hotcopy, either normal or incremental.
  *

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.c Sun Mar  9 10:08:46 2014
@@ -272,13 +272,14 @@ svn_fs_x__id_check_related(const svn_fs_
 }
 
 
-int
+svn_fs_node_relation_t
 svn_fs_x__id_compare(const svn_fs_id_t *a,
                      const svn_fs_id_t *b)
 {
   if (svn_fs_x__id_eq(a, b))
-    return 0;
-  return (svn_fs_x__id_check_related(a, b) ? 1 : -1);
+    return svn_fs_node_same;
+  return (svn_fs_x__id_check_related(a, b) ? svn_fs_node_common_ancestor
+                                           : svn_fs_node_unrelated);
 }
 
 int
@@ -341,6 +342,7 @@ svn_fs_id_t *
 svn_fs_x__id_txn_create(const svn_fs_x__id_part_t *node_id,
                         const svn_fs_x__id_part_t *copy_id,
                         svn_fs_x__txn_id_t txn_id,
+                        apr_uint64_t item,
                         apr_pool_t *pool)
 {
   fs_x__id_t *id = apr_pcalloc(pool, sizeof(*id));
@@ -349,6 +351,7 @@ svn_fs_x__id_txn_create(const svn_fs_x__
   id->copy_id = *copy_id;
 
   id->noderev_id.change_set = svn_fs_x__change_set_by_txn(txn_id);
+  id->noderev_id.number = item;
 
   id->generic_id.vtable = &id_vtable;
   id->generic_id.fsap_data = id;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/id.h Sun Mar  9 10:08:46 2014
@@ -126,9 +126,9 @@ svn_boolean_t svn_fs_x__id_eq(const svn_
 svn_boolean_t svn_fs_x__id_check_related(const svn_fs_id_t *a,
                                          const svn_fs_id_t *b);
 
-/* Return 0 if A and B are equal, 1 if they are related, -1 otherwise. */
-int svn_fs_x__id_compare(const svn_fs_id_t *a,
-                         const svn_fs_id_t *b);
+/* Return the noderev relationship between A and B. */
+svn_fs_node_relation_t svn_fs_x__id_compare(const svn_fs_id_t *a,
+                                            const svn_fs_id_t *b);
 
 /* Return 0 if A and B are equal, 1 if A is "greater than" B, -1 otherwise. */
 int svn_fs_x__id_part_compare(const svn_fs_x__id_part_t *a,
@@ -142,11 +142,12 @@ svn_fs_id_t *svn_fs_x__id_txn_create_roo
 svn_fs_id_t *svn_fs_x__id_create_root(const svn_revnum_t revision,
                                       apr_pool_t *pool);
 
-/* Create an ID within a transaction based on NODE_ID, COPY_ID, and
-   TXN_ID, allocated in POOL. */
+/* Create an ID within a transaction based on NODE_ID, COPY_ID, TXN_ID
+   and ITEM number, allocated in POOL. */
 svn_fs_id_t *svn_fs_x__id_txn_create(const svn_fs_x__id_part_t *node_id,
                                      const svn_fs_x__id_part_t *copy_id,
                                      svn_fs_x__txn_id_t txn_id,
+                                     apr_uint64_t item,
                                      apr_pool_t *pool);
 
 /* Create a permanent ID based on NODE_ID, COPY_ID and NODEREV_ID,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/index.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/index.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/index.c Sun Mar  9 10:08:46 2014
@@ -101,7 +101,7 @@ typedef struct l2p_page_t
   apr_uint32_t *sub_items;
 } l2p_page_t;
 
-/* All of the log-to-phys proto index file consist of entires of this type.
+/* All of the log-to-phys proto index file consist of entries of this type.
  */
 typedef struct l2p_proto_entry_t
 {
@@ -299,7 +299,7 @@ packed_stream_read(packed_number_stream_
   stream->current = 0;
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Create and open a packed number stream reading from FILE_NAME and
  * return it in *STREAM.  Access the file in chunks of BLOCK_SIZE bytes.
@@ -439,10 +439,7 @@ svn_error_t *
 svn_fs_x__l2p_proto_index_add_revision(apr_file_t *proto_index,
                                        apr_pool_t *pool)
 {
-  l2p_proto_entry_t entry;
-  entry.offset = 0;
-  entry.item_index = 0;
-
+  l2p_proto_entry_t entry = { 0 };
   return svn_error_trace(write_entry_to_proto_index(proto_index, entry,
                                                     pool));
 }
@@ -454,7 +451,7 @@ svn_fs_x__l2p_proto_index_add_entry(apr_
                                     apr_uint64_t item_index,
                                     apr_pool_t *pool)
 {
-  l2p_proto_entry_t entry;
+  l2p_proto_entry_t entry = { 0 };
 
   /* make sure the conversion to uint64 works */
   SVN_ERR_ASSERT(offset >= -1);
@@ -559,7 +556,7 @@ compare_l2p_entries_by_offset(const l2p_
 
 /* Write the log-2-phys index page description for the l2p_page_entry_t
  * array ENTRIES, starting with element START up to but not including END.
- * Write the resulting represenation into BUFFER.  Use POOL for tempoary
+ * Write the resulting representation into BUFFER.  Use POOL for tempoary
  * allocations.
  */
 static svn_error_t *

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/low_level.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/low_level.c Sun Mar  9 10:08:46 2014
@@ -563,14 +563,16 @@ svn_fs_x__unparse_representation(represe
 {
   if (!rep->has_sha1)
     return svn_stringbuf_createf
-            (pool, "%ld %" APR_INT64_T_FMT " %" SVN_FILESIZE_T_FMT
+            (pool,
+             "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
              " %" SVN_FILESIZE_T_FMT " %s",
              rep->id.change_set, rep->id.number, rep->size,
              rep->expanded_size,
              format_digest(rep->md5_digest, svn_checksum_md5, FALSE, pool));
 
   return svn_stringbuf_createf
-          (pool, "%ld %" APR_INT64_T_FMT " %" SVN_FILESIZE_T_FMT
+          (pool,
+           "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
            " %" SVN_FILESIZE_T_FMT " %s %s",
            rep->id.change_set, rep->id.number, rep->size,
            rep->expanded_size,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.c Sun Mar  9 10:08:46 2014
@@ -177,7 +177,7 @@ struct svn_fs_x__noderevs_t
 };
 
 svn_fs_x__noderevs_t *
-svn_fs_x__noderevs_create(apr_size_t initial_count,
+svn_fs_x__noderevs_create(int initial_count,
                           apr_pool_t* pool)
 {
   svn_fs_x__noderevs_t *noderevs = apr_palloc(pool, sizeof(*noderevs));
@@ -588,7 +588,7 @@ svn_fs_x__write_noderevs_container(svn_s
     svn_packed__create_int_substream(ids_stream, TRUE, FALSE);
 
   svn_packed__create_int_substream(noderevs_stream, FALSE, FALSE);
-  for (i = 0; i < 12; ++i)
+  for (i = 0; i < 11; ++i)
     svn_packed__create_int_substream(noderevs_stream, TRUE, FALSE);
 
   /* serialize ids array */
@@ -656,7 +656,7 @@ read_reps(apr_array_header_t **reps_p,
   apr_size_t count
     = svn_packed__int_count(svn_packed__first_int_substream(rep_stream));
   apr_array_header_t *reps
-    = apr_array_make(pool, count, sizeof(binary_representation_t));
+    = apr_array_make(pool, (int)count, sizeof(binary_representation_t));
 
   for (i = 0; i < count; ++i)
     {

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/noderevs.h Sun Mar  9 10:08:46 2014
@@ -50,7 +50,7 @@ typedef struct svn_fs_x__noderevs_t svn_
  * INITIAL_COUNT node_revision_t objects.  Allocate the result in POOL.
  */
 svn_fs_x__noderevs_t *
-svn_fs_x__noderevs_create(apr_size_t initial_count,
+svn_fs_x__noderevs_create(int initial_count,
                           apr_pool_t *pool);
 
 /* Add NODEREV to the CONTAINER. Return the index that identifies the new

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/pack.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/pack.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/pack.c Sun Mar  9 10:08:46 2014
@@ -229,17 +229,17 @@ initialize_pack_context(pack_context_t *
                         const char *pack_file_dir,
                         const char *shard_dir,
                         svn_revnum_t shard_rev,
-                        apr_size_t max_items,
+                        int max_items,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         apr_pool_t *pool)
 {
   fs_x_data_t *ffd = fs->fsap_data;
   const char *temp_dir;
-  apr_size_t max_revs = MIN(ffd->max_files_per_dir, (int)max_items);
-  
+  apr_size_t max_revs = MIN(ffd->max_files_per_dir, max_items);
+
   SVN_ERR_ASSERT(shard_rev % ffd->max_files_per_dir == 0);
-  
+
   /* where we will place our various temp files */
   SVN_ERR(svn_io_temp_dir(&temp_dir, pool));
 
@@ -304,7 +304,7 @@ initialize_pack_context(pack_context_t *
   context->paths = svn_prefix_tree__create(context->info_pool);
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Clean up / free all revision range specific data and files in CONTEXT.
  * Use POOL for temporary allocations.
@@ -329,7 +329,7 @@ reset_pack_context(pack_context_t *conte
   svn_pool_clear(context->info_pool);
   
   return SVN_NO_ERROR;
-};
+}
 
 /* Call this after the last revision range.  It will finalize all index files
  * for CONTEXT and close any open files.  Use POOL for temporary allocations.
@@ -372,7 +372,7 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_file_close(context->pack_file, pool));
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Efficiently copy SIZE bytes from SOURCE to DEST.  Invoke the CANCEL_FUNC
  * from CONTEXT at regular intervals.  Use POOL for allocations.
@@ -1985,7 +1985,9 @@ pack_log_addressed(svn_fs_t *fs,
                    + 6 * sizeof(void*)
     };
 
-  apr_size_t max_items = max_mem / PER_ITEM_MEM;
+  int max_items = max_mem / PER_ITEM_MEM > INT_MAX
+                ? INT_MAX
+                : (int)(max_mem / PER_ITEM_MEM);
   apr_array_header_t *max_ids;
   pack_context_t context = { 0 };
   int i;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/reps.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/reps.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/reps.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/reps.c Sun Mar  9 10:08:46 2014
@@ -622,7 +622,7 @@ svn_fs_x__reps_get(svn_fs_x__rep_extract
   result->result = svn_stringbuf_create_empty(pool);
   result->pool = pool;
 
-  /* fill all the bits of the result that we can, i.e. all but bits comming
+  /* fill all the bits of the result that we can, i.e. all but bits coming
    * from base representations */
   get_text(result, container, first, last - first);
   *extractor = result;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/string_table.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/string_table.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/string_table.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/string_table.c Sun Mar  9 10:08:46 2014
@@ -137,29 +137,29 @@ balance(builder_table_t *table,
         builder_string_t **parent,
         builder_string_t *node)
 {
-  unsigned left_hight = node->left ? node->left->depth + 1 : 0;
-  unsigned right_hight = node->right ? node->right->depth + 1 : 0;
+  apr_size_t left_height = node->left ? node->left->depth + 1 : 0;
+  apr_size_t right_height = node->right ? node->right->depth + 1 : 0;
 
-  if (left_hight > right_hight + 1)
+  if (left_height > right_height + 1)
     {
       builder_string_t *temp = node->left->right;
       node->left->right = node;
       *parent = node->left;
       node->left = temp;
       
-      --left_hight;
+      --left_height;
     }
-  else if (left_hight + 1 < right_hight)
+  else if (left_height + 1 < right_height)
     {
       builder_string_t *temp = node->right->left;
       *parent = node->right;
       node->right->left = node;
       node->right = temp;
 
-      --right_hight;
+      --right_height;
     }
 
-  node->depth = MAX(left_hight, right_hight);
+  node->depth = MAX(left_height, right_height);
 }
 
 static apr_uint16_t
@@ -274,7 +274,7 @@ svn_fs_x__string_table_builder_add(strin
                                    const char *string,
                                    apr_size_t len)
 {
-  apr_size_t result = -1;
+  apr_size_t result;
   builder_table_t *table = APR_ARRAY_IDX(builder->tables,
                                          builder->tables->nelts - 1,
                                          builder_table_t *);
@@ -319,7 +319,7 @@ svn_fs_x__string_table_builder_add(strin
           || table->max_data_size < len)
         table = add_table(builder);
 
-      item->position = (apr_size_t)table->short_strings->nelts;
+      item->position = table->short_strings->nelts;
       APR_ARRAY_PUSH(table->short_strings, builder_string_t *) = item;
 
       if (table->top == NULL)
@@ -441,9 +441,10 @@ create_table(string_sub_table_t *target,
       string->data = apr_pstrmemdup(pool, string->data, string->len);
     }
 
-  data->len += PADDING; /* there a few extra bytes at then of the buffer
-                           that we want to keep */
+  data->len += PADDING; /* add a few extra bytes at the end of the buffer
+                           that we want to keep valid for chunky access */
   assert(data->len < data->blocksize);
+  memset(data->data + data->len - PADDING, 0, PADDING);
 
   target->data = apr_pmemdup(pool, data->data, data->len);
   target->data_size = data->len;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.c Sun Mar  9 10:08:46 2014
@@ -181,7 +181,7 @@ svn_fs_x__deserialize_apr_array(void *bu
   (*array)->pool = pool;
 }
 
-/* auxilliary structure representing the content of a directory hash */
+/* auxiliary structure representing the content of a directory hash */
 typedef struct hash_data_t
 {
   /* number of entries in the directory */
@@ -256,7 +256,7 @@ serialize_dir(apr_hash_t *entries, apr_p
   apr_size_t entries_len = (count + over_provision) * sizeof(svn_fs_dirent_t*);
   apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
 
-  /* copy the hash entries to an auxilliary struct of known layout */
+  /* copy the hash entries to an auxiliary struct of known layout */
   hash_data.count = count;
   hash_data.over_provision = over_provision;
   hash_data.operations = 0;
@@ -520,7 +520,7 @@ svn_fs_x__deserialize_manifest(void **ou
   return SVN_NO_ERROR;
 }
 
-/* Auxilliary structure representing the content of a properties hash.
+/* Auxiliary structure representing the content of a properties hash.
    This structure is much easier to (de-)serialize than an apr_hash.
  */
 typedef struct properties_data_t
@@ -590,7 +590,7 @@ svn_fs_x__serialize_properties(void **da
   svn_stringbuf_t *serialized;
   apr_size_t i;
 
-  /* create our auxilliary data structure */
+  /* create our auxiliary data structure */
   properties.count = apr_hash_count(hash);
   properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
   properties.values = apr_palloc(pool, sizeof(const char*) * properties.count);
@@ -631,7 +631,7 @@ svn_fs_x__deserialize_properties(void **
   properties_data_t *properties = (properties_data_t *)data;
   size_t i;
 
-  /* de-serialize our auxilliary data structure */
+  /* de-serialize our auxiliary data structure */
   svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
   svn_temp_deserializer__resolve(properties, (void**)&properties->values);
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_x/temp_serializer.h Sun Mar  9 10:08:46 2014
@@ -71,7 +71,7 @@ svn_fs_x__deserialize_apr_array(void *bu
 
 /**
  * #svn_txdelta_window_t is not sufficient for caching the data it
- * represents because data read process needs auxilliary information.
+ * represents because data read process needs auxiliary information.
  */
 typedef struct
 {