Author: stefan2
Date: Sat Jul 31 20:28:49 2010
New Revision: 981090

URL: http://svn.apache.org/viewvc?rev=981090&view=rev
Log:
Introduce a simple serialization framework that simplifies and
speeds up serialization of most data structures used by FSFS,
for instance.

* subversion/include/private/svn_serializer.h
  (PCPCSTR, PCPCVOID, PPVOID): introduce useful typedefs
  (svn_serializer__context_t): introduce new data type
  (svn_serializer__init, svn_serializer__push, svn_serializer__pop, 
   svn_serializer__add_string, svn_serializer__get): declare new
  serialization functions
  (svn_deserializer__resolve): declare new deserialization function

Added:
    subversion/branches/performance/subversion/include/private/svn_serializer.h 
  (with props)
    subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c   
(with props)

Added: 
subversion/branches/performance/subversion/include/private/svn_serializer.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/private/svn_serializer.h?rev=981090&view=auto
==============================================================================
--- subversion/branches/performance/subversion/include/private/svn_serializer.h 
(added)
+++ subversion/branches/performance/subversion/include/private/svn_serializer.h 
Sat Jul 31 20:28:49 2010
@@ -0,0 +1,124 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    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.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file svn_serializer.h
+ * @brief Structure serialization helper API
+ */
+
+#include <apr.h>
+#include "svn_types.h"
+
+/* forward declaration */
+struct svn_stringbuf_t;
+
+/* We often use references to pointers. Although converting a pointer to
+ * a pointer can safely be cast to references to constant pointers to
+ * constant data, C compilers tend to reject them. Provide a couple of
+ * typedefs to simplify explicit casts.
+ */
+typedef const char * const * PCPCSTR;
+typedef const void * const * PCPCVOID;
+typedef void * * PPVOID;
+
+/**
+ * Opaque structure controlling the serialization process and holding the
+ * intermediate as well as final results.
+ */
+typedef struct svn_serializer__context_t svn_serializer__context_t;
+
+/**
+ * Begin the serialization process for the @a source_struct and all objects
+ * referenced from it. @a struct_size must match the result of @c sizeof()
+ * of the actual structure. Due to the generic nature of the init function
+ * we can't determine the structure size as part of the function.
+ *
+ * You may suggest a larger initial buffer size in @a suggested_buffer_size
+ * to minimize the number of internal buffer re-allocations during the
+ * serialization process. All allocations will be made from @a pool.
+ *
+ * Pointers within the structure will be replaced by their serialized
+ * representation when the respective strings or sub-structures get
+ * serialized. This scheme allows only for tree-like, i.e. non-circular
+ * data structures.
+ *
+ * @return the serization context.
+ */
+svn_serializer__context_t *
+svn_serializer__init(const void *source_struct,
+                     apr_size_t struct_size,
+                     apr_size_t suggested_buffer_size,
+                     apr_pool_t *pool);
+
+/**
+ * Begin serialization of a referenced sub-structure within the
+ * serialization @a context. @a source_struct must be a reference to the
+ * pointer in the original parent structure so that the correspondence in
+ * the serialized structure can be established. @a struct_size must match
+ * the result of @c sizeof() of the actual structure.
+ *
+ * Sub-structures and strings will be added in a FIFO fashion. If you need
+ * add further sub-structures on the same level, you need to call @ref
+ * svn_serializer__pop to realign the serialization context.
+ */
+void
+svn_serializer__push(svn_serializer__context_t *context,
+                     PCPCVOID source_struct,
+                     apr_size_t struct_size);
+
+/**
+ * End the serialization of the current sub-structure. The serialization
+ * @c context will be focussed back on the parent structure. You may then
+ * add further sub-structures starting from that level.
+ *
+ * It is not necessary to call this function just for symmetry at the end
+ * of the serialization process.
+ */
+void
+svn_serializer__pop(svn_serializer__context_t *context);
+
+/**
+ * Serialize a string referenced from the current structure within the
+ * serialization @a context. @a s must be a reference to the @c char*
+ * pointer in the original structure so that the correspondence in the
+ * serialized structure can be established.
+ */
+void
+svn_serializer__add_string(svn_serializer__context_t *context, PCPCSTR s);
+
+/**
+ * @return a reference to the data buffer containing the data serialialized
+ * so far in the given serialization @a context.
+ */
+struct svn_stringbuf_t *
+svn_serializer__get(svn_serializer__context_t *context);
+
+/**
+ * Deserialization is straightforward: just copy the serialized buffer to
+ * a natively aligned memory location (APR pools will take care of that
+ * automatically) and resolve all pointers to sub-structures.
+ *
+ * To do the latter, call this function for each of these pointers, giving
+ * the start address of the copyied buffer in @a buffer and a reference to
+ * the pointer to resolve in @a ptr.
+ */
+void
+svn_deserializer__resolve(void *buffer, PPVOID ptr);

Propchange: 
subversion/branches/performance/subversion/include/private/svn_serializer.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c?rev=981090&view=auto
==============================================================================
--- subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c 
(added)
+++ subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c Sat 
Jul 31 20:28:49 2010
@@ -0,0 +1,242 @@
+/*
+ * svn_serializer.c: serialization helper functions
+ *
+ * ====================================================================
+ *    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 <assert.h>
+#include "private/svn_serializer.h"
+#include "svn_string.h"
+
+/* This is a very efficient serialization and especially efficient
+ * deserialization framework. The idea is just to concatenate all sub-
+ * structures and strings into a single buffer while preserving proper
+ * member alignment. Pointers will be replaced by the respective data
+ * offsets in the buffer when that target that it pointed to gets
+ * serialized, i.e. appended to the data buffer written so far.
+ *
+ * Hence, deserialization can be simply done by copying the buffer and
+ * adjusting the pointers. No fine-grained allocation and copying is
+ * necessary. 
+ */
+
+/* An element in the structure stack. It contains a pointer to the source
+ * structure so that the relative offset of sub-structure or string
+ * references can be determined properly. It also contains the corresponding
+ * position within the serialized data. Thus, pointers can be serialized
+ * as offsets within the target buffer.
+ */
+typedef struct source_stack_t
+{
+  /* the source structure passed in to *_init or *_push */
+  const void *source_struct;
+
+  /* offset within the target buffer to where the structure got copied */
+  apr_size_t target_offset;
+
+  /* parent stack entry. Will be NULL for the root entry. */
+  struct source_stack_t *upper;
+} source_stack_t;
+
+/* Serialization context info. It basically consists of the buffer holding
+ * the serialized result and the stack of source structure information.
+ */
+struct svn_serializer__context_t
+{
+  /* allocations are made from this pool */
+  apr_pool_t *pool;
+
+  /* the buffer holding all serialized data */
+  svn_stringbuf_t *buffer;
+
+  /* the stack of structures being serialized. If NULL, the serialization
+   * process has been finished. However, it is not necessarily NULL when
+   * the application end serialization. */
+  source_stack_t *source;
+};
+
+/* Mmake sure the serialized data len is a multiple of the default alignment,
+ * i.e. structures may be appended without violating member alignment
+ * guarantees.
+ */
+static void
+align_buffer_end(svn_serializer__context_t *context)
+{
+  apr_size_t current_len = context->buffer->len;
+  apr_size_t aligned_len = APR_ALIGN_DEFAULT(current_len);
+  if (aligned_len != current_len)
+    {
+      svn_stringbuf_ensure(context->buffer, aligned_len+1);
+      context->buffer->len = aligned_len;
+    }
+}
+
+/* Begin the serialization process for the SOURCE_STRUCT and all objects
+ * referenced from it. STRUCT_SIZE must match the result of sizeof() of
+ * the actual structure. You may suggest a larger initial buffer size
+ * in SUGGESTED_BUFFER_SIZE to minimize the number of internal buffer
+ * re-allocations during the serialization process. All allocations will
+ * be made from POOL.
+ */
+svn_serializer__context_t *
+svn_serializer__init(const void *source_struct,
+                     apr_size_t struct_size,
+                     apr_size_t suggested_buffer_size,
+                     apr_pool_t *pool)
+{
+  /* select a meaningful initial memory buffer capacity */
+  apr_size_t init_size = suggested_buffer_size < struct_size
+                       ? struct_size
+                       : suggested_buffer_size;
+
+  /* create the serialization context and initialize it, including the
+   * structure stack */
+  svn_serializer__context_t *context = apr_palloc(pool, sizeof(*context));
+  context->pool = pool;
+  context->buffer = svn_stringbuf_create_ensure(init_size, pool);
+  context->source = apr_palloc(pool, sizeof(*context->source));
+  context->source->source_struct = source_struct;
+  context->source->target_offset = 0;
+  context->source->upper = NULL;
+
+  /* serialize, i.e. append, the content of the first structure */
+  svn_stringbuf_appendbytes(context->buffer, source_struct, struct_size);
+
+  /* done */
+  return context;
+}
+
+/* Utility function replacing the serialized pointer corresponding to
+ * *SOURCE_POINTER with the offset that it will be put when being append
+ * right after this function call.
+ */
+static void
+store_current_end_pointer(svn_serializer__context_t *context,
+                          PCPCVOID source_pointer)
+{
+  /* relative position of the serialized pointer to the begin of the buffer */
+  apr_size_t offset = (const char *)source_pointer
+                    - (const char *)context->source->source_struct
+                    + context->source->target_offset;
+
+  /* use the serialized pointer as a storage for the offset */
+  apr_size_t *target_string_ptr = (apr_size_t*)(context->buffer->data + 
offset);
+
+  /* the offset must be within the serialized data. Otherwise, you forgot
+   * to serialize the respective sub-struct. */
+  assert(context->buffer->len > offset);
+
+  /* store the current buffer length because that's where we will append
+   * the serialized data of the sub-struct or string */
+  *target_string_ptr = *source_pointer == NULL ? 0 : context->buffer->len;
+}
+
+/* Begin serialization of a referenced sub-structure within the
+ * serialization CONTEXT. SOURCE_STRUCT must be a reference to the pointer
+ * in the original parent structure so that the correspondence in the
+ * serialized structure can be established. STRUCT_SIZE must match the 
+ * result of sizeof() of the actual structure.
+ */
+void
+svn_serializer__push(svn_serializer__context_t *context,
+                     PCPCVOID source_struct,
+                     apr_size_t struct_size)
+{
+  /* create a new entry for the structure stack */
+  source_stack_t *new = apr_palloc(context->pool, sizeof(*new));
+
+  /* the serialized structure must be properly aligned */
+  if (*source_struct)
+    align_buffer_end(context);
+
+  /* Store the offset at which the struct data that will the appended.
+   * Write 0 for NULL pointers. */
+  store_current_end_pointer(context, source_struct);
+
+  /* store source and target information */
+  new->source_struct = *source_struct;
+  new->target_offset = context->buffer->len;
+
+  /* put the new entry onto the stack*/
+  new->upper = context->source;
+  context->source = new;
+
+  /* finally, actually append the new struct
+   * (so we can now manipulate pointers within it) */
+  if (*source_struct)
+    svn_stringbuf_appendbytes(context->buffer, *source_struct, struct_size);
+}
+
+/* Remove the lastest structure from the stack.
+ */
+void
+svn_serializer__pop(svn_serializer__context_t *context)
+{
+  /* we may pop the original struct but not further */
+  assert(context->source);
+
+  /* one level up the structure stack */
+  context->source = context->source->upper;
+}
+
+/* Serialize a string referenced from the current structure within the
+ * serialization CONTEXT. S must be a reference to the char* pointer in 
+ * the original structure so that the correspondence in the serialized 
+ * structure can be established.
+ */
+void
+svn_serializer__add_string(svn_serializer__context_t *context, PCPCSTR s)
+{
+  /* Store the offset at which the string data that will the appended.
+   * Write 0 for NULL pointers. Strings don't need special alignment. */
+  store_current_end_pointer(context, (const void **)s);
+
+  /* append the string data */
+  if (*s)
+    svn_stringbuf_appendbytes(context->buffer, *s, strlen(*s) + 1);
+}
+
+/* Return the the data buffer that receives the serialialized data from
+ * the given serialization CONTEXT.
+ */
+svn_stringbuf_t *
+svn_serializer__get(svn_serializer__context_t *context)
+{
+  return context->buffer;
+}
+
+/* Replace the deserialized pointer value at PTR inside BUFFER with a 
+ * proper pointer value.
+ */
+void
+svn_deserializer__resolve(void *buffer, PPVOID ptr)
+{
+  if ((apr_size_t)*ptr)
+    {
+      /* replace the offset in *ptr with the pointer to buffer[*ptr] */
+      (*(const char **)ptr) = (const char*)buffer + (apr_size_t)*ptr;
+    }
+  else
+    {
+      /* NULL pointers are stored as 0 which might have a different
+       * binary representation. */
+      *ptr = NULL;
+    }
+}

Propchange: 
subversion/branches/performance/subversion/libsvn_subr/svn_serializer.c
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to