subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1467454 - in /subversion/branches/fsfs-format7/subversion/libsvn_fs_fs: noderevs.c noderevs.h
Date Fri, 12 Apr 2013 20:36:03 GMT
Author: stefan2
Date: Fri Apr 12 20:36:02 2013
New Revision: 1467454

URL: http://svn.apache.org/r1467454
Log:
On the fsfs-format7 branch:  Introduce a container data structure
for node revisions.

* subversion/libsvn_fs_fs/noderevs.h
  (svn_fs_fs__noderevs_t): declare container data type
  (svn_fs_fs__noderevs_create,
   svn_fs_fs__noderevs_add,
   svn_fs_fs__noderevs_estimate_size,
   svn_fs_fs__noderevs_get,
   svn_fs_fs__write_noderevs_container,
   svn_fs_fs__read_noderevs_container): declare container API

* subversion/libsvn_fs_fs/noderevs.c
  (NODEREV_KIND_MASK,
   NODEREV_HAS_MINFO,
   NODEREV_HAS_COPYFROM,
   NODEREV_HAS_COPYROOT,
   NODEREV_HAS_CPATH): define various encoding flags & fields
  (binary_id_t,
   struct binary_noderev_t,
   svn_fs_fs__noderevs_t): define data types
  (store_id,
   store_representation,
   get_id,
   get_representation,
   create_rep_stream,
   write_reps,
   read_reps): utility functions
  (svn_fs_fs__noderevs_create,
   svn_fs_fs__noderevs_add,
   svn_fs_fs__noderevs_estimate_size,
   svn_fs_fs__noderevs_get,
   svn_fs_fs__write_noderevs_container,
   svn_fs_fs__read_noderevs_container): implement container API

Added:
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.c
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.h

Added: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.c?rev=1467454&view=auto
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.c (added)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.c Fri Apr 12 20:36:02
2013
@@ -0,0 +1,754 @@
+/* noderevs.h --- FSFS node revision container
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_private_config.h"
+
+#include "private/svn_packed_data.h"
+#include "private/svn_subr_private.h"
+
+#include "noderevs.h"
+#include "string_table.h"
+
+/* These flags will be used with the FLAGS field in binary_noderev_t.
+ */
+
+/* (flags & NODEREV_KIND_MASK) extracts the noderev type */
+#define NODEREV_KIND_MASK    0x00007
+
+/* the noderev has merge info */
+#define NODEREV_HAS_MINFO    0x00008
+
+/* the noderev has copy-from-path and revision */
+#define NODEREV_HAS_COPYFROM 0x00010
+
+/* the noderev has copy-root path and revision */
+#define NODEREV_HAS_COPYROOT 0x00020
+
+/* the noderev has copy-root path and revision */
+#define NODEREV_HAS_CPATH    0x00040
+
+/* Our internal representation of an id
+ * (basically, strip off the txn_id and the fs-agnostic header)
+ */
+typedef struct binary_id_t
+{
+  svn_fs_fs__id_part_t node_id;
+  svn_fs_fs__id_part_t copy_id;
+  svn_fs_fs__id_part_t rev_id;
+} binary_id_t;
+
+/* Our internal representation of a node_revision_t.
+ * 
+ * We will store path strings in a string container and reference them
+ * from here.  Similarly, IDs and representations are being stored in
+ * separate containers and then also referenced here.  This eliminates
+ * the need to store the same IDs and representations more than once.
+ */
+typedef struct binary_noderev_t
+{
+  /* node type and presence indicators */
+  apr_uint32_t flags;
+
+  /* Index+1 of the node-id for this node-rev. */
+  int id;
+
+  /* Index+1 of the predecessor node revision id, or 0 if there is no
+     predecessor for this node revision */
+  int predecessor_id;
+
+  /* number of predecessors this node revision has (recursively), or
+     -1 if not known (for backward compatibility). */
+  int predecessor_count;
+
+  /* If this node-rev is a copy, what revision was it copied from? */
+  svn_revnum_t copyfrom_rev;
+
+  /* Helper for history tracing, root revision of the parent tree from
+     whence this node-rev was copied. */
+  svn_revnum_t copyroot_rev;
+
+  /* If this node-rev is a copy, this is the string index+1 of the path
+     from which that copy way made. 0, otherwise. */
+  int copyfrom_path;
+
+  /* String index+1 of the root of the parent tree from whence this node-
+   * rev was copied. */
+  int copyroot_path;
+
+  /* Index+1 of the representation key for this node's properties.
+     May be 0 if there are no properties.  */
+  int prop_rep;
+
+  /* Index+1 of the representation for this node's data.
+     May be 0 if there is no data. */
+  int data_rep;
+
+  /* String index+1 of the path at which this node first came into
+     existence.  */
+  int created_path;
+
+  /* Number of nodes with svn:mergeinfo properties that are
+     descendants of this node (including it itself) */
+  apr_int64_t mergeinfo_count;
+
+} binary_noderev_t;
+
+/* The actual container object.  Node revisions are concatenated into
+ * NODEREVS, referenced representations are stored in DATA_REPS / PROP_REPS
+ * and the ids in IDs.  PATHS is the string table for all paths.
+ *
+ * During construction, BUILDER will be used instead of PATHS. IDS_DICT,
+ * DATA_REPS_DICT and PROP_REPS_DICT are also only used during construction
+ * and are NULL otherwise.
+ */
+struct svn_fs_fs__noderevs_t
+{
+  /* The paths - either in 'builder' mode or finalized mode.
+   * The respective other pointer will be NULL. */
+  string_table_builder_t *builder;
+  string_table_t *paths;
+
+  /* During construction, maps a full binary_id_t to an index into IDS */
+  apr_hash_t *ids_dict;
+
+  /* During construction, maps a full representation_t to an index into
+   * DATA_REPS. */
+  apr_hash_t *data_reps_dict;
+
+  /* During construction, maps a full representation_t to an index into
+   * PROP_REPS. */
+  apr_hash_t *prop_reps_dict;
+
+  /* array of binary_id_t */
+  apr_array_header_t *ids;
+
+  /* arrays of representation_t */
+  apr_array_header_t *data_reps;
+  apr_array_header_t *prop_reps;
+
+  /* array of binary_noderev_t. */
+  apr_array_header_t *noderevs;
+};
+
+svn_fs_fs__noderevs_t *
+svn_fs_fs__noderevs_create(apr_size_t initial_count,
+                           apr_pool_t* pool)
+{
+  svn_fs_fs__noderevs_t *noderevs = apr_palloc(pool, sizeof(*noderevs));
+
+  noderevs->builder = svn_fs_fs__string_table_builder_create(pool);
+  noderevs->ids_dict = svn_hash__make(pool);
+  noderevs->data_reps_dict = svn_hash__make(pool);
+  noderevs->prop_reps_dict = svn_hash__make(pool);
+  noderevs->paths = NULL;
+
+  noderevs->ids
+    = apr_array_make(pool, initial_count, sizeof(binary_id_t));
+  noderevs->data_reps
+    = apr_array_make(pool, initial_count, sizeof(representation_t));
+  noderevs->prop_reps
+    = apr_array_make(pool, initial_count, sizeof(representation_t));
+  noderevs->noderevs
+    = apr_array_make(pool, initial_count, sizeof(binary_noderev_t));
+
+  return noderevs;
+}
+
+/* Given the ID, return the index+1 into IDS that contains a binary_id
+ * for it.  Returns 0 for NULL IDs.  We use DICT to detect duplicates.
+ */
+static int
+store_id(apr_array_header_t *ids,
+         apr_hash_t *dict,
+         const svn_fs_id_t *id)
+{
+  binary_id_t bin_id = { 0 };
+  int idx;
+
+  if (id == NULL)
+    return 0;
+  
+  bin_id.node_id = *svn_fs_fs__id_node_id(id);
+  bin_id.copy_id = *svn_fs_fs__id_copy_id(id);
+  bin_id.rev_id = *svn_fs_fs__id_rev_item(id);
+
+  idx = (int)(apr_uintptr_t)apr_hash_get(dict, &bin_id, sizeof(bin_id));
+  if (idx == 0)
+    {
+      APR_ARRAY_PUSH(ids, binary_id_t) = bin_id;
+      idx = ids->nelts;
+      apr_hash_set(dict, ids->elts + idx * ids->elt_size, ids->elt_size,
+                   (void*)(apr_uintptr_t)idx);
+    }
+
+  return idx;
+}
+
+/* Given the REP, return the index+1 into REPS that contains a copy of it.
+ * Returns 0 for NULL IDs.  We use DICT to detect duplicates.
+ */
+static int
+store_representation(apr_array_header_t *reps,
+                     apr_hash_t *dict,
+                     const representation_t *rep)
+{
+  int idx;
+  if (rep == NULL)
+    return 0;
+
+  idx = (int)(apr_uintptr_t)apr_hash_get(dict, rep, sizeof(*rep));
+  if (idx == 0)
+    {
+      APR_ARRAY_PUSH(reps, representation_t) = *rep;
+      idx = reps->nelts;
+      apr_hash_set(dict, reps->elts + idx * reps->elt_size, reps->elt_size,
+                   (void*)(apr_uintptr_t)idx);
+    }
+
+  return idx;
+}
+
+apr_size_t
+svn_fs_fs__noderevs_add(svn_fs_fs__noderevs_t *container,
+                        node_revision_t *noderev)
+{
+  binary_noderev_t binary_noderev = { 0 };
+  svn_boolean_t is_txn_id;
+
+  binary_noderev.flags = (noderev->has_mergeinfo ? NODEREV_HAS_MINFO : 0)
+                       | (noderev->copyfrom_path ? NODEREV_HAS_COPYFROM : 0)
+                       | (noderev->copyroot_rev  ? NODEREV_HAS_COPYROOT : 0)
+                       | (noderev->created_path  ? NODEREV_HAS_CPATH : 0)
+                       | (int)noderev->kind;
+
+  binary_noderev.id
+    = store_id(container->ids, container->ids_dict, noderev->id);
+  binary_noderev.predecessor_id
+    = store_id(container->ids, container->ids_dict, noderev->predecessor_id);
+
+  if (noderev->copyfrom_path)
+    {
+      binary_noderev.copyfrom_path
+        = svn_fs_fs__string_table_builder_add(container->builder,
+                                              noderev->copyfrom_path,
+                                              0);
+      binary_noderev.copyfrom_rev = noderev->copyfrom_rev;
+    }
+
+  if (noderev->copyroot_rev)
+    {
+      binary_noderev.copyroot_path
+        = svn_fs_fs__string_table_builder_add(container->builder,
+                                              noderev->copyroot_path,
+                                              0);
+      binary_noderev.copyroot_rev = noderev->copyroot_rev;
+    }
+
+  binary_noderev.predecessor_count = noderev->predecessor_count;
+  binary_noderev.data_rep = store_representation(container->data_reps,
+                                                 container->data_reps_dict,
+                                                 noderev->data_rep);
+  binary_noderev.prop_rep = store_representation(container->prop_reps,
+                                                 container->prop_reps_dict,
+                                                 noderev->prop_rep);
+
+  if (noderev->created_path)
+    binary_noderev.created_path
+      = svn_fs_fs__string_table_builder_add(container->builder,
+                                            noderev->created_path,
+                                            0);
+
+  binary_noderev.mergeinfo_count = noderev->mergeinfo_count;
+  
+  APR_ARRAY_PUSH(container->noderevs, binary_noderev_t) = binary_noderev;
+
+  return container->noderevs->nelts - 1;
+}
+
+apr_size_t
+svn_fs_fs__noderevs_estimate_size(const svn_fs_fs__noderevs_t *container)
+{
+  /* CONTAINER must be in 'builder' mode */
+  if (container->builder == NULL)
+    return 0;
+
+  /* string table code makes its own prediction,
+   * noderevs should be < 12 bytes each,
+   * ids < 10 bytes each,
+   * data representations < 50 bytes each,
+   * property representations < 50 bytes each,
+   * some static overhead should be assumed */
+  return svn_fs_fs__string_table_builder_estimate_size(container->builder)
+       + container->noderevs->nelts * 12
+       + container->ids->nelts * 10
+       + container->data_reps->nelts * 50
+       + container->prop_reps->nelts * 30
+       + 100;
+}
+
+/* Create an svn_fs_id_t in *ID, allocated in POOL based on the id stored
+ * at index IDX in IDS.
+ */
+static svn_error_t *
+get_id(const svn_fs_id_t **id,
+       const apr_array_header_t *ids,
+       int idx,
+       apr_pool_t *pool)
+{
+  binary_id_t *binary_id;
+
+  /* handle NULL IDs  */
+  if (idx == 0)
+    {
+      *id = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  /* check for corrupted data */
+  if (idx < 0 || idx > ids->nelts)
+    return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
+                             _("Node revision ID index %d" 
+                               " exceeds container size %d"),
+                             idx, ids->nelts);
+
+  /* create a svn_fs_id_t from stored info */
+  binary_id = &APR_ARRAY_IDX(ids, idx - 1, binary_id_t);
+  *id = svn_fs_fs__id_rev_create(&binary_id->node_id,
+                                 &binary_id->copy_id,
+                                 &binary_id->rev_id,
+                                 pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Create a representation_t in *REP, allocated in POOL based on the
+ * representation stored at index IDX in REPS.
+ */
+static svn_error_t *
+get_representation(representation_t **rep,
+                   const apr_array_header_t *reps,
+                   int idx,
+                   apr_pool_t *pool)
+{
+  /* handle NULL representations  */
+  if (idx == 0)
+    {
+      *rep = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  /* check for corrupted data */
+  if (idx < 0 || idx > reps->nelts)
+    return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
+                             _("Node revision ID index %d"
+                               " exceeds container size %d"),
+                             idx, reps->nelts);
+
+  /* no translation required. Just duplicate the info */
+  *rep = apr_pmemdup(pool,
+                     &APR_ARRAY_IDX(reps, idx - 1, representation_t),
+                     reps->elt_size);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__noderevs_get(node_revision_t **noderev_p,
+                        const svn_fs_fs__noderevs_t *container,
+                        apr_size_t idx,
+                        apr_pool_t *pool)
+{
+  node_revision_t *noderev;
+  binary_noderev_t *binary_noderev;
+  
+  /* CONTAINER must be in 'finalized' mode */
+  SVN_ERR_ASSERT(container->builder == NULL);
+  SVN_ERR_ASSERT(container->paths);
+
+  /* validate index */
+  if (idx >= (apr_size_t)container->noderevs->nelts)
+    return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
+                             _("Node revision index %" APR_SIZE_T_FMT
+                               " exceeds container size %d"),
+                             idx, container->noderevs->nelts);
+
+  /* allocate result struct and fill it field by field */
+  noderev = apr_pcalloc(pool, sizeof(*noderev));
+  binary_noderev = &APR_ARRAY_IDX(container->noderevs, idx, binary_noderev_t);
+  
+  noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK);
+  SVN_ERR(get_id(&noderev->id, container->ids, binary_noderev->id, pool));
+  SVN_ERR(get_id(&noderev->predecessor_id, container->ids,
+                 binary_noderev->predecessor_id, pool));
+
+  if (binary_noderev->flags & NODEREV_HAS_COPYFROM)
+    {
+      noderev->copyfrom_path
+        = svn_fs_fs__string_table_get(container->paths,
+                                      binary_noderev->copyfrom_path,
+                                      pool);
+      noderev->copyroot_rev = binary_noderev->copyfrom_rev;
+    }
+  else
+    {
+      noderev->copyfrom_path = NULL;
+      noderev->copyfrom_rev = SVN_INVALID_REVNUM;
+    }
+
+  if (binary_noderev->flags & NODEREV_HAS_COPYROOT)
+    {
+      noderev->copyroot_path
+        = svn_fs_fs__string_table_get(container->paths,
+                                      binary_noderev->copyroot_path,
+                                      pool);
+      noderev->copyroot_rev = binary_noderev->copyroot_rev;
+    }
+  else
+    {
+      noderev->copyroot_path = NULL;
+      noderev->copyroot_rev = SVN_INVALID_REVNUM;
+    }
+
+  noderev->predecessor_count = binary_noderev->predecessor_count;
+
+  SVN_ERR(get_representation(&noderev->prop_rep, container->prop_reps,
+                             binary_noderev->prop_rep, pool));
+  SVN_ERR(get_representation(&noderev->data_rep, container->data_reps,
+                             binary_noderev->data_rep, pool));
+
+  if (binary_noderev->flags & NODEREV_HAS_CPATH)
+    noderev->created_path
+      = svn_fs_fs__string_table_get(container->paths,
+                                    binary_noderev->created_path,
+                                    pool);
+
+  noderev->mergeinfo_count = binary_noderev->mergeinfo_count;
+
+  noderev->has_mergeinfo = (binary_noderev->flags & NODEREV_HAS_MINFO) ? 1 : 0;
+  *noderev_p = noderev;
+
+  return SVN_NO_ERROR;
+}
+
+/* Create and return a stream for representations in PARENT.
+ * Initialize the sub-streams for all fields, except checksums.
+ */
+static svn_packed__int_stream_t *
+create_rep_stream(svn_packed__int_stream_t *parent)
+{
+  svn_packed__int_stream_t *stream
+    = svn_packed__create_int_substream(parent, FALSE, FALSE);
+
+  /* sub-streams for members - except for checksums */
+  /* has_sha1 */
+  svn_packed__create_int_substream(stream, FALSE, FALSE);
+
+  /* rev, item_index, size, expanded_size */
+  svn_packed__create_int_substream(stream, TRUE, FALSE);
+  svn_packed__create_int_substream(stream, FALSE, FALSE);
+  svn_packed__create_int_substream(stream, FALSE, FALSE);
+  svn_packed__create_int_substream(stream, FALSE, FALSE);
+
+  /* uniquifier */
+  svn_packed__create_int_substream(stream, TRUE, FALSE);
+  svn_packed__create_int_substream(stream, TRUE, FALSE);
+  svn_packed__create_int_substream(stream, TRUE, FALSE);
+
+  return stream;
+}
+
+/* Serialize all representations in REP.  Store checksums in DIGEST_STREAM,
+ * put all other fields into REP_STREAM.
+ */
+static void
+write_reps(svn_packed__int_stream_t *rep_stream,
+           svn_packed__byte_stream_t *digest_stream,
+           apr_array_header_t *reps)
+{
+  int i;
+  for (i = 0; i < reps->nelts; ++i)
+    {
+      representation_t *rep = &APR_ARRAY_IDX(reps, i, representation_t);
+
+      svn_packed__add_uint(rep_stream, rep->has_sha1);
+
+      svn_packed__add_uint(rep_stream, rep->revision);
+      svn_packed__add_uint(rep_stream, rep->item_index);
+      svn_packed__add_uint(rep_stream, rep->size);
+      svn_packed__add_uint(rep_stream, rep->expanded_size);
+      
+      svn_packed__add_uint(rep_stream, rep->uniquifier.txn_id.revision);
+      svn_packed__add_uint(rep_stream, rep->uniquifier.txn_id.number);
+      svn_packed__add_uint(rep_stream, rep->uniquifier.number);
+
+      svn_packed__add_bytes(digest_stream,
+                            rep->md5_digest,
+                            sizeof(rep->md5_digest));
+      if (rep->has_sha1)
+        svn_packed__add_bytes(digest_stream,
+                              rep->sha1_digest,
+                              sizeof(rep->sha1_digest));
+    }
+}
+
+svn_error_t *
+svn_fs_fs__write_noderevs_container(svn_stream_t *stream,
+                                    const svn_fs_fs__noderevs_t *container,
+                                    apr_pool_t *pool)
+{
+  int i;
+
+  string_table_t *paths = container->paths
+                        ? container->paths
+                        : svn_fs_fs__string_table_create(container->builder,
+                                                         pool);
+
+  svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
+
+  /* one common top-level stream for all arrays. One sub-stream */
+  svn_packed__int_stream_t *structs_stream
+    = svn_packed__create_int_stream(root, FALSE, FALSE);
+  svn_packed__int_stream_t *ids_stream
+    = svn_packed__create_int_substream(structs_stream, FALSE, FALSE);
+  svn_packed__int_stream_t *data_reps_stream
+    = create_rep_stream(structs_stream);
+  svn_packed__int_stream_t *prop_reps_stream
+    = create_rep_stream(structs_stream);
+  svn_packed__int_stream_t *noderevs_stream
+    = svn_packed__create_int_substream(structs_stream, FALSE, FALSE);
+  svn_packed__byte_stream_t *digests_stream
+    = svn_packed__create_bytes_stream(root);
+
+  /* structure the CHANGES_STREAM such we can extract much of the redundancy
+   * from the binary_change_t structs */
+  for (i = 0; i < 3 * 2; ++i)
+    svn_packed__create_int_substream(ids_stream, TRUE, FALSE);
+
+  svn_packed__create_int_substream(noderevs_stream, FALSE, FALSE);
+  for (i = 0; i < 11; ++i)
+    svn_packed__create_int_substream(noderevs_stream, TRUE, FALSE);
+
+  /* serialize ids array */
+  for (i = 0; i < container->ids->nelts; ++i)
+    {
+      binary_id_t *id = &APR_ARRAY_IDX(container->ids, i, binary_id_t);
+
+      svn_packed__add_uint(ids_stream, id->node_id.revision);
+      svn_packed__add_uint(ids_stream, id->node_id.number);
+      svn_packed__add_uint(ids_stream, id->copy_id.revision);
+      svn_packed__add_uint(ids_stream, id->copy_id.number);
+      svn_packed__add_uint(ids_stream, id->rev_id.revision);
+      svn_packed__add_uint(ids_stream, id->rev_id.number);
+    }
+
+  /* serialize rep arrays */
+  write_reps(data_reps_stream, digests_stream, container->data_reps);
+  write_reps(prop_reps_stream, digests_stream, container->prop_reps);
+
+  /* serialize noderevs array */
+  for (i = 0; i < container->noderevs->nelts; ++i)
+    {
+      const binary_noderev_t *noderev
+        = &APR_ARRAY_IDX(container->noderevs, i, binary_noderev_t);
+
+      svn_packed__add_uint(noderevs_stream, noderev->flags);
+      
+      svn_packed__add_uint(noderevs_stream, noderev->id);
+      svn_packed__add_uint(noderevs_stream, noderev->predecessor_id);
+      svn_packed__add_uint(noderevs_stream, noderev->predecessor_count);
+      
+      svn_packed__add_uint(noderevs_stream, noderev->copyfrom_path);
+      svn_packed__add_uint(noderevs_stream, noderev->copyfrom_rev);
+      svn_packed__add_uint(noderevs_stream, noderev->copyroot_path);
+      svn_packed__add_uint(noderevs_stream, noderev->copyroot_path);
+
+      svn_packed__add_uint(noderevs_stream, noderev->prop_rep);
+      svn_packed__add_uint(noderevs_stream, noderev->data_rep);
+
+      svn_packed__add_uint(noderevs_stream, noderev->created_path);
+      svn_packed__add_uint(noderevs_stream, noderev->mergeinfo_count);
+    }
+
+  /* write to disk */
+  SVN_ERR(svn_fs_fs__write_string_table(stream, paths, pool));
+  SVN_ERR(svn_packed__data_write(stream, root, pool));
+  
+  return SVN_NO_ERROR;
+}
+
+/* Allocate a representation_t array in POOL and return it in *REPS_P.
+ * Deserialize the data in REP_STREAM and DIGEST_STREAM and store the
+ * resulting representations into the *REPS_P.
+ */
+static svn_error_t *
+read_reps(apr_array_header_t **reps_p,
+          svn_packed__int_stream_t *rep_stream,
+          svn_packed__byte_stream_t *digest_stream,
+          apr_pool_t *pool)
+{
+  apr_size_t i;
+  apr_size_t len;
+  const char *bytes;
+
+  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(representation_t));
+
+  for (i = 0; i < count; ++i)
+    {
+      representation_t rep;
+
+      rep.has_sha1 = svn_packed__get_uint(rep_stream);
+
+      rep.revision = svn_packed__get_uint(rep_stream);
+      rep.item_index = svn_packed__get_uint(rep_stream);
+      rep.size = svn_packed__get_uint(rep_stream);
+      rep.expanded_size = svn_packed__get_uint(rep_stream);
+
+      rep.uniquifier.txn_id.revision = svn_packed__get_uint(rep_stream);
+      rep.uniquifier.txn_id.number = svn_packed__get_uint(rep_stream);
+      rep.uniquifier.number = svn_packed__get_uint(rep_stream);
+
+      svn_fs_fs__id_txn_reset(&rep.txn_id);
+
+      /* when extracting the checksums, beware of buffer under/overflows
+         caused by disk data corruption. */
+      bytes = svn_packed__get_bytes(digest_stream, &len);
+      if (len != sizeof(rep.md5_digest))
+        return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
+                                _("Unexpected MD5 digest size %"
+                                  APR_SIZE_T_FMT),
+                                len);
+
+      memcpy(rep.md5_digest, bytes, sizeof(rep.md5_digest));
+      if (rep.has_sha1)
+        {
+          bytes = svn_packed__get_bytes(digest_stream, &len);
+          if (len != sizeof(rep.sha1_digest))
+            return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
+                                    _("Unexpected MD5 digest size %"
+                                      APR_SIZE_T_FMT),
+                                    len);
+
+          memcpy(rep.sha1_digest, bytes, sizeof(rep.sha1_digest));
+        }
+
+      APR_ARRAY_PUSH(reps, representation_t) = rep;
+    }
+
+  *reps_p = reps;
+  
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__read_noderevs_container(svn_fs_fs__noderevs_t **container,
+                                   svn_stream_t *stream,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
+{
+  apr_size_t i;
+  apr_size_t count;
+
+  svn_fs_fs__noderevs_t *noderevs
+    = apr_pcalloc(result_pool, sizeof(*noderevs));
+
+  svn_packed__data_root_t *root;
+  svn_packed__int_stream_t *structs_stream;
+  svn_packed__int_stream_t *ids_stream;
+  svn_packed__int_stream_t *data_reps_stream;
+  svn_packed__int_stream_t *prop_reps_stream;
+  svn_packed__int_stream_t *noderevs_stream;
+  svn_packed__byte_stream_t *digests_stream;
+
+  /* read everything from disk */
+  SVN_ERR(svn_fs_fs__read_string_table(&noderevs->paths, stream,
+                                       result_pool, scratch_pool));
+  SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool));
+
+  /* get streams */
+  structs_stream = svn_packed__first_int_stream(root);
+  ids_stream = svn_packed__first_int_substream(structs_stream);
+  data_reps_stream = svn_packed__next_int_stream(ids_stream);
+  prop_reps_stream = svn_packed__next_int_stream(data_reps_stream);
+  noderevs_stream = svn_packed__next_int_stream(prop_reps_stream);
+  digests_stream = svn_packed__first_byte_stream(root);
+
+  /* read ids array */
+  count
+    = svn_packed__int_count(svn_packed__first_int_substream(ids_stream));
+  noderevs->ids
+    = apr_array_make(result_pool, count, sizeof(binary_id_t));
+  for (i = 0; i < count; ++i)
+    {
+      binary_id_t id;
+
+      id.node_id.revision = svn_packed__get_uint(ids_stream);
+      id.node_id.number = svn_packed__get_uint(ids_stream);
+      id.copy_id.revision = svn_packed__get_uint(ids_stream);
+      id.copy_id.number = svn_packed__get_uint(ids_stream);
+      id.rev_id.revision = svn_packed__get_uint(ids_stream);
+      id.rev_id.number = svn_packed__get_uint(ids_stream);
+
+      APR_ARRAY_PUSH(noderevs->ids, binary_id_t) = id;
+    }
+    
+  /* read rep arrays */
+  SVN_ERR(read_reps(&noderevs->data_reps, data_reps_stream, digests_stream,
+                    result_pool));
+  SVN_ERR(read_reps(&noderevs->prop_reps, prop_reps_stream, digests_stream,
+                    result_pool));
+
+  /* read noderevs array */
+  count
+    = svn_packed__int_count(svn_packed__first_int_substream(noderevs_stream));
+  noderevs->noderevs
+    = apr_array_make(result_pool, count, sizeof(binary_noderev_t));
+  for (i = 0; i < count; ++i)
+    {
+      binary_noderev_t noderev;
+
+      noderev.flags = svn_packed__get_uint(noderevs_stream);
+
+      noderev.id = svn_packed__get_uint(noderevs_stream);
+      noderev.predecessor_id = svn_packed__get_uint(noderevs_stream);
+      noderev.predecessor_count = svn_packed__get_uint(noderevs_stream);
+
+      noderev.copyfrom_path = svn_packed__get_uint(noderevs_stream);
+      noderev.copyfrom_rev = svn_packed__get_uint(noderevs_stream);
+      noderev.copyroot_path = svn_packed__get_uint(noderevs_stream);
+      noderev.copyroot_path = svn_packed__get_uint(noderevs_stream);
+
+      noderev.prop_rep = svn_packed__get_uint(noderevs_stream);
+      noderev.data_rep = svn_packed__get_uint(noderevs_stream);
+
+      noderev.created_path = svn_packed__get_uint(noderevs_stream);
+      noderev.mergeinfo_count = svn_packed__get_uint(noderevs_stream);
+
+      APR_ARRAY_PUSH(noderevs->noderevs, binary_noderev_t) = noderev;
+    }
+
+  *container = noderevs;
+  
+  return SVN_NO_ERROR;
+}

Added: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.h?rev=1467454&view=auto
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.h (added)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/noderevs.h Fri Apr 12 20:36:02
2013
@@ -0,0 +1,100 @@
+/* noderevs.h --- FSFS node revision container
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_LIBSVN_FS__NODEREVS_H
+#define SVN_LIBSVN_FS__NODEREVS_H
+
+#include "svn_io.h"
+#include "fs.h"
+
+/* A collection of related noderevs tends to be widely redundant (similar
+ * paths, predecessor ID matching anothers ID, shared representations etc.)
+ * Also, the binary representation of a noderev can be much shorter than
+ * the ordinary textual variant.
+ *
+ * In its serialized form, the svn_fs_fs__noderevs_t container extracts
+ * most of that redundancy and the run-time representation is also much
+ * smaller than sum of the respective node_revision_t objects.
+ *
+ * As with other containers, this one has two modes: 'construction', in
+ * which you may add data to it, and 'getter' in which there is only r/o
+ * access to the data.
+ */
+
+/* An opaque collection of node revisions.
+ */
+typedef struct svn_fs_fs__noderevs_t svn_fs_fs__noderevs_t;
+
+/* Create and populate noderev containers. */
+
+/* Create and return a new noderevs container with an initial capacity of
+ * INITIAL_COUNT node_revision_t objects.  Allocate the result in POOL.
+ */
+svn_fs_fs__noderevs_t *
+svn_fs_fs__noderevs_create(apr_size_t initial_count,
+                           apr_pool_t *pool);
+
+/* Add NODEREV to the CONTAINER. Return the index that identifies the new
+ * item in this container.
+ */
+apr_size_t
+svn_fs_fs__noderevs_add(svn_fs_fs__noderevs_t *container,
+                        node_revision_t *noderev);
+
+/* Return a rough estimate in bytes for the serialized representation
+ * of CONTAINER.
+ */
+apr_size_t
+svn_fs_fs__noderevs_estimate_size(const svn_fs_fs__noderevs_t *container);
+
+/* Read from noderev containers. */
+
+/* From CONTAINER, extract the noderev with the given IDX.  Allocate
+ * the result in POOL and return it in *NODEREV_P.
+ */
+svn_error_t *
+svn_fs_fs__noderevs_get(node_revision_t **noderev_p,
+                        const svn_fs_fs__noderevs_t *container,
+                        apr_size_t idx,
+                        apr_pool_t *pool);
+
+/* I/O interface. */
+
+/* Write a serialized representation of CONTAINER to STREAM.  Use POOL for
+ * temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__write_noderevs_container(svn_stream_t *stream,
+                                    const svn_fs_fs__noderevs_t *container,
+                                    apr_pool_t *pool);
+
+/* Read a noderev container from its serialized representation in STREAM.
+ * Allocate the result in RESULT_POOL and return it in *CONTAINER.  Use
+ * SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__read_noderevs_container(svn_fs_fs__noderevs_t **container,
+                                   svn_stream_t *stream,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool);
+
+#endif
\ No newline at end of file



Mime
View raw message