You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/04/17 17:06:23 UTC

svn commit: r1094153 - /subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c

Author: stefan2
Date: Sun Apr 17 15:06:22 2011
New Revision: 1094153

URL: http://svn.apache.org/viewvc?rev=1094153&view=rev
Log:
Fix the serialized directory update code: We need to explicitly store the
size of every entry since entries are no longer stored in the same order
as they appear in the "entries" index.

* subversion/libsvn_fs_fs/temp_serializer.c
  (hash_data_t): add lengths member
  (serialize_dir_entry): also store serialized entry length
  (serialize_dir): serialize lengths array, too
  (svn_fs_fs__extract_dir_entry): take length from the lengths array
  (svn_fs_fs__replace_dir_entry): carefully update the lengths array as well

Modified:
    subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c

Modified: subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c?rev=1094153&r1=1094152&r2=1094153&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/temp_serializer.c Sun Apr 17 15:06:22 2011
@@ -262,6 +262,10 @@ typedef struct hash_data_t
 
   /* reference to the entries */
   svn_fs_dirent_t **entries;
+
+  /* size of the serialized entries and don't be too wasteful
+   * (needed since the entries are no longer in sequence) */
+  apr_uint32_t *lengths;
 } hash_data_t;
 
 static int
@@ -272,21 +276,27 @@ compare_dirent_id_names(const void *lhs,
 }
 
 /* Utility function to serialize the *ENTRY_P into a the given
- * serialization CONTEXT.
+ * serialization CONTEXT. Return the serialized size of the
+ * dir entry in *LENGTH.
  */
 static void
 serialize_dir_entry(svn_temp_serializer__context_t *context,
-                    svn_fs_dirent_t **entry_p)
+                    svn_fs_dirent_t **entry_p,
+                    apr_uint32_t *length)
 {
   svn_fs_dirent_t *entry = *entry_p;
+  apr_size_t initial_length = svn_temp_serializer__get_length(context);
 
   svn_temp_serializer__push(context,
                             (const void * const *)entry_p,
-                             sizeof(svn_fs_dirent_t));
+                            sizeof(svn_fs_dirent_t));
 
   svn_fs_fs__id_serialize(context, &entry->id);
   svn_temp_serializer__add_string(context, &entry->name);
 
+  *length = (apr_uint32_t)(  svn_temp_serializer__get_length(context)
+                           - APR_ALIGN_DEFAULT(initial_length));
+
   svn_temp_serializer__pop(context);
 }
 
@@ -305,19 +315,18 @@ serialize_dir(apr_hash_t *entries, apr_p
   apr_size_t count = apr_hash_count(entries);
   apr_size_t over_provision = 2 + count / 4;
   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 */
   hash_data.count = count;
   hash_data.over_provision = over_provision;
   hash_data.operations = 0;
   hash_data.entries = apr_palloc(pool, entries_len);
+  hash_data.lengths = apr_palloc(pool, lengths_len);
 
   for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi), ++i)
     hash_data.entries[i] = svn__apr_hash_index_val(hi);
 
-  for (i = 0; i < over_provision; ++i)
-    hash_data.entries[i + count] = NULL;
-
   /* sort entry index by ID name */
   qsort(hash_data.entries,
         count,
@@ -338,7 +347,16 @@ serialize_dir(apr_hash_t *entries, apr_p
 
   /* serialize the individual entries and their sub-structures */
   for (i = 0; i < count; ++i)
-    serialize_dir_entry(context, &hash_data.entries[i]);
+    serialize_dir_entry(context,
+                        &hash_data.entries[i],
+                        &hash_data.lengths[i]);
+
+  svn_temp_serializer__pop(context);
+
+  /* serialize entries references */
+  svn_temp_serializer__push(context,
+                            (const void * const *)&hash_data.lengths,
+                            lengths_len);
 
   return context;
 }
@@ -796,6 +814,10 @@ svn_fs_fs__extract_dir_entry(void **out,
   const svn_fs_dirent_t * const *entries =
     svn_temp_deserializer__ptr(data, (const void **)&hash_data->entries);
 
+  /* resolve the reference to the lengths array */
+  const apr_uint32_t *lengths =
+    svn_temp_deserializer__ptr(data, (const void **)&hash_data->lengths);
+
   /* binary search for the desired entry by name */
   apr_size_t index = find_entry((svn_fs_dirent_t **)entries,
                                 name,
@@ -814,10 +836,7 @@ svn_fs_fs__extract_dir_entry(void **out,
        * block of memory whose end-offset is either the beginning of the
        * next entry or the end of the buffer
        */
-      apr_size_t end_offset = index + 1 < hash_data->count
-                            ? ((apr_size_t*)entries)[index+1]
-                            : hash_data->len;
-      apr_size_t size = end_offset - ((apr_size_t*)entries)[index];
+      apr_size_t size = lengths[index];
 
       /* copy & deserialize the entry */
       svn_fs_dirent_t *new_entry = apr_palloc(pool, size);
@@ -868,6 +887,8 @@ svn_fs_fs__replace_dir_entry(char **data
   hash_data_t *hash_data = (hash_data_t *)*data;
   svn_boolean_t found;
   svn_fs_dirent_t **entries;
+  apr_uint32_t *lengths;
+  apr_uint32_t length;
   apr_size_t index;
 
   svn_temp_serializer__context_t *context;
@@ -883,6 +904,11 @@ svn_fs_fs__replace_dir_entry(char **data
     svn_temp_deserializer__ptr((const char *)hash_data,
                                (const void **)&hash_data->entries);
 
+  /* resolve the reference to the lengths array */
+  lengths = (apr_uint32_t *)
+    svn_temp_deserializer__ptr((const char *)hash_data,
+                               (const void **)&hash_data->lengths);
+
   /* binary search for the desired entry by name */
   index = find_entry(entries, replace_baton->name, hash_data->count, &found);
 
@@ -895,6 +921,9 @@ svn_fs_fs__replace_dir_entry(char **data
           memmove(&entries[index],
                   &entries[index + 1],
                   sizeof(entries[index]) * (hash_data->count - index));
+          memmove(&lengths[index],
+                  &lengths[index + 1],
+                  sizeof(lengths[index]) * (hash_data->count - index));
 
           hash_data->count--;
           hash_data->over_provision++;
@@ -917,6 +946,9 @@ svn_fs_fs__replace_dir_entry(char **data
       memmove(&entries[index + 1],
               &entries[index],
               sizeof(entries[index]) * (hash_data->count - index));
+      memmove(&lengths[index + 1],
+              &lengths[index],
+              sizeof(lengths[index]) * (hash_data->count - index));
 
       hash_data->count++;
       hash_data->over_provision--;
@@ -930,10 +962,22 @@ svn_fs_fs__replace_dir_entry(char **data
                                              hash_data->len,
                                              *data_len,
                                              pool);
-  serialize_dir_entry(context, &entries[index]);
+  serialize_dir_entry(context, &entries[index], &length);
 
   /* return the updated serialized data */
-  return return_serialized_dir_context(context,
-                                       data,
-                                       data_len);
+  SVN_ERR (return_serialized_dir_context(context,
+                                         data,
+                                         data_len));
+
+  /* since the previous call may have re-allocated the buffer, the lengths
+   * pointer may no longer point to the entry in that buffer. Therefore,
+   * re-map it again and store the length value after that. */
+
+  hash_data = (hash_data_t *)*data;
+  lengths = (apr_uint32_t *)
+    svn_temp_deserializer__ptr((const char *)hash_data,
+                               (const void **)&hash_data->lengths);
+  lengths[index] = length;
+
+  return SVN_NO_ERROR;
 }