You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2012/09/17 18:37:30 UTC

svn commit: r1386708 - in /subversion/branches/inheritable-props: ./ configure.ac subversion/libsvn_auth_gnome_keyring/gnome_keyring.c subversion/libsvn_ra_serf/util.c tools/dev/unix-build/Makefile.svn tools/fsfs/reorg.c

Author: pburba
Date: Mon Sep 17 16:37:29 2012
New Revision: 1386708

URL: http://svn.apache.org/viewvc?rev=1386708&view=rev
Log:
On the inheritable-props branch: Sync with ^/subversion/trunk through
r1386705.

Modified:
    subversion/branches/inheritable-props/   (props changed)
    subversion/branches/inheritable-props/configure.ac
    subversion/branches/inheritable-props/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
    subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c
    subversion/branches/inheritable-props/tools/dev/unix-build/Makefile.svn
    subversion/branches/inheritable-props/tools/fsfs/reorg.c

Propchange: subversion/branches/inheritable-props/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1384890-1386705

Modified: subversion/branches/inheritable-props/configure.ac
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/configure.ac?rev=1386708&r1=1386707&r2=1386708&view=diff
==============================================================================
--- subversion/branches/inheritable-props/configure.ac (original)
+++ subversion/branches/inheritable-props/configure.ac Mon Sep 17 16:37:29 2012
@@ -587,17 +587,16 @@ if test "$with_gnome_keyring" != "no"; t
             SVN_GNOME_KEYRING_LIBS="`$PKG_CONFIG --libs glib-2.0 gnome-keyring-1`"
           else
             AC_MSG_RESULT([no])
-            AC_MSG_ERROR([cannot find GNOME Keyring])
           fi
         else
           AC_MSG_RESULT([no])
-          AC_MSG_ERROR([cannot find GLib and GNOME Keyring .pc files])
+          AC_MSG_WARN([cannot find GLib and GNOME Keyring .pc files. GNOME Keyring disabled.])
         fi
       else
-        AC_MSG_ERROR([cannot find pkg-config])
+        AC_MSG_WARN([cannot find pkg-config. GNOME Keyring disabled.])
       fi
     else
-      AC_MSG_ERROR([APR does not have support for DSOs])
+      AC_MSG_WARN([APR does not have support for DSOs. GNOME Keyring disabled.])
     fi
   else
     AC_MSG_ERROR([--with-gnome-keyring conflicts with --disable-shared])

Modified: subversion/branches/inheritable-props/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c?rev=1386708&r1=1386707&r2=1386708&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c Mon Sep 17 16:37:29 2012
@@ -28,6 +28,7 @@
 /*** Includes. ***/
 
 #include <apr_pools.h>
+#include <apr_strings.h>
 #include "svn_auth.h"
 #include "svn_config.h"
 #include "svn_error.h"
@@ -137,9 +138,9 @@ callback_default_keyring(GnomeKeyringRes
   return;
 }
 
-/* Returns the default keyring name. */
+/* Returns the default keyring name, allocated in RESULT_POOL. */
 static char*
-get_default_keyring_name(apr_pool_t *pool)
+get_default_keyring_name(apr_pool_t *result_pool)
 {
   char *def = NULL;
   struct gnome_keyring_baton key_info;
@@ -158,7 +159,7 @@ get_default_keyring_name(apr_pool_t *poo
       return NULL;
     }
 
-  def = strdup(key_info.keyring_name);
+  def = apr_pstrdup(result_pool, key_info.keyring_name);
   callback_destroy_data_keyring(&key_info);
 
   return def;
@@ -290,7 +291,6 @@ password_get_gnome_keyring(svn_boolean_t
                            svn_boolean_t non_interactive,
                            apr_pool_t *pool)
 {
-  char *default_keyring = NULL;
   GnomeKeyringResult result;
   GList *items;
 
@@ -298,8 +298,6 @@ password_get_gnome_keyring(svn_boolean_t
 
   SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
 
-  default_keyring = get_default_keyring_name(pool);
-
   if (! apr_hash_get(parameters,
                      "gnome-keyring-opening-failed",
                      APR_HASH_KEY_STRING))
@@ -338,8 +336,6 @@ password_get_gnome_keyring(svn_boolean_t
                    "");
     }
 
-  free(default_keyring);
-
   return SVN_NO_ERROR;
 }
 
@@ -355,7 +351,6 @@ password_set_gnome_keyring(svn_boolean_t
                            svn_boolean_t non_interactive,
                            apr_pool_t *pool)
 {
-  char *default_keyring = NULL;
   GnomeKeyringResult result;
   guint32 item_id;
 
@@ -363,8 +358,6 @@ password_set_gnome_keyring(svn_boolean_t
 
   SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
 
-  default_keyring = get_default_keyring_name(pool);
-
   if (! apr_hash_get(parameters,
                      "gnome-keyring-opening-failed",
                      APR_HASH_KEY_STRING))
@@ -387,8 +380,6 @@ password_set_gnome_keyring(svn_boolean_t
                    "");
     }
 
-  free(default_keyring);
-
   *done = (result == GNOME_KEYRING_RESULT_OK);
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c?rev=1386708&r1=1386707&r2=1386708&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c Mon Sep 17 16:37:29 2012
@@ -2418,7 +2418,7 @@ expat_response_handler(serf_request_t *r
       XML_SetCharacterDataHandler(ectx->parser, expat_cdata);
     }
 
-  /* ### TODO: sline.com < 200 should really be handled by the core */
+  /* ### TODO: sline.code < 200 should really be handled by the core */
   if ((ectx->handler->sline.code < 200) || (ectx->handler->sline.code >= 300))
     {
       /* By deferring to expect_empty_body(), it will make a choice on

Modified: subversion/branches/inheritable-props/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/tools/dev/unix-build/Makefile.svn?rev=1386708&r1=1386707&r2=1386708&view=diff
==============================================================================
--- subversion/branches/inheritable-props/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/inheritable-props/tools/dev/unix-build/Makefile.svn Mon Sep 17 16:37:29 2012
@@ -1151,6 +1151,7 @@ MOD_DAV_SVN=modules/svn-$(WC)/mod_dav_sv
 MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_authz_svn.so
 LIBMAGIC_FLAG=--with-libmagic=$(PREFIX)/libmagic
 NEON_FLAG=--with-neon="$(PREFIX)/neon"
+GNOME_KEYRING_FLAG=--with-gnome-keyring=yes
 JAVAHL_CHECK_TARGET=check-javahl
 else ifeq ($(BRANCH_MAJOR),1.6)
 BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
@@ -1159,6 +1160,7 @@ MOD_DAV_SVN=modules/svn-$(WC)/mod_dav_sv
 MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_authz_svn.so
 W_NO_SYSTEM_HEADERS=-Wno-system-headers
 NEON_FLAG=--with-neon="$(PREFIX)/neon"
+GNOME_KEYRING_FLAG=--with-gnome-keyring=yes
 JAVAHL_CHECK_TARGET=check-javahl
 else ifeq ($(BRANCH_MAJOR),1.5)
 BDB_FLAG=$(PREFIX)/bdb
@@ -1168,6 +1170,7 @@ MOD_AUTHZ_SVN=modules/mod_authz_svn.so
 DISABLE_NEON_VERSION_CHECK=--disable-neon-version-check
 W_NO_SYSTEM_HEADERS=-Wno-system-headers
 NEON_FLAG=--with-neon="$(PREFIX)/neon"
+GNOME_KEYRING_FLAG=
 JAVAHL_CHECK_TARGET=check-javahl
 else # 1.8
 BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
@@ -1175,6 +1178,7 @@ SERF_FLAG=--with-serf="$(PREFIX)/serf"
 MOD_DAV_SVN=modules/svn-$(WC)/mod_dav_svn.so
 MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_authz_svn.so
 LIBMAGIC_FLAG=--with-libmagic=$(PREFIX)/libmagic
+GNOME_KEYRING_FLAG=--with-gnome-keyring=yes
 JAVAHL_CHECK_TARGET=check-all-javahl
 endif
 
@@ -1208,6 +1212,7 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)
 			--with-apr="$(PREFIX)/apr" \
 			--with-apr-util="$(PREFIX)/apr" \
 			$(NEON_FLAG) \
+			$(GNOME_KEYRING_FLAG) \
 			$(SVN_WITH_HTTPD) \
 			$(SVN_WITH_SASL) \
 			$(SERF_FLAG) \

Modified: subversion/branches/inheritable-props/tools/fsfs/reorg.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/tools/fsfs/reorg.c?rev=1386708&r1=1386707&r2=1386708&view=diff
==============================================================================
--- subversion/branches/inheritable-props/tools/fsfs/reorg.c (original)
+++ subversion/branches/inheritable-props/tools/fsfs/reorg.c Mon Sep 17 16:37:29 2012
@@ -38,6 +38,7 @@
 #include "svn_hash.h"
 
 #include "private/svn_string_private.h"
+#include "private/svn_subr_private.h"
 
 #ifndef _
 #define _(x) x
@@ -82,6 +83,7 @@ typedef struct location_t
 typedef struct direntry_t
 {
   const char *name;
+  apr_size_t name_len;
   noderev_t *node;
 } direntry_t;
 
@@ -148,6 +150,41 @@ typedef struct content_cache_t
   apr_size_t insert_count;
 } content_cache_t;
 
+typedef struct dir_cache_entry_t
+{
+  svn_revnum_t revision;
+  apr_off_t offset;
+  
+  apr_hash_t *hash;
+} dir_cache_entry_t;
+
+typedef struct dir_cache_t
+{
+  dir_cache_entry_t *entries;
+
+  apr_pool_t *pool1;
+  apr_pool_t *pool2;
+  apr_size_t entry_count;
+  apr_size_t insert_count;
+} dir_cache_t;
+
+typedef struct window_cache_entry_t
+{
+  svn_revnum_t revision;
+  apr_off_t offset;
+
+  svn_stringbuf_t *window;
+} window_cache_entry_t;
+
+typedef struct window_cache_t
+{
+  window_cache_entry_t *entries;
+
+  apr_pool_t *pool;
+  apr_size_t entry_count;
+  apr_size_t insert_count;
+} window_cache_t;
+
 typedef struct fs_fs_t
 {
   const char *path;
@@ -163,6 +200,8 @@ typedef struct fs_fs_t
 
   representation_t *null_base;
   content_cache_t *cache;
+  dir_cache_t *dir_cache;
+  window_cache_t *window_cache;
 } fs_fs_t;
 
 static const char *
@@ -217,7 +256,7 @@ create_content_cache(apr_pool_t *pool,
 
   result->pool = pool;
   result->hash_pool = svn_pool_create(pool);
-  result->hash = apr_hash_make(result->hash_pool);
+  result->hash = svn_hash__make(result->hash_pool);
   result->limit = limit;
   result->total_size = 0;
   result->insert_count = 0;
@@ -248,11 +287,11 @@ set_cached_content(content_cache_t *cach
       if (cache->insert_count > 10000)
         {
           svn_pool_clear(cache->hash_pool);
-          cache->hash = apr_hash_make(cache->hash_pool);
+          cache->hash = svn_hash__make(cache->hash_pool);
           cache->insert_count = 0;
         }
       else
-        cache->hash = apr_hash_make(cache->hash_pool);
+        cache->hash = svn_hash__make(cache->hash_pool);
 
       cache->total_size = 0;
     }
@@ -311,6 +350,146 @@ get_content(svn_string_t **data,
   return SVN_NO_ERROR;
 }
 
+static dir_cache_t *
+create_dir_cache(apr_pool_t *pool,
+                 apr_size_t entry_count)
+{
+  dir_cache_t *result = apr_pcalloc(pool, sizeof(*result));
+
+  result->pool1 = svn_pool_create(pool);
+  result->pool2 = svn_pool_create(pool);
+  result->entry_count = entry_count;
+  result->insert_count = 0;
+  result->entries = apr_pcalloc(pool, sizeof(*result->entries) * entry_count);
+
+  return result;
+}
+
+static apr_size_t
+get_dir_cache_index(fs_fs_t *fs,
+                    svn_revnum_t revision,
+                    apr_off_t offset)
+{
+  return (revision + offset * 0xd1f3da69) % fs->dir_cache->entry_count;
+}
+
+static apr_pool_t *
+get_cached_dir_pool(fs_fs_t *fs)
+{
+  return fs->dir_cache->pool1;
+}
+
+static apr_hash_t *
+get_cached_dir(fs_fs_t *fs,
+               representation_t *representation)
+{
+  svn_revnum_t revision = representation->revision->revision;
+  apr_off_t offset = representation->original.offset;
+
+  apr_size_t index = get_dir_cache_index(fs, revision, offset);
+  dir_cache_entry_t *entry = &fs->dir_cache->entries[index];
+  
+  return entry->offset == offset && entry->revision == revision
+    ? entry->hash
+    : NULL;
+}
+
+static void
+set_cached_dir(fs_fs_t *fs,
+               representation_t *representation,
+               apr_hash_t *hash)
+{
+  svn_revnum_t revision = representation->revision->revision;
+  apr_off_t offset = representation->original.offset;
+
+  apr_size_t index = get_dir_cache_index(fs, revision, offset);
+  dir_cache_entry_t *entry = &fs->dir_cache->entries[index];
+
+  fs->dir_cache->insert_count += apr_hash_count(hash);
+  if (fs->dir_cache->insert_count >= fs->dir_cache->entry_count * 100)
+    {
+      apr_pool_t *pool;
+
+      svn_pool_clear(fs->dir_cache->pool2);
+      memset(fs->dir_cache->entries,
+             0,
+             sizeof(*fs->dir_cache->entries) * fs->dir_cache->entry_count);
+      fs->dir_cache->insert_count = 0;
+
+      pool = fs->dir_cache->pool2;
+      fs->dir_cache->pool2 = fs->dir_cache->pool1;
+      fs->dir_cache->pool1 = pool;
+    }
+
+  entry->hash = hash;
+  entry->offset = offset;
+  entry->revision = revision;
+}
+
+static window_cache_t *
+create_window_cache(apr_pool_t *pool,
+                    apr_size_t entry_count)
+{
+  window_cache_t *result = apr_pcalloc(pool, sizeof(*result));
+
+  result->pool = svn_pool_create(pool);
+  result->entry_count = entry_count;
+  result->insert_count = 0;
+  result->entries = apr_pcalloc(pool, sizeof(*result->entries) * entry_count);
+
+  return result;
+}
+
+static apr_size_t
+get_window_cache_index(fs_fs_t *fs,
+                       svn_revnum_t revision,
+                       apr_off_t offset)
+{
+  return (revision + offset * 0xd1f3da69) % fs->window_cache->entry_count;
+}
+
+static svn_stringbuf_t *
+get_cached_window(fs_fs_t *fs,
+                  representation_t *representation,
+                  apr_pool_t *pool)
+{
+  svn_revnum_t revision = representation->revision->revision;
+  apr_off_t offset = representation->original.offset;
+
+  apr_size_t index = get_window_cache_index(fs, revision, offset);
+  window_cache_entry_t *entry = &fs->window_cache->entries[index];
+
+  return entry->offset == offset && entry->revision == revision
+    ? svn_stringbuf_dup(entry->window, pool)
+    : NULL;
+}
+
+static void
+set_cached_window(fs_fs_t *fs,
+                  representation_t *representation,
+                  svn_stringbuf_t *window)
+{
+  svn_revnum_t revision = representation->revision->revision;
+  apr_off_t offset = representation->original.offset;
+
+  apr_size_t index = get_window_cache_index(fs, revision, offset);
+  window_cache_entry_t *entry = &fs->window_cache->entries[index];
+
+  fs->window_cache->insert_count += window->len;
+  if (fs->window_cache->insert_count >= fs->window_cache->entry_count * 10000)
+    {
+      svn_pool_clear(fs->window_cache->pool);
+      memset(fs->window_cache->entries,
+             0,
+             sizeof(*fs->window_cache->entries) * fs->window_cache->entry_count);
+      fs->window_cache->insert_count = 0;
+    }
+
+  entry->window = svn_stringbuf_dup(window, fs->window_cache->pool);
+  entry->offset = offset;
+  entry->revision = revision;
+}
+
 /* Given REV in FS, set *REV_OFFSET to REV's offset in the packed file.
    Use POOL for temporary allocations. */
 static svn_error_t *
@@ -515,7 +694,7 @@ fs_open(fs_fs_t **fs, const char *path, 
                       &(*fs)->max_files_per_dir,
                       svn_dirent_join(path, "db/format", pool),
                       pool));
-  if ((*fs)->format != 4)
+  if (((*fs)->format != 4) && ((*fs)->format != 6))
     return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL, NULL);
     
   SVN_ERR(read_number(&(*fs)->min_unpacked_rev,
@@ -557,6 +736,7 @@ parse_revnode_pos(revision_info_t **revi
   *offset_pos = 0;
   SVN_ERR(svn_cstring_atoi(&revision, revision_pos + 1));
   SVN_ERR(svn_cstring_atoi64(offset, offset_pos + 1));
+  *offset_pos = '/';
 
   if (revision - fs->start_revision > fs->revisions->nelts)
     return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
@@ -819,6 +999,10 @@ get_combined_window(svn_stringbuf_t **co
 
   if (representation->is_plain)
     return read_plain(content, fs, representation, pool);
+
+  *content = get_cached_window(fs, representation, pool);
+  if (*content)
+    return SVN_NO_ERROR;
   
   SVN_ERR(read_windows(&windows, fs, representation, sub_pool));
   if (representation->delta_base && representation->delta_base->revision)
@@ -850,6 +1034,7 @@ get_combined_window(svn_stringbuf_t **co
   svn_pool_destroy(iter_pool);
   svn_pool_destroy(sub_pool);
   
+  set_cached_window(fs, representation, result);
   *content = result;
   return SVN_NO_ERROR;
 }
@@ -893,22 +1078,30 @@ static svn_error_t *
 read_dir(apr_hash_t **hash,
          fs_fs_t *fs,
          representation_t *representation,
-         apr_pool_t *pool,
          apr_pool_t *scratch_pool)
 {
   svn_stringbuf_t *text;
-  apr_pool_t *text_pool = svn_pool_create(scratch_pool);
+  apr_pool_t *text_pool;
   svn_stream_t *stream;
+  apr_pool_t *pool;
 
-  *hash = apr_hash_make(pool);
-  if (representation == NULL)
+  *hash = get_cached_dir(fs, representation);
+  if (*hash)
     return SVN_NO_ERROR;
 
-  SVN_ERR(get_combined_window(&text, fs, representation, text_pool));
-  stream = svn_stream_from_stringbuf(text, text_pool);
-  SVN_ERR(svn_hash_read2(*hash, stream, SVN_HASH_TERMINATOR, pool));
-  svn_pool_destroy(text_pool);
+  pool = get_cached_dir_pool(fs);
+  *hash = svn_hash__make(pool);
+  if (representation != NULL)
+    {
+      text_pool = svn_pool_create(scratch_pool);
+      SVN_ERR(get_combined_window(&text, fs, representation, text_pool));
+      stream = svn_stream_from_stringbuf(text, text_pool);
+      SVN_ERR(svn_hash_read2(*hash, stream, SVN_HASH_TERMINATOR, pool));
+      svn_pool_destroy(text_pool);
+    }
 
+  set_cached_dir(fs, representation, *hash);
+  
   return SVN_NO_ERROR;
 }
 
@@ -922,8 +1115,7 @@ parse_dir(fs_fs_t *fs,
   apr_hash_t *hash;
   apr_hash_index_t *hi;
   apr_pool_t *iter_pool = svn_pool_create(scratch_pool);
-  apr_pool_t *hash_pool = svn_pool_create(scratch_pool);
-  apr_hash_t *base_dir = apr_hash_make(scratch_pool);
+  apr_hash_t *base_dir = svn_hash__make(scratch_pool);
 
   if (representation == NULL)
     return SVN_NO_ERROR;
@@ -936,11 +1128,11 @@ parse_dir(fs_fs_t *fs,
       for (i = 0; i < dir->nelts; ++i)
         {
           direntry_t *entry = APR_ARRAY_IDX(dir, i, direntry_t *);
-          apr_hash_set(base_dir, entry->name, APR_HASH_KEY_STRING, entry);
+          apr_hash_set(base_dir, entry->name, entry->name_len, entry);
         }
     }
 
-  SVN_ERR(read_dir(&hash, fs, representation, hash_pool, scratch_pool));
+  SVN_ERR(read_dir(&hash, fs, representation, scratch_pool));
 
   representation->dir = apr_pcalloc(pool, sizeof(*representation->dir));
   representation->dir->entries
@@ -953,8 +1145,9 @@ parse_dir(fs_fs_t *fs,
       svn_string_t *str_val = svn__apr_hash_index_val(hi);
       apr_off_t offset;
       revision_info_t *revision_info;
+      apr_size_t name_len = strlen(name);
       direntry_t *entry = base_dir
-                        ? apr_hash_get(base_dir, name, APR_HASH_KEY_STRING)
+                        ? apr_hash_get(base_dir, name, name_len)
                         : NULL;
 
       SVN_ERR(parse_revnode_pos(&revision_info, &offset, fs, str_val));
@@ -965,6 +1158,7 @@ parse_dir(fs_fs_t *fs,
           || entry->node->original.offset != offset)
         {
           direntry_t *new_entry = apr_pcalloc(pool, sizeof(*entry));
+          new_entry->name_len = name_len;
           if (entry)
             new_entry->name = entry->name;
           else
@@ -979,7 +1173,6 @@ parse_dir(fs_fs_t *fs,
       svn_pool_clear(iter_pool);
     }
 
-  svn_pool_destroy(hash_pool);
   svn_pool_destroy(iter_pool);
   return SVN_NO_ERROR;
 }
@@ -1061,6 +1254,12 @@ read_noderev(noderev_t **noderev,
   return SVN_NO_ERROR;
 }
 
+static void print_progress(svn_revnum_t revision)
+{
+  printf("%8ld", revision);
+  fflush(stdout);
+}
+
 static svn_error_t *
 read_pack_file(fs_fs_t *fs,
                svn_revnum_t base,
@@ -1126,7 +1325,7 @@ read_pack_file(fs_fs_t *fs,
       svn_pool_clear(iter_pool);
     }
 
-  printf("%8ld", base);
+  print_progress(base);
   apr_pool_destroy(local_pool);
 
   return SVN_NO_ERROR;
@@ -1208,6 +1407,14 @@ read_revisions(fs_fs_t **fs,
                     (apr_allocator_owner_get
                          (svn_pool_create_allocator(FALSE)),
                           limit * 1024 * 1024);
+  (*fs)->dir_cache = create_dir_cache
+                    (apr_allocator_owner_get
+                         (svn_pool_create_allocator(FALSE)),
+                          100000);
+  (*fs)->window_cache = create_window_cache
+                    (apr_allocator_owner_get
+                         (svn_pool_create_allocator(FALSE)),
+                          10000);
 
   for ( revision = start_revision
       ; revision < (*fs)->min_unpacked_rev
@@ -1363,8 +1570,8 @@ add_representation_recursively(fs_fs_t *
       svn_stringbuf_t *content;
 
       get_combined_window(&content, fs, representation, text_pool);
-      representation->target.size = content->len + 13;
-      *current_pos += representation->target.size;
+      representation->target.size = content->len;
+      *current_pos += representation->target.size + 13;
 
       svn_pool_destroy(text_pool);
     }
@@ -1496,6 +1703,9 @@ reorder_revisions(fs_fs_t *fs,
           noderev_t *node = APR_ARRAY_IDX(info->node_revs, k, noderev_t*);
           SVN_ERR(add_noderev_recursively(fs, node, pool));
         }
+
+      if (info->revision % 1000 == 0)
+        print_progress(info->revision);
     }
 
   /* pack file tails */
@@ -1510,9 +1720,293 @@ reorder_revisions(fs_fs_t *fs,
 }
 
 static svn_error_t *
+get_fragment_content(svn_string_t **content,
+                     fs_fs_t *fs,
+                     fragment_t *fragment,
+                     apr_pool_t *pool);
+
+static svn_error_t *
+update_noderevs(fs_fs_t *fs,
+                revision_pack_t *pack,
+                apr_pool_t *pool)
+{
+  int i;
+  apr_pool_t *itempool = svn_pool_create(pool);
+
+  for (i = 0; i < pack->fragments->nelts; ++i)
+    {
+      fragment_t *fragment = &APR_ARRAY_IDX(pack->fragments, i, fragment_t);
+      if (fragment->kind == dir_fragment)
+        {
+          svn_string_t *content;
+
+          SVN_ERR(get_fragment_content(&content, fs, fragment, itempool));
+          svn_pool_clear(itempool);
+        }
+    }
+
+  svn_pool_destroy(itempool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_content_length(apr_size_t *length,
+                   fs_fs_t *fs,
+                   fragment_t *fragment,
+                   svn_boolean_t add_padding,
+                   apr_pool_t *pool)
+{
+  svn_string_t *content;
+
+  SVN_ERR(get_fragment_content(&content, fs, fragment, pool));
+  if (add_padding)
+    switch (fragment->kind)
+      {
+        case dir_fragment:
+          *length = content->len + 16;
+          break;
+        case noderep_fragment:
+          *length = content->len + 3;
+          break;
+        default:
+          *length = content->len;
+          break;
+      }
+  else
+    *length = content->len;
+    
+  return SVN_NO_ERROR;
+}
+
+static void
+move_fragment(fragment_t *fragment,
+              apr_size_t new_position)
+{
+  revision_info_t *info;
+  representation_t *representation;
+  noderev_t *node;
+  
+  fragment->position = new_position; 
+
+  switch (fragment->kind)
+    {
+      case header_fragment:
+        info = fragment->data;
+        info->target.offset = new_position;
+        break;
+
+      case changes_fragment:
+        info = fragment->data;
+        info->target.changes = new_position - info->target.offset;
+        break;
+
+      case property_fragment:
+      case file_fragment:
+      case dir_fragment:
+        representation = fragment->data;
+        representation->target.offset = new_position;
+        break;
+
+      case noderep_fragment:
+        node = fragment->data;
+        node->target.offset = new_position;
+        break;
+    }
+}
+
+static svn_error_t *
 pack_revisions(fs_fs_t *fs,
+               revision_pack_t *pack,
                apr_pool_t *pool)
 {
+  int i;
+  fragment_t *fragment, *next;
+  svn_boolean_t needed_to_expand;
+  revision_info_t *info;
+  apr_size_t current_pos, len, old_len;
+
+  apr_pool_t *itempool = svn_pool_create(pool);
+
+  SVN_ERR(update_noderevs(fs, pack, pool));
+
+  current_pos = pack->info->nelts > 1 ? 64 : 0;
+  for (i = 0; i + 1 < pack->fragments->nelts; ++i)
+    {
+      fragment = &APR_ARRAY_IDX(pack->fragments, i, fragment_t);
+      SVN_ERR(get_content_length(&len, fs, fragment, TRUE, itempool));
+      move_fragment(fragment, current_pos);
+      current_pos += len;
+
+      svn_pool_clear(itempool);
+    }
+
+  fragment = &APR_ARRAY_IDX(pack->fragments, pack->fragments->nelts-1, fragment_t);
+  fragment->position = current_pos;
+
+  do
+    {
+      needed_to_expand = FALSE;
+      current_pos = pack->info->nelts > 1 ? 64 : 0;
+
+      for (i = 0; i + 1 < pack->fragments->nelts; ++i)
+        {
+          fragment = &APR_ARRAY_IDX(pack->fragments, i, fragment_t);
+          next = &APR_ARRAY_IDX(pack->fragments, i + 1, fragment_t);
+          old_len = next->position - fragment->position;
+
+          SVN_ERR(get_content_length(&len, fs, fragment, FALSE, itempool));
+
+          if (len > old_len)
+            {
+              len = (apr_size_t)(len * 1.1) + 10;
+              needed_to_expand = TRUE;
+            }
+          else
+            len = old_len;
+
+          if (i == pack->info->nelts - 1)
+            {
+              info = APR_ARRAY_IDX(pack->info, pack->info->nelts - 1, revision_info_t*);
+              info->target.offset = current_pos;
+            }
+
+          move_fragment(fragment, current_pos);
+          current_pos += len;
+
+          svn_pool_clear(itempool);
+        }
+
+      fragment = &APR_ARRAY_IDX(pack->fragments, pack->fragments->nelts-1, fragment_t);
+      fragment->position = current_pos;
+
+      SVN_ERR(get_content_length(&len, fs, fragment, FALSE, itempool));
+      current_pos += len;
+
+      for (i = 0; i < pack->info->nelts; ++i)
+        {
+          info = APR_ARRAY_IDX(pack->info, i, revision_info_t*);
+          info->target.end = current_pos;
+        }
+    }
+  while (needed_to_expand);
+  
+  svn_pool_destroy(itempool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+write_revisions(fs_fs_t *fs,
+                revision_pack_t *pack,
+                apr_pool_t *pool)
+{
+  int i;
+  fragment_t *fragment = NULL;
+  svn_string_t *content;
+
+  apr_pool_t *itempool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(pool);
+
+  apr_file_t *file;
+  apr_size_t current_pos = 0;
+  svn_stringbuf_t *null_buffer = svn_stringbuf_create_empty(iterpool);
+
+  const char *dir = apr_psprintf(iterpool, "%s/new/%ld%s",
+                                  fs->path, pack->base / 1000,
+                                  pack->info->nelts > 1 ? ".pack" : "");
+  SVN_ERR(svn_io_make_dir_recursively(dir, pool));
+  SVN_ERR(svn_io_file_open(&file,
+                            pack->info->nelts > 1
+                              ? apr_psprintf(iterpool, "%s/pack", dir)
+                              : apr_psprintf(iterpool, "%s/%ld", dir, pack->base),
+                            APR_WRITE | APR_CREATE | APR_BUFFERED,
+                            APR_OS_DEFAULT,
+                            iterpool));
+
+  for (i = 0; i < pack->fragments->nelts; ++i)
+    {
+      apr_size_t padding;
+      fragment = &APR_ARRAY_IDX(pack->fragments, i, fragment_t);
+      SVN_ERR(get_fragment_content(&content, fs, fragment, itempool));
+
+      SVN_ERR_ASSERT(fragment->position >= current_pos);
+      if (   fragment->kind == header_fragment
+          && i+1 < pack->fragments->nelts)
+        padding = APR_ARRAY_IDX(pack->fragments, i+1, fragment_t).position -
+                  content->len - current_pos;
+      else
+        padding = fragment->position - current_pos;
+
+      if (padding)
+        {
+          while (null_buffer->len < padding)
+            svn_stringbuf_appendbyte(null_buffer, 0);
+
+          SVN_ERR(svn_io_file_write_full(file,
+                                          null_buffer->data,
+                                          padding,
+                                          NULL,
+                                          itempool));
+          current_pos += padding;
+        }
+
+      SVN_ERR(svn_io_file_write_full(file,
+                                      content->data,
+                                      content->len,
+                                      NULL,
+                                      itempool));
+      current_pos += content->len;
+
+      svn_pool_clear(itempool);
+    }
+
+  apr_file_close(file);
+
+  if (pack->info->nelts > 1)
+    {
+      svn_stream_t *stream;
+      SVN_ERR(svn_io_file_open(&file,
+                                apr_psprintf(iterpool, "%s/manifest", dir),
+                                APR_WRITE | APR_CREATE | APR_BUFFERED,
+                                APR_OS_DEFAULT,
+                                iterpool));
+      stream = svn_stream_from_aprfile2(file, FALSE, iterpool);
+
+      for (i = 0; i < pack->info->nelts; ++i)
+        {
+          revision_info_t *info = APR_ARRAY_IDX(pack->info, i, revision_info_t*);
+          svn_stream_printf(stream, itempool, "%ld\n", info->target.offset);
+          svn_pool_clear(itempool);
+        }
+    }
+
+  svn_pool_destroy(itempool);
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+pack_and_write_revisions(fs_fs_t *fs,
+                         apr_pool_t *pool)
+{
+  int i;
+
+  SVN_ERR(svn_io_make_dir_recursively(apr_psprintf(pool, "%s/new",
+                                                   fs->path),
+                                      pool));
+
+  for (i = 0; i < fs->packs->nelts; ++i)
+    {
+      revision_pack_t *pack = APR_ARRAY_IDX(fs->packs, i, revision_pack_t*);
+      if (pack->base % fs->max_files_per_dir == 0)
+        print_progress(pack->base);
+
+      SVN_ERR(pack_revisions(fs, pack, pool));
+      SVN_ERR(write_revisions(fs, pack, pool));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -1530,22 +2024,27 @@ get_updated_dir(svn_string_t **content,
   svn_stream_t *stream;
   svn_stringbuf_t *result;
   
-  SVN_ERR(read_dir(&hash, fs, representation, hash_pool, scratch_pool));
+  SVN_ERR(read_dir(&hash, fs, representation, scratch_pool));
+  hash = apr_hash_copy(hash_pool, hash);
   for (i = 0; i < dir->nelts; ++i)
     {
+      char buffer[256];
       svn_string_t *new_val;
+      apr_size_t pos;
       direntry_t *entry = APR_ARRAY_IDX(dir, i, direntry_t *);
-      svn_string_t *str_val = apr_hash_get(hash, entry->name,
-                                           APR_HASH_KEY_STRING);
+      svn_string_t *str_val = apr_hash_get(hash, entry->name, entry->name_len);
       if (str_val == NULL)
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Dir entry '%s' not found"), entry->name);
 
-      strchr((char *)str_val->data, '/')[1] = 0;
-      new_val = svn_string_createf(hash_pool, "%s%ld", str_val->data,
-                                   entry->node->target.offset - entry->node->revision->target.offset);
+      SVN_ERR_ASSERT(str_val->len < sizeof(buffer));
+      
+      memcpy(buffer, str_val->data, str_val->len+1);
+      pos = strchr(buffer, '/') - buffer + 1;
+      pos += svn__ui64toa(buffer + pos, entry->node->target.offset - entry->node->revision->target.offset);
+      new_val = svn_string_ncreate(buffer, pos, hash_pool);
 
-      apr_hash_set(hash, entry->name, APR_HASH_KEY_STRING, new_val);
+      apr_hash_set(hash, entry->name, entry->name_len, new_val);
     }
 
   result = svn_stringbuf_create_ensure(representation->target.size, pool);
@@ -1744,7 +2243,8 @@ get_fragment_content(svn_string_t **cont
               header = svn_stringbuf_createf(pool,
                                              "DELTA %ld %ld %ld\n",
                                              representation->delta_base->revision->revision,
-                                             representation->delta_base->target.offset - representation->delta_base->revision->target.offset,
+                                             representation->delta_base->target.offset
+                                             - representation->delta_base->revision->target.offset,
                                              representation->delta_base->target.size);
         else
           header = svn_stringbuf_create("PLAIN\n", pool);
@@ -1834,146 +2334,6 @@ get_fragment_content(svn_string_t **cont
 }
 
 static svn_error_t *
-update_dir_reps(fs_fs_t *fs,
-                apr_pool_t *pool)
-{
-  int i, k;
-  fragment_t *fragment;
-  svn_string_t *content;
-
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_pool_t *itempool = svn_pool_create(pool);
-  
-  for (i = 0; i < fs->packs->nelts; ++i)
-    {
-      revision_pack_t *pack = APR_ARRAY_IDX(fs->packs, i, revision_pack_t*);
-      for (k = 0; k < pack->fragments->nelts; ++k)
-        {
-          fragment = &APR_ARRAY_IDX(pack->fragments, k, fragment_t);
-/*          if (fragment->kind == dir_fragment) */
-            SVN_ERR(get_fragment_content(&content, fs, fragment, itempool));
-
-          svn_pool_clear(itempool);
-        }
-
-      svn_pool_clear(iterpool);
-    }
-
-  svn_pool_destroy(itempool);
-  svn_pool_destroy(iterpool);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-write_revisions(fs_fs_t *fs,
-                apr_pool_t *pool)
-{
-  int i, k;
-  fragment_t *fragment;
-  svn_string_t *content;
-
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_pool_t *itempool = svn_pool_create(pool);
-
-  SVN_ERR(update_dir_reps(fs, pool));
-
-  SVN_ERR(svn_io_make_dir_recursively(apr_psprintf(iterpool, "%s/new",
-                                                   fs->path),
-                                      pool));
-  
-  for (i = 0; i < fs->packs->nelts; ++i)
-    {
-      apr_file_t *file;
-      apr_size_t current_pos = 0;
-      svn_stringbuf_t *null_buffer = svn_stringbuf_create_empty(iterpool);
-
-      revision_pack_t *pack = APR_ARRAY_IDX(fs->packs, i, revision_pack_t*);
-
-      const char *dir = apr_psprintf(iterpool, "%s/new/%ld%s",
-                                     fs->path, pack->base / 1000,
-                                     pack->info->nelts > 1 ? ".pack" : "");
-      SVN_ERR(svn_io_make_dir_recursively(dir, pool));
-      SVN_ERR(svn_io_file_open(&file,
-                               pack->info->nelts > 1
-                                 ? apr_psprintf(iterpool, "%s/pack", dir)
-                                 : apr_psprintf(iterpool, "%s/%ld", dir, pack->base),
-                               APR_WRITE | APR_CREATE | APR_BUFFERED,
-                               APR_OS_DEFAULT,
-                               iterpool));
-
-      for (k = 0; k < pack->fragments->nelts; ++k)
-        {
-          apr_size_t padding;
-          
-          fragment = &APR_ARRAY_IDX(pack->fragments, k, fragment_t);
-          SVN_ERR(get_fragment_content(&content, fs, fragment, itempool));
-
-          SVN_ERR_ASSERT(fragment->position >= current_pos);
-          if (   fragment->kind == header_fragment
-              && k+1 < pack->fragments->nelts)
-            padding = APR_ARRAY_IDX(pack->fragments, k+1, fragment_t).position -
-                      content->len - current_pos;
-          else
-            padding = fragment->position - current_pos;
-          
-          if (padding)
-            {
-              while (null_buffer->len < padding)
-                svn_stringbuf_appendbyte(null_buffer, 0);
-
-              SVN_ERR(svn_io_file_write_full(file,
-                                             null_buffer->data,
-                                             padding,
-                                             NULL,
-                                             itempool));
-              current_pos += padding;
-            }
-
-          SVN_ERR(svn_io_file_write_full(file,
-                                         content->data,
-                                         content->len,
-                                         NULL,
-                                         itempool));
-          current_pos += content->len;
-
-          svn_pool_clear(itempool);
-        }
-
-      apr_file_close(file);
-      
-      if (pack->info->nelts > 1)
-        {
-          svn_stream_t *stream;
-          SVN_ERR(svn_io_file_open(&file,
-                                   apr_psprintf(iterpool, "%s/manifest", dir),
-                                   APR_WRITE | APR_CREATE | APR_BUFFERED,
-                                   APR_OS_DEFAULT,
-                                   iterpool));
-          stream = svn_stream_from_aprfile2(file, FALSE, iterpool);
-          
-          for (k = 0; k < pack->info->nelts; ++k)
-            {
-              revision_info_t *info = APR_ARRAY_IDX(pack->info, k, revision_info_t*);
-              svn_stream_printf(stream, itempool, "%ld\n", info->target.offset);
-              svn_pool_clear(itempool);
-            }
-        }
-
-
-      if (pack->info->nelts > 1)
-        printf("%8ld", pack->base);
-
-      svn_pool_clear(iterpool);
-    }
-
-  svn_pool_destroy(itempool);
-  svn_pool_destroy(iterpool);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
 prepare_repo(const char *path, apr_pool_t *pool)
 {
   svn_node_kind_t kind;
@@ -2064,31 +2424,25 @@ int main(int argc, const char *argv[])
   repo_path = argv[1];
   start_revision = (long)rev;
 
-  printf("\nPrepare repository\n");
+  printf("\nPreparing repository\n");
   svn_err = prepare_repo(repo_path, pool);
 
   if (!svn_err)
     {
-      printf("\nRead repository\n");
+      printf("\nReading revisions\n");
       svn_err = read_revisions(&fs, repo_path, start_revision, 4000, pool);
     }
   
   if (!svn_err)
     {
-      printf("\nReorder revisions\n");
+      printf("\nReordering revision content\n");
       svn_err = reorder_revisions(fs, pool);
     }
     
   if (!svn_err)
     {
-      printf("\nPack revisions\n");
-      svn_err = pack_revisions(fs, pool);
-    }
-
-  if (!svn_err)
-    {
-      printf("\nWrite new revs data\n");
-      svn_err = write_revisions(fs, pool);
+      printf("\nPacking and writing revisions\n");
+      svn_err = pack_and_write_revisions(fs, pool);
     }
 
   if (!svn_err)