1289177Speter/* temp_serializer.c: serialization functions for caching of FSX structures
2289177Speter *
3289177Speter * ====================================================================
4289177Speter *    Licensed to the Apache Software Foundation (ASF) under one
5289177Speter *    or more contributor license agreements.  See the NOTICE file
6289177Speter *    distributed with this work for additional information
7289177Speter *    regarding copyright ownership.  The ASF licenses this file
8289177Speter *    to you under the Apache License, Version 2.0 (the
9289177Speter *    "License"); you may not use this file except in compliance
10289177Speter *    with the License.  You may obtain a copy of the License at
11289177Speter *
12289177Speter *      http://www.apache.org/licenses/LICENSE-2.0
13289177Speter *
14289177Speter *    Unless required by applicable law or agreed to in writing,
15289177Speter *    software distributed under the License is distributed on an
16289177Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17289177Speter *    KIND, either express or implied.  See the License for the
18289177Speter *    specific language governing permissions and limitations
19289177Speter *    under the License.
20289177Speter * ====================================================================
21289177Speter */
22289177Speter
23289177Speter#include <apr_pools.h>
24289177Speter
25289177Speter#include "svn_pools.h"
26289177Speter#include "svn_hash.h"
27289177Speter#include "svn_sorts.h"
28289177Speter#include "svn_fs.h"
29289177Speter
30289177Speter#include "private/svn_fs_util.h"
31289177Speter#include "private/svn_sorts_private.h"
32289177Speter#include "private/svn_temp_serializer.h"
33289177Speter#include "private/svn_subr_private.h"
34289177Speter
35289177Speter#include "id.h"
36289177Speter#include "temp_serializer.h"
37289177Speter#include "low_level.h"
38289177Speter#include "cached_data.h"
39289177Speter
40289177Speter/* Utility to encode a signed NUMBER into a variable-length sequence of
41289177Speter * 8-bit chars in KEY_BUFFER and return the last writen position.
42289177Speter *
43289177Speter * Numbers will be stored in 7 bits / byte and using byte values above
44289177Speter * 32 (' ') to make them combinable with other string by simply separating
45289177Speter * individual parts with spaces.
46289177Speter */
47289177Speterstatic char*
48289177Speterencode_number(apr_int64_t number, char *key_buffer)
49289177Speter{
50289177Speter  /* encode the sign in the first byte */
51289177Speter  if (number < 0)
52289177Speter  {
53289177Speter    number = -number;
54289177Speter    *key_buffer = (char)((number & 63) + ' ' + 65);
55289177Speter  }
56289177Speter  else
57289177Speter    *key_buffer = (char)((number & 63) + ' ' + 1);
58289177Speter  number /= 64;
59289177Speter
60289177Speter  /* write 7 bits / byte until no significant bits are left */
61289177Speter  while (number)
62289177Speter  {
63289177Speter    *++key_buffer = (char)((number & 127) + ' ' + 1);
64289177Speter    number /= 128;
65289177Speter  }
66289177Speter
67289177Speter  /* return the last written position */
68289177Speter  return key_buffer;
69289177Speter}
70289177Speter
71289177Speterconst char*
72289177Spetersvn_fs_x__combine_number_and_string(apr_int64_t number,
73289177Speter                                    const char *string,
74362181Sdim                                    apr_pool_t *result_pool)
75289177Speter{
76289177Speter  apr_size_t len = strlen(string);
77289177Speter
78289177Speter  /* number part requires max. 10x7 bits + 1 space.
79289177Speter   * Add another 1 for the terminal 0 */
80362181Sdim  char *key_buffer = apr_palloc(result_pool, len + 12);
81289177Speter  const char *key = key_buffer;
82289177Speter
83289177Speter  /* Prepend the number to the string and separate them by space. No other
84289177Speter   * number can result in the same prefix, no other string in the same
85289177Speter   * postfix nor can the boundary between them be ambiguous. */
86289177Speter  key_buffer = encode_number(number, key_buffer);
87289177Speter  *++key_buffer = ' ';
88289177Speter  memcpy(++key_buffer, string, len+1);
89289177Speter
90289177Speter  /* return the start of the key */
91289177Speter  return key;
92289177Speter}
93289177Speter
94289177Speter/* Utility function to serialize string S in the given serialization CONTEXT.
95289177Speter */
96289177Speterstatic void
97289177Speterserialize_svn_string(svn_temp_serializer__context_t *context,
98289177Speter                     const svn_string_t * const *s)
99289177Speter{
100289177Speter  const svn_string_t *string = *s;
101289177Speter
102289177Speter  /* Nothing to do for NULL string references. */
103289177Speter  if (string == NULL)
104289177Speter    return;
105289177Speter
106289177Speter  svn_temp_serializer__push(context,
107289177Speter                            (const void * const *)s,
108289177Speter                            sizeof(*string));
109289177Speter
110289177Speter  /* the "string" content may actually be arbitrary binary data.
111289177Speter   * Thus, we cannot use svn_temp_serializer__add_string. */
112289177Speter  svn_temp_serializer__add_leaf(context,
113289177Speter                                (const void * const *)&string->data,
114289177Speter                                string->len + 1);
115289177Speter
116289177Speter  /* back to the caller's nesting level */
117289177Speter  svn_temp_serializer__pop(context);
118289177Speter}
119289177Speter
120289177Speter/* Utility function to deserialize the STRING inside the BUFFER.
121289177Speter */
122289177Speterstatic void
123362181Sdimdeserialize_svn_string(const void *buffer, svn_string_t **string)
124289177Speter{
125289177Speter  svn_temp_deserializer__resolve(buffer, (void **)string);
126289177Speter  if (*string == NULL)
127289177Speter    return;
128289177Speter
129289177Speter  svn_temp_deserializer__resolve(*string, (void **)&(*string)->data);
130289177Speter}
131289177Speter
132289177Speter/* Utility function to serialize the REPRESENTATION within the given
133289177Speter * serialization CONTEXT.
134289177Speter */
135289177Speterstatic void
136289177Speterserialize_representation(svn_temp_serializer__context_t *context,
137289177Speter                         svn_fs_x__representation_t * const *representation)
138289177Speter{
139289177Speter  const svn_fs_x__representation_t * rep = *representation;
140289177Speter  if (rep == NULL)
141289177Speter    return;
142289177Speter
143289177Speter  /* serialize the representation struct itself */
144289177Speter  svn_temp_serializer__add_leaf(context,
145289177Speter                                (const void * const *)representation,
146289177Speter                                sizeof(*rep));
147289177Speter}
148289177Speter
149289177Spetervoid
150289177Spetersvn_fs_x__serialize_apr_array(svn_temp_serializer__context_t *context,
151289177Speter                              apr_array_header_t **a)
152289177Speter{
153289177Speter  const apr_array_header_t *array = *a;
154289177Speter
155289177Speter  /* Nothing to do for NULL string references. */
156289177Speter  if (array == NULL)
157289177Speter    return;
158289177Speter
159289177Speter  /* array header struct */
160289177Speter  svn_temp_serializer__push(context,
161289177Speter                            (const void * const *)a,
162289177Speter                            sizeof(*array));
163289177Speter
164289177Speter  /* contents */
165289177Speter  svn_temp_serializer__add_leaf(context,
166289177Speter                                (const void * const *)&array->elts,
167289177Speter                                (apr_size_t)array->nelts * array->elt_size);
168289177Speter
169289177Speter  /* back to the caller's nesting level */
170289177Speter  svn_temp_serializer__pop(context);
171289177Speter}
172289177Speter
173289177Spetervoid
174289177Spetersvn_fs_x__deserialize_apr_array(void *buffer,
175289177Speter                                apr_array_header_t **array,
176362181Sdim                                apr_pool_t *result_pool)
177289177Speter{
178289177Speter  svn_temp_deserializer__resolve(buffer, (void **)array);
179289177Speter  if (*array == NULL)
180289177Speter    return;
181289177Speter
182289177Speter  svn_temp_deserializer__resolve(*array, (void **)&(*array)->elts);
183362181Sdim  (*array)->pool = result_pool;
184289177Speter}
185289177Speter
186289177Speter/* auxilliary structure representing the content of a directory array */
187289177Spetertypedef struct dir_data_t
188289177Speter{
189289177Speter  /* number of entries in the directory
190289177Speter   * (it's int because the directory is an APR array) */
191289177Speter  int count;
192289177Speter
193362181Sdim  /** Current length of the in-txn in-disk representation of the directory.
194362181Sdim   * SVN_INVALID_FILESIZE if unknown (i.e. committed data). */
195362181Sdim  svn_filesize_t txn_filesize;
196362181Sdim
197289177Speter  /* number of unused dir entry buckets in the index */
198289177Speter  apr_size_t over_provision;
199289177Speter
200289177Speter  /* internal modifying operations counter
201289177Speter   * (used to repack data once in a while) */
202289177Speter  apr_size_t operations;
203289177Speter
204289177Speter  /* size of the serialization buffer actually used.
205289177Speter   * (we will allocate more than we actually need such that we may
206289177Speter   * append more data in situ later) */
207289177Speter  apr_size_t len;
208289177Speter
209289177Speter  /* reference to the entries */
210289177Speter  svn_fs_x__dirent_t **entries;
211289177Speter
212289177Speter  /* size of the serialized entries and don't be too wasteful
213289177Speter   * (needed since the entries are no longer in sequence) */
214289177Speter  apr_uint32_t *lengths;
215289177Speter} dir_data_t;
216289177Speter
217289177Speter/* Utility function to serialize the *ENTRY_P into a the given
218289177Speter * serialization CONTEXT. Return the serialized size of the
219289177Speter * dir entry in *LENGTH.
220289177Speter */
221289177Speterstatic void
222289177Speterserialize_dir_entry(svn_temp_serializer__context_t *context,
223289177Speter                    svn_fs_x__dirent_t **entry_p,
224289177Speter                    apr_uint32_t *length)
225289177Speter{
226289177Speter  svn_fs_x__dirent_t *entry = *entry_p;
227289177Speter  apr_size_t initial_length = svn_temp_serializer__get_length(context);
228289177Speter
229289177Speter  svn_temp_serializer__push(context,
230289177Speter                            (const void * const *)entry_p,
231362181Sdim                            sizeof(**entry_p));
232289177Speter
233289177Speter  svn_temp_serializer__add_string(context, &entry->name);
234289177Speter
235289177Speter  *length = (apr_uint32_t)(  svn_temp_serializer__get_length(context)
236289177Speter                           - APR_ALIGN_DEFAULT(initial_length));
237289177Speter
238289177Speter  svn_temp_serializer__pop(context);
239289177Speter}
240289177Speter
241362181Sdim/* Utility function to serialize the DIR into a new serialization
242289177Speter * context to be returned.
243289177Speter *
244289177Speter * Temporary allocation will be made form SCRATCH_POOL.
245289177Speter */
246289177Speterstatic svn_temp_serializer__context_t *
247362181Sdimserialize_dir(svn_fs_x__dir_data_t *dir,
248289177Speter              apr_pool_t *scratch_pool)
249289177Speter{
250289177Speter  dir_data_t dir_data;
251289177Speter  int i = 0;
252289177Speter  svn_temp_serializer__context_t *context;
253362181Sdim  apr_array_header_t *entries = dir->entries;
254289177Speter
255289177Speter  /* calculate sizes */
256289177Speter  int count = entries->nelts;
257289177Speter  apr_size_t over_provision = 2 + count / 4;
258289177Speter  apr_size_t entries_len =   (count + over_provision)
259289177Speter                           * sizeof(svn_fs_x__dirent_t*);
260289177Speter  apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
261289177Speter
262362181Sdim  /* Estimate the size of a directory entry + its name. */
263362181Sdim  enum { ENTRY_SIZE = sizeof(svn_fs_x__dirent_t) + 32 };
264362181Sdim
265289177Speter  /* copy the hash entries to an auxiliary struct of known layout */
266289177Speter  dir_data.count = count;
267362181Sdim  dir_data.txn_filesize = dir->txn_filesize;
268289177Speter  dir_data.over_provision = over_provision;
269289177Speter  dir_data.operations = 0;
270289177Speter  dir_data.entries = apr_palloc(scratch_pool, entries_len);
271289177Speter  dir_data.lengths = apr_palloc(scratch_pool, lengths_len);
272289177Speter
273289177Speter  for (i = 0; i < count; ++i)
274289177Speter    dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_x__dirent_t *);
275289177Speter
276289177Speter  /* Serialize that aux. structure into a new one. Also, provide a good
277289177Speter   * estimate for the size of the buffer that we will need. */
278289177Speter  context = svn_temp_serializer__init(&dir_data,
279289177Speter                                      sizeof(dir_data),
280362181Sdim                                      50 + count * ENTRY_SIZE
281362181Sdim                                         + entries_len + lengths_len,
282289177Speter                                      scratch_pool);
283289177Speter
284289177Speter  /* serialize entries references */
285289177Speter  svn_temp_serializer__push(context,
286289177Speter                            (const void * const *)&dir_data.entries,
287289177Speter                            entries_len);
288289177Speter
289289177Speter  /* serialize the individual entries and their sub-structures */
290289177Speter  for (i = 0; i < count; ++i)
291289177Speter    serialize_dir_entry(context,
292289177Speter                        &dir_data.entries[i],
293289177Speter                        &dir_data.lengths[i]);
294289177Speter
295289177Speter  svn_temp_serializer__pop(context);
296289177Speter
297289177Speter  /* serialize entries references */
298289177Speter  svn_temp_serializer__push(context,
299289177Speter                            (const void * const *)&dir_data.lengths,
300289177Speter                            lengths_len);
301289177Speter
302289177Speter  return context;
303289177Speter}
304289177Speter
305362181Sdim/* Utility function to reconstruct a dir entries struct from serialized data
306362181Sdim * in BUFFER and DIR_DATA. Allocation will be made form RESULT_POOL.
307289177Speter */
308362181Sdimstatic svn_fs_x__dir_data_t *
309362181Sdimdeserialize_dir(void *buffer,
310362181Sdim                dir_data_t *dir_data,
311362181Sdim                apr_pool_t *result_pool)
312289177Speter{
313362181Sdim  svn_fs_x__dir_data_t *result;
314289177Speter  apr_size_t i;
315289177Speter  apr_size_t count;
316289177Speter  svn_fs_x__dirent_t *entry;
317289177Speter  svn_fs_x__dirent_t **entries;
318289177Speter
319362181Sdim  /* Construct empty directory object. */
320362181Sdim  result = apr_pcalloc(result_pool, sizeof(*result));
321362181Sdim  result->entries
322362181Sdim    = apr_array_make(result_pool, dir_data->count,
323362181Sdim                     sizeof(svn_fs_x__dirent_t *));
324362181Sdim  result->txn_filesize = dir_data->txn_filesize;
325362181Sdim
326289177Speter  /* resolve the reference to the entries array */
327289177Speter  svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
328289177Speter  entries = dir_data->entries;
329289177Speter
330362181Sdim  /* fixup the references within each entry and add it to the RESULT */
331289177Speter  for (i = 0, count = dir_data->count; i < count; ++i)
332289177Speter    {
333289177Speter      svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
334289177Speter      entry = dir_data->entries[i];
335289177Speter
336289177Speter      /* pointer fixup */
337289177Speter      svn_temp_deserializer__resolve(entry, (void **)&entry->name);
338289177Speter
339289177Speter      /* add the entry to the hash */
340362181Sdim      APR_ARRAY_PUSH(result->entries, svn_fs_x__dirent_t *) = entry;
341289177Speter    }
342289177Speter
343289177Speter  /* return the now complete hash */
344289177Speter  return result;
345289177Speter}
346289177Speter
347362181Sdim/**
348362181Sdim * Serialize a NODEREV_P within the serialization CONTEXT.
349362181Sdim */
350362181Sdimstatic void
351362181Sdimnoderev_serialize(svn_temp_serializer__context_t *context,
352362181Sdim                  svn_fs_x__noderev_t * const *noderev_p)
353289177Speter{
354289177Speter  const svn_fs_x__noderev_t *noderev = *noderev_p;
355289177Speter  if (noderev == NULL)
356289177Speter    return;
357289177Speter
358289177Speter  /* serialize the representation struct itself */
359289177Speter  svn_temp_serializer__push(context,
360289177Speter                            (const void * const *)noderev_p,
361289177Speter                            sizeof(*noderev));
362289177Speter
363289177Speter  /* serialize sub-structures */
364289177Speter  serialize_representation(context, &noderev->prop_rep);
365289177Speter  serialize_representation(context, &noderev->data_rep);
366289177Speter
367289177Speter  svn_temp_serializer__add_string(context, &noderev->copyfrom_path);
368289177Speter  svn_temp_serializer__add_string(context, &noderev->copyroot_path);
369289177Speter  svn_temp_serializer__add_string(context, &noderev->created_path);
370289177Speter
371289177Speter  /* return to the caller's nesting level */
372289177Speter  svn_temp_serializer__pop(context);
373289177Speter}
374289177Speter
375362181Sdim/**
376362181Sdim * Deserialize a NODEREV_P within the BUFFER and associate it with.
377362181Sdim */
378362181Sdimstatic void
379362181Sdimnoderev_deserialize(void *buffer,
380362181Sdim                    svn_fs_x__noderev_t **noderev_p)
381289177Speter{
382289177Speter  svn_fs_x__noderev_t *noderev;
383289177Speter
384289177Speter  /* fixup the reference to the representation itself,
385289177Speter   * if this is part of a parent structure. */
386289177Speter  if (buffer != *noderev_p)
387289177Speter    svn_temp_deserializer__resolve(buffer, (void **)noderev_p);
388289177Speter
389289177Speter  noderev = *noderev_p;
390289177Speter  if (noderev == NULL)
391289177Speter    return;
392289177Speter
393289177Speter  /* fixup of sub-structures */
394289177Speter  svn_temp_deserializer__resolve(noderev, (void **)&noderev->prop_rep);
395289177Speter  svn_temp_deserializer__resolve(noderev, (void **)&noderev->data_rep);
396289177Speter
397289177Speter  svn_temp_deserializer__resolve(noderev, (void **)&noderev->copyfrom_path);
398289177Speter  svn_temp_deserializer__resolve(noderev, (void **)&noderev->copyroot_path);
399289177Speter  svn_temp_deserializer__resolve(noderev, (void **)&noderev->created_path);
400289177Speter}
401289177Speter
402289177Speter
403289177Speter/* Utility function to serialize COUNT svn_txdelta_op_t objects
404289177Speter * at OPS in the given serialization CONTEXT.
405289177Speter */
406289177Speterstatic void
407289177Speterserialize_txdelta_ops(svn_temp_serializer__context_t *context,
408289177Speter                      const svn_txdelta_op_t * const * ops,
409289177Speter                      apr_size_t count)
410289177Speter{
411289177Speter  if (*ops == NULL)
412289177Speter    return;
413289177Speter
414289177Speter  /* the ops form a contiguous chunk of memory with no further references */
415289177Speter  svn_temp_serializer__add_leaf(context,
416289177Speter                                (const void * const *)ops,
417289177Speter                                count * sizeof(svn_txdelta_op_t));
418289177Speter}
419289177Speter
420289177Speter/* Utility function to serialize W in the given serialization CONTEXT.
421289177Speter */
422289177Speterstatic void
423289177Speterserialize_txdeltawindow(svn_temp_serializer__context_t *context,
424289177Speter                        svn_txdelta_window_t * const * w)
425289177Speter{
426289177Speter  svn_txdelta_window_t *window = *w;
427289177Speter
428289177Speter  /* serialize the window struct itself */
429289177Speter  svn_temp_serializer__push(context,
430289177Speter                            (const void * const *)w,
431289177Speter                            sizeof(svn_txdelta_window_t));
432289177Speter
433289177Speter  /* serialize its sub-structures */
434289177Speter  serialize_txdelta_ops(context, &window->ops, window->num_ops);
435289177Speter  serialize_svn_string(context, &window->new_data);
436289177Speter
437289177Speter  svn_temp_serializer__pop(context);
438289177Speter}
439289177Speter
440289177Spetersvn_error_t *
441289177Spetersvn_fs_x__serialize_txdelta_window(void **buffer,
442289177Speter                                   apr_size_t *buffer_size,
443289177Speter                                   void *item,
444289177Speter                                   apr_pool_t *pool)
445289177Speter{
446289177Speter  svn_fs_x__txdelta_cached_window_t *window_info = item;
447289177Speter  svn_stringbuf_t *serialized;
448289177Speter
449289177Speter  /* initialize the serialization process and allocate a buffer large
450289177Speter   * enough to do without the need of re-allocations in most cases. */
451289177Speter  apr_size_t text_len = window_info->window->new_data
452289177Speter                      ? window_info->window->new_data->len
453289177Speter                      : 0;
454289177Speter  svn_temp_serializer__context_t *context =
455289177Speter      svn_temp_serializer__init(window_info,
456289177Speter                                sizeof(*window_info),
457289177Speter                                500 + text_len,
458289177Speter                                pool);
459289177Speter
460289177Speter  /* serialize the sub-structure(s) */
461289177Speter  serialize_txdeltawindow(context, &window_info->window);
462289177Speter
463289177Speter  /* return the serialized result */
464289177Speter  serialized = svn_temp_serializer__get(context);
465289177Speter
466289177Speter  *buffer = serialized->data;
467289177Speter  *buffer_size = serialized->len;
468289177Speter
469289177Speter  return SVN_NO_ERROR;
470289177Speter}
471289177Speter
472289177Spetersvn_error_t *
473289177Spetersvn_fs_x__deserialize_txdelta_window(void **item,
474289177Speter                                     void *buffer,
475289177Speter                                     apr_size_t buffer_size,
476362181Sdim                                     apr_pool_t *result_pool)
477289177Speter{
478289177Speter  svn_txdelta_window_t *window;
479289177Speter
480289177Speter  /* Copy the _full_ buffer as it also contains the sub-structures. */
481289177Speter  svn_fs_x__txdelta_cached_window_t *window_info =
482289177Speter      (svn_fs_x__txdelta_cached_window_t *)buffer;
483289177Speter
484289177Speter  /* pointer reference fixup */
485289177Speter  svn_temp_deserializer__resolve(window_info,
486289177Speter                                 (void **)&window_info->window);
487289177Speter  window = window_info->window;
488289177Speter
489289177Speter  svn_temp_deserializer__resolve(window, (void **)&window->ops);
490289177Speter
491289177Speter  deserialize_svn_string(window, (svn_string_t**)&window->new_data);
492289177Speter
493289177Speter  /* done */
494289177Speter  *item = window_info;
495289177Speter
496289177Speter  return SVN_NO_ERROR;
497289177Speter}
498289177Speter
499289177Speter/* Auxiliary structure representing the content of a properties hash.
500289177Speter   This structure is much easier to (de-)serialize than an apr_hash.
501289177Speter */
502289177Spetertypedef struct properties_data_t
503289177Speter{
504289177Speter  /* number of entries in the hash */
505289177Speter  apr_size_t count;
506289177Speter
507289177Speter  /* reference to the keys */
508289177Speter  const char **keys;
509289177Speter
510289177Speter  /* reference to the values */
511289177Speter  const svn_string_t **values;
512289177Speter} properties_data_t;
513289177Speter
514289177Speter/* Serialize COUNT C-style strings from *STRINGS into CONTEXT. */
515289177Speterstatic void
516289177Speterserialize_cstring_array(svn_temp_serializer__context_t *context,
517289177Speter                        const char ***strings,
518289177Speter                        apr_size_t count)
519289177Speter{
520289177Speter  apr_size_t i;
521289177Speter  const char **entries = *strings;
522289177Speter
523289177Speter  /* serialize COUNT entries pointers (the array) */
524289177Speter  svn_temp_serializer__push(context,
525289177Speter                            (const void * const *)strings,
526289177Speter                            count * sizeof(const char*));
527289177Speter
528289177Speter  /* serialize array elements */
529289177Speter  for (i = 0; i < count; ++i)
530289177Speter    svn_temp_serializer__add_string(context, &entries[i]);
531289177Speter
532289177Speter  svn_temp_serializer__pop(context);
533289177Speter}
534289177Speter
535289177Speter/* Serialize COUNT svn_string_t* items from *STRINGS into CONTEXT. */
536289177Speterstatic void
537289177Speterserialize_svn_string_array(svn_temp_serializer__context_t *context,
538289177Speter                           const svn_string_t ***strings,
539289177Speter                           apr_size_t count)
540289177Speter{
541289177Speter  apr_size_t i;
542289177Speter  const svn_string_t **entries = *strings;
543289177Speter
544289177Speter  /* serialize COUNT entries pointers (the array) */
545289177Speter  svn_temp_serializer__push(context,
546289177Speter                            (const void * const *)strings,
547289177Speter                            count * sizeof(const char*));
548289177Speter
549289177Speter  /* serialize array elements */
550289177Speter  for (i = 0; i < count; ++i)
551289177Speter    serialize_svn_string(context, &entries[i]);
552289177Speter
553289177Speter  svn_temp_serializer__pop(context);
554289177Speter}
555289177Speter
556289177Spetersvn_error_t *
557289177Spetersvn_fs_x__serialize_properties(void **data,
558289177Speter                               apr_size_t *data_len,
559289177Speter                               void *in,
560289177Speter                               apr_pool_t *pool)
561289177Speter{
562289177Speter  apr_hash_t *hash = in;
563289177Speter  properties_data_t properties;
564289177Speter  svn_temp_serializer__context_t *context;
565289177Speter  apr_hash_index_t *hi;
566289177Speter  svn_stringbuf_t *serialized;
567289177Speter  apr_size_t i;
568289177Speter
569289177Speter  /* create our auxiliary data structure */
570289177Speter  properties.count = apr_hash_count(hash);
571289177Speter  properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
572362181Sdim  properties.values = apr_palloc(pool, sizeof(const svn_string_t *) * properties.count);
573289177Speter
574289177Speter  /* populate it with the hash entries */
575289177Speter  for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i)
576289177Speter    {
577289177Speter      properties.keys[i] = apr_hash_this_key(hi);
578289177Speter      properties.values[i] = apr_hash_this_val(hi);
579289177Speter    }
580289177Speter
581289177Speter  /* serialize it */
582289177Speter  context = svn_temp_serializer__init(&properties,
583289177Speter                                      sizeof(properties),
584289177Speter                                      properties.count * 100,
585289177Speter                                      pool);
586289177Speter
587289177Speter  properties.keys[i] = "";
588289177Speter  serialize_cstring_array(context, &properties.keys, properties.count + 1);
589289177Speter  serialize_svn_string_array(context, &properties.values, properties.count);
590289177Speter
591289177Speter  /* return the serialized result */
592289177Speter  serialized = svn_temp_serializer__get(context);
593289177Speter
594289177Speter  *data = serialized->data;
595289177Speter  *data_len = serialized->len;
596289177Speter
597289177Speter  return SVN_NO_ERROR;
598289177Speter}
599289177Speter
600289177Spetersvn_error_t *
601289177Spetersvn_fs_x__deserialize_properties(void **out,
602289177Speter                                 void *data,
603289177Speter                                 apr_size_t data_len,
604362181Sdim                                 apr_pool_t *result_pool)
605289177Speter{
606362181Sdim  apr_hash_t *hash = svn_hash__make(result_pool);
607289177Speter  properties_data_t *properties = (properties_data_t *)data;
608289177Speter  size_t i;
609289177Speter
610289177Speter  /* de-serialize our auxiliary data structure */
611289177Speter  svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
612289177Speter  svn_temp_deserializer__resolve(properties, (void**)&properties->values);
613289177Speter
614289177Speter  /* de-serialize each entry and put it into the hash */
615289177Speter  for (i = 0; i < properties->count; ++i)
616289177Speter    {
617289177Speter      apr_size_t len = properties->keys[i+1] - properties->keys[i] - 1;
618289177Speter      svn_temp_deserializer__resolve(properties->keys,
619289177Speter                                     (void**)&properties->keys[i]);
620289177Speter
621289177Speter      deserialize_svn_string(properties->values,
622289177Speter                             (svn_string_t **)&properties->values[i]);
623289177Speter
624289177Speter      apr_hash_set(hash,
625289177Speter                   properties->keys[i], len,
626289177Speter                   properties->values[i]);
627289177Speter    }
628289177Speter
629289177Speter  /* done */
630289177Speter  *out = hash;
631289177Speter
632289177Speter  return SVN_NO_ERROR;
633289177Speter}
634289177Speter
635289177Speter/** Caching svn_fs_x__noderev_t objects. **/
636289177Speter
637289177Spetersvn_error_t *
638289177Spetersvn_fs_x__serialize_node_revision(void **buffer,
639289177Speter                                  apr_size_t *buffer_size,
640289177Speter                                  void *item,
641289177Speter                                  apr_pool_t *pool)
642289177Speter{
643289177Speter  svn_stringbuf_t *serialized;
644289177Speter  svn_fs_x__noderev_t *noderev = item;
645289177Speter
646289177Speter  /* create an (empty) serialization context with plenty of (initial)
647289177Speter   * buffer space. */
648289177Speter  svn_temp_serializer__context_t *context =
649289177Speter      svn_temp_serializer__init(NULL, 0,
650289177Speter                                1024 - SVN_TEMP_SERIALIZER__OVERHEAD,
651289177Speter                                pool);
652289177Speter
653289177Speter  /* serialize the noderev */
654362181Sdim  noderev_serialize(context, &noderev);
655289177Speter
656289177Speter  /* return serialized data */
657289177Speter  serialized = svn_temp_serializer__get(context);
658289177Speter  *buffer = serialized->data;
659289177Speter  *buffer_size = serialized->len;
660289177Speter
661289177Speter  return SVN_NO_ERROR;
662289177Speter}
663289177Speter
664289177Spetersvn_error_t *
665289177Spetersvn_fs_x__deserialize_node_revision(void **item,
666289177Speter                                    void *buffer,
667289177Speter                                    apr_size_t buffer_size,
668362181Sdim                                    apr_pool_t *result_pool)
669289177Speter{
670289177Speter  /* Copy the _full_ buffer as it also contains the sub-structures. */
671289177Speter  svn_fs_x__noderev_t *noderev = (svn_fs_x__noderev_t *)buffer;
672289177Speter
673289177Speter  /* fixup of all pointers etc. */
674362181Sdim  noderev_deserialize(noderev, &noderev);
675289177Speter
676289177Speter  /* done */
677289177Speter  *item = noderev;
678289177Speter  return SVN_NO_ERROR;
679289177Speter}
680289177Speter
681289177Speter/* Utility function that returns the directory serialized inside CONTEXT
682362181Sdim * to DATA and DATA_LEN.  If OVERPROVISION is set, allocate some extra
683362181Sdim * room for future in-place changes by svn_fs_x__replace_dir_entry. */
684289177Speterstatic svn_error_t *
685289177Speterreturn_serialized_dir_context(svn_temp_serializer__context_t *context,
686289177Speter                              void **data,
687362181Sdim                              apr_size_t *data_len,
688362181Sdim                              svn_boolean_t overprovision)
689289177Speter{
690289177Speter  svn_stringbuf_t *serialized = svn_temp_serializer__get(context);
691289177Speter
692289177Speter  *data = serialized->data;
693362181Sdim  *data_len = overprovision ? serialized->blocksize : serialized->len;
694289177Speter  ((dir_data_t *)serialized->data)->len = serialized->len;
695289177Speter
696289177Speter  return SVN_NO_ERROR;
697289177Speter}
698289177Speter
699289177Spetersvn_error_t *
700289177Spetersvn_fs_x__serialize_dir_entries(void **data,
701289177Speter                                apr_size_t *data_len,
702289177Speter                                void *in,
703289177Speter                                apr_pool_t *pool)
704289177Speter{
705362181Sdim  svn_fs_x__dir_data_t *dir = in;
706289177Speter
707289177Speter  /* serialize the dir content into a new serialization context
708289177Speter   * and return the serialized data */
709289177Speter  return return_serialized_dir_context(serialize_dir(dir, pool),
710289177Speter                                       data,
711362181Sdim                                       data_len,
712362181Sdim                                       FALSE);
713289177Speter}
714289177Speter
715289177Spetersvn_error_t *
716289177Spetersvn_fs_x__deserialize_dir_entries(void **out,
717289177Speter                                  void *data,
718289177Speter                                  apr_size_t data_len,
719362181Sdim                                  apr_pool_t *result_pool)
720289177Speter{
721289177Speter  /* Copy the _full_ buffer as it also contains the sub-structures. */
722289177Speter  dir_data_t *dir_data = (dir_data_t *)data;
723289177Speter
724289177Speter  /* reconstruct the hash from the serialized data */
725362181Sdim  *out = deserialize_dir(dir_data, dir_data, result_pool);
726289177Speter
727289177Speter  return SVN_NO_ERROR;
728289177Speter}
729289177Speter
730289177Spetersvn_error_t *
731289177Spetersvn_fs_x__get_sharded_offset(void **out,
732289177Speter                             const void *data,
733289177Speter                             apr_size_t data_len,
734289177Speter                             void *baton,
735289177Speter                             apr_pool_t *pool)
736289177Speter{
737289177Speter  const apr_off_t *manifest = data;
738289177Speter  apr_int64_t shard_pos = *(apr_int64_t *)baton;
739289177Speter
740289177Speter  *(apr_off_t *)out = manifest[shard_pos];
741289177Speter
742289177Speter  return SVN_NO_ERROR;
743289177Speter}
744289177Speter
745362181Sdimsvn_error_t *
746362181Sdimsvn_fs_x__extract_dir_filesize(void **out,
747362181Sdim                               const void *data,
748362181Sdim                               apr_size_t data_len,
749362181Sdim                               void *baton,
750362181Sdim                               apr_pool_t *pool)
751362181Sdim{
752362181Sdim  const dir_data_t *dir_data = data;
753362181Sdim
754362181Sdim  *(svn_filesize_t *)out = dir_data->txn_filesize;
755362181Sdim
756362181Sdim  return SVN_NO_ERROR;
757362181Sdim}
758362181Sdim
759289177Speter/* Utility function that returns the lowest index of the first entry in
760289177Speter * *ENTRIES that points to a dir entry with a name equal or larger than NAME.
761289177Speter * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
762289177Speter * the number of valid entries in ENTRIES.
763289177Speter */
764289177Speterstatic apr_size_t
765289177Speterfind_entry(svn_fs_x__dirent_t **entries,
766289177Speter           const char *name,
767289177Speter           apr_size_t count,
768289177Speter           svn_boolean_t *found)
769289177Speter{
770289177Speter  /* binary search for the desired entry by name */
771289177Speter  apr_size_t lower = 0;
772289177Speter  apr_size_t upper = count;
773289177Speter  apr_size_t middle;
774289177Speter
775289177Speter  for (middle = upper / 2; lower < upper; middle = (upper + lower) / 2)
776289177Speter    {
777289177Speter      const svn_fs_x__dirent_t *entry =
778289177Speter          svn_temp_deserializer__ptr(entries, (const void *const *)&entries[middle]);
779289177Speter      const char* entry_name =
780289177Speter          svn_temp_deserializer__ptr(entry, (const void *const *)&entry->name);
781289177Speter
782289177Speter      int diff = strcmp(entry_name, name);
783289177Speter      if (diff < 0)
784289177Speter        lower = middle + 1;
785289177Speter      else
786289177Speter        upper = middle;
787289177Speter    }
788289177Speter
789289177Speter  /* check whether we actually found a match */
790289177Speter  *found = FALSE;
791289177Speter  if (lower < count)
792289177Speter    {
793289177Speter      const svn_fs_x__dirent_t *entry =
794289177Speter          svn_temp_deserializer__ptr(entries, (const void *const *)&entries[lower]);
795289177Speter      const char* entry_name =
796289177Speter          svn_temp_deserializer__ptr(entry, (const void *const *)&entry->name);
797289177Speter
798289177Speter      if (strcmp(entry_name, name) == 0)
799289177Speter        *found = TRUE;
800289177Speter    }
801289177Speter
802289177Speter  return lower;
803289177Speter}
804289177Speter
805289177Speter/* Utility function that returns TRUE if entry number IDX in ENTRIES has the
806289177Speter * name NAME.
807289177Speter */
808289177Speterstatic svn_boolean_t
809289177Speterfound_entry(const svn_fs_x__dirent_t * const *entries,
810289177Speter            const char *name,
811289177Speter            apr_size_t idx)
812289177Speter{
813289177Speter  /* check whether we actually found a match */
814289177Speter  const svn_fs_x__dirent_t *entry =
815289177Speter    svn_temp_deserializer__ptr(entries, (const void *const *)&entries[idx]);
816289177Speter  const char* entry_name =
817289177Speter    svn_temp_deserializer__ptr(entry, (const void *const *)&entry->name);
818289177Speter
819289177Speter  return strcmp(entry_name, name) == 0;
820289177Speter}
821289177Speter
822289177Spetersvn_error_t *
823289177Spetersvn_fs_x__extract_dir_entry(void **out,
824289177Speter                            const void *data,
825289177Speter                            apr_size_t data_len,
826289177Speter                            void *baton,
827289177Speter                            apr_pool_t *pool)
828289177Speter{
829289177Speter  const dir_data_t *dir_data = data;
830289177Speter  svn_fs_x__ede_baton_t *b = baton;
831289177Speter  svn_boolean_t found;
832289177Speter  apr_size_t pos;
833289177Speter
834289177Speter  /* resolve the reference to the entries array */
835289177Speter  const svn_fs_x__dirent_t * const *entries =
836289177Speter    svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries);
837289177Speter
838289177Speter  /* resolve the reference to the lengths array */
839289177Speter  const apr_uint32_t *lengths =
840289177Speter    svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
841289177Speter
842362181Sdim  /* Before we return, make sure we tell the caller this data is even still
843362181Sdim     relevant. */
844362181Sdim  b->out_of_date = dir_data->txn_filesize != b->txn_filesize;
845362181Sdim
846289177Speter  /* Special case: Early out for empty directories.
847289177Speter     That simplifies tests further down the road. */
848289177Speter  *out = NULL;
849289177Speter  if (dir_data->count == 0)
850289177Speter    return SVN_NO_ERROR;
851289177Speter
852289177Speter  /* HINT _might_ be the position we hit last time.
853289177Speter     If within valid range, check whether HINT+1 is a hit. */
854289177Speter  if (   b->hint < dir_data->count - 1
855289177Speter      && found_entry(entries, b->name, b->hint + 1))
856289177Speter    {
857289177Speter      /* Got lucky. */
858289177Speter      pos = b->hint + 1;
859289177Speter      found = TRUE;
860289177Speter    }
861289177Speter  else
862289177Speter    {
863289177Speter      /* Binary search for the desired entry by name. */
864289177Speter      pos = find_entry((svn_fs_x__dirent_t **)entries, b->name,
865289177Speter                       dir_data->count, &found);
866289177Speter    }
867289177Speter
868289177Speter  /* Remember the hit index - if we FOUND the entry. */
869289177Speter  if (found)
870289177Speter    b->hint = pos;
871289177Speter
872362181Sdim  /* de-serialize that entry or return NULL, if no match has been found.
873362181Sdim   * Be sure to check that the directory contents is still up-to-date. */
874362181Sdim  if (found && !b->out_of_date)
875289177Speter    {
876289177Speter      const svn_fs_x__dirent_t *source =
877289177Speter          svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
878289177Speter
879289177Speter      /* Entries have been serialized one-by-one, each time including all
880289177Speter       * nested structures and strings. Therefore, they occupy a single
881289177Speter       * block of memory whose end-offset is either the beginning of the
882289177Speter       * next entry or the end of the buffer
883289177Speter       */
884289177Speter      apr_size_t size = lengths[pos];
885289177Speter
886289177Speter      /* copy & deserialize the entry */
887362181Sdim      svn_fs_x__dirent_t *new_entry = apr_pmemdup(pool, source, size);
888289177Speter
889289177Speter      svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name);
890289177Speter      *(svn_fs_x__dirent_t **)out = new_entry;
891289177Speter    }
892289177Speter
893289177Speter  return SVN_NO_ERROR;
894289177Speter}
895289177Speter
896289177Speter/* Utility function for svn_fs_x__replace_dir_entry that implements the
897289177Speter * modification as a simply deserialize / modify / serialize sequence.
898289177Speter */
899289177Speterstatic svn_error_t *
900289177Speterslowly_replace_dir_entry(void **data,
901289177Speter                         apr_size_t *data_len,
902289177Speter                         void *baton,
903289177Speter                         apr_pool_t *pool)
904289177Speter{
905289177Speter  replace_baton_t *replace_baton = (replace_baton_t *)baton;
906289177Speter  dir_data_t *dir_data = (dir_data_t *)*data;
907362181Sdim  svn_fs_x__dir_data_t *dir;
908289177Speter  int idx = -1;
909289177Speter  svn_fs_x__dirent_t *entry;
910362181Sdim  apr_array_header_t *entries;
911289177Speter
912289177Speter  SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir,
913289177Speter                                            *data,
914289177Speter                                            dir_data->len,
915289177Speter                                            pool));
916289177Speter
917362181Sdim  entries = dir->entries;
918362181Sdim  entry = svn_fs_x__find_dir_entry(entries, replace_baton->name, &idx);
919289177Speter
920289177Speter  /* Replacement or removal? */
921289177Speter  if (replace_baton->new_entry)
922289177Speter    {
923289177Speter      /* Replace ENTRY with / insert the NEW_ENTRY */
924289177Speter      if (entry)
925362181Sdim        APR_ARRAY_IDX(entries, idx, svn_fs_x__dirent_t *)
926289177Speter          = replace_baton->new_entry;
927289177Speter      else
928362181Sdim        SVN_ERR(svn_sort__array_insert2(entries, &replace_baton->new_entry, idx));
929289177Speter    }
930289177Speter  else
931289177Speter    {
932289177Speter      /* Remove the old ENTRY. */
933289177Speter      if (entry)
934362181Sdim        SVN_ERR(svn_sort__array_delete2(entries, idx, 1));
935289177Speter    }
936289177Speter
937289177Speter  return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool);
938289177Speter}
939289177Speter
940289177Spetersvn_error_t *
941289177Spetersvn_fs_x__replace_dir_entry(void **data,
942289177Speter                            apr_size_t *data_len,
943289177Speter                            void *baton,
944289177Speter                            apr_pool_t *pool)
945289177Speter{
946289177Speter  replace_baton_t *replace_baton = (replace_baton_t *)baton;
947289177Speter  dir_data_t *dir_data = (dir_data_t *)*data;
948289177Speter  svn_boolean_t found;
949289177Speter  svn_fs_x__dirent_t **entries;
950289177Speter  apr_uint32_t *lengths;
951289177Speter  apr_uint32_t length;
952289177Speter  apr_size_t pos;
953289177Speter
954289177Speter  svn_temp_serializer__context_t *context;
955289177Speter
956362181Sdim  /* update the cached file length info.
957362181Sdim   * Because we are writing to the cache, it is fair to assume that the
958362181Sdim   * caller made sure that the current contents is consistent with the
959362181Sdim   * previous state of the directory file. */
960362181Sdim  dir_data->txn_filesize = replace_baton->txn_filesize;
961362181Sdim
962289177Speter  /* after quite a number of operations, let's re-pack everything.
963289177Speter   * This is to limit the number of wasted space as we cannot overwrite
964289177Speter   * existing data but must always append. */
965289177Speter  if (dir_data->operations > 2 + dir_data->count / 4)
966289177Speter    return slowly_replace_dir_entry(data, data_len, baton, pool);
967289177Speter
968289177Speter  /* resolve the reference to the entries array */
969289177Speter  entries = (svn_fs_x__dirent_t **)
970289177Speter    svn_temp_deserializer__ptr((const char *)dir_data,
971289177Speter                               (const void *const *)&dir_data->entries);
972289177Speter
973289177Speter  /* resolve the reference to the lengths array */
974289177Speter  lengths = (apr_uint32_t *)
975289177Speter    svn_temp_deserializer__ptr((const char *)dir_data,
976289177Speter                               (const void *const *)&dir_data->lengths);
977289177Speter
978289177Speter  /* binary search for the desired entry by name */
979289177Speter  pos = find_entry(entries, replace_baton->name, dir_data->count, &found);
980289177Speter
981289177Speter  /* handle entry removal (if found at all) */
982289177Speter  if (replace_baton->new_entry == NULL)
983289177Speter    {
984289177Speter      if (found)
985289177Speter        {
986289177Speter          /* remove reference to the entry from the index */
987289177Speter          memmove(&entries[pos],
988289177Speter                  &entries[pos + 1],
989289177Speter                  sizeof(entries[pos]) * (dir_data->count - pos));
990289177Speter          memmove(&lengths[pos],
991289177Speter                  &lengths[pos + 1],
992289177Speter                  sizeof(lengths[pos]) * (dir_data->count - pos));
993289177Speter
994289177Speter          dir_data->count--;
995289177Speter          dir_data->over_provision++;
996289177Speter          dir_data->operations++;
997289177Speter        }
998289177Speter
999289177Speter      return SVN_NO_ERROR;
1000289177Speter    }
1001289177Speter
1002289177Speter  /* if not found, prepare to insert the new entry */
1003289177Speter  if (!found)
1004289177Speter    {
1005289177Speter      /* fallback to slow operation if there is no place left to insert an
1006289177Speter       * new entry to index. That will automatically give add some spare
1007289177Speter       * entries ("overprovision"). */
1008289177Speter      if (dir_data->over_provision == 0)
1009289177Speter        return slowly_replace_dir_entry(data, data_len, baton, pool);
1010289177Speter
1011289177Speter      /* make entries[index] available for pointing to the new entry */
1012289177Speter      memmove(&entries[pos + 1],
1013289177Speter              &entries[pos],
1014289177Speter              sizeof(entries[pos]) * (dir_data->count - pos));
1015289177Speter      memmove(&lengths[pos + 1],
1016289177Speter              &lengths[pos],
1017289177Speter              sizeof(lengths[pos]) * (dir_data->count - pos));
1018289177Speter
1019289177Speter      dir_data->count++;
1020289177Speter      dir_data->over_provision--;
1021289177Speter      dir_data->operations++;
1022289177Speter    }
1023289177Speter
1024289177Speter  /* de-serialize the new entry */
1025289177Speter  entries[pos] = replace_baton->new_entry;
1026289177Speter  context = svn_temp_serializer__init_append(dir_data,
1027289177Speter                                             entries,
1028289177Speter                                             dir_data->len,
1029289177Speter                                             *data_len,
1030289177Speter                                             pool);
1031289177Speter  serialize_dir_entry(context, &entries[pos], &length);
1032289177Speter
1033289177Speter  /* return the updated serialized data */
1034362181Sdim  SVN_ERR(return_serialized_dir_context(context, data, data_len, TRUE));
1035289177Speter
1036289177Speter  /* since the previous call may have re-allocated the buffer, the lengths
1037289177Speter   * pointer may no longer point to the entry in that buffer. Therefore,
1038289177Speter   * re-map it again and store the length value after that. */
1039289177Speter
1040289177Speter  dir_data = (dir_data_t *)*data;
1041289177Speter  lengths = (apr_uint32_t *)
1042289177Speter    svn_temp_deserializer__ptr((const char *)dir_data,
1043289177Speter                               (const void *const *)&dir_data->lengths);
1044289177Speter  lengths[pos] = length;
1045289177Speter
1046289177Speter  return SVN_NO_ERROR;
1047289177Speter}
1048289177Speter
1049362181Sdimsvn_error_t *
1050362181Sdimsvn_fs_x__reset_txn_filesize(void **data,
1051362181Sdim                             apr_size_t *data_len,
1052362181Sdim                             void *baton,
1053362181Sdim                             apr_pool_t *pool)
1054362181Sdim{
1055362181Sdim  dir_data_t *dir_data = (dir_data_t *)*data;
1056362181Sdim  dir_data->txn_filesize = SVN_INVALID_FILESIZE;
1057362181Sdim
1058362181Sdim  return SVN_NO_ERROR;
1059362181Sdim}
1060362181Sdim
1061289177Spetersvn_error_t  *
1062289177Spetersvn_fs_x__serialize_rep_header(void **data,
1063289177Speter                               apr_size_t *data_len,
1064289177Speter                               void *in,
1065289177Speter                               apr_pool_t *pool)
1066289177Speter{
1067289177Speter  *data_len = sizeof(svn_fs_x__rep_header_t);
1068362181Sdim  *data = in;
1069289177Speter
1070289177Speter  return SVN_NO_ERROR;
1071289177Speter}
1072289177Speter
1073289177Spetersvn_error_t *
1074289177Spetersvn_fs_x__deserialize_rep_header(void **out,
1075289177Speter                                 void *data,
1076289177Speter                                 apr_size_t data_len,
1077362181Sdim                                 apr_pool_t *result_pool)
1078289177Speter{
1079289177Speter  *out = data;
1080289177Speter
1081289177Speter  return SVN_NO_ERROR;
1082289177Speter}
1083289177Speter
1084289177Speter/* Utility function to serialize change CHANGE_P in the given serialization
1085289177Speter * CONTEXT.
1086289177Speter */
1087289177Speterstatic void
1088289177Speterserialize_change(svn_temp_serializer__context_t *context,
1089289177Speter                 svn_fs_x__change_t * const *change_p)
1090289177Speter{
1091289177Speter  const svn_fs_x__change_t * change = *change_p;
1092289177Speter  if (change == NULL)
1093289177Speter    return;
1094289177Speter
1095289177Speter  /* serialize the change struct itself */
1096289177Speter  svn_temp_serializer__push(context,
1097289177Speter                            (const void * const *)change_p,
1098289177Speter                            sizeof(*change));
1099289177Speter
1100289177Speter  /* serialize sub-structures */
1101289177Speter  svn_temp_serializer__add_string(context, &change->path.data);
1102289177Speter  svn_temp_serializer__add_string(context, &change->copyfrom_path);
1103289177Speter
1104289177Speter  /* return to the caller's nesting level */
1105289177Speter  svn_temp_serializer__pop(context);
1106289177Speter}
1107289177Speter
1108289177Speter/* Utility function to serialize the CHANGE_P within the given
1109289177Speter * serialization CONTEXT.
1110289177Speter */
1111289177Speterstatic void
1112289177Speterdeserialize_change(void *buffer,
1113362181Sdim                   svn_fs_x__change_t **change_p)
1114289177Speter{
1115289177Speter  svn_fs_x__change_t * change;
1116289177Speter
1117289177Speter  /* fix-up of the pointer to the struct in question */
1118289177Speter  svn_temp_deserializer__resolve(buffer, (void **)change_p);
1119289177Speter
1120289177Speter  change = *change_p;
1121289177Speter  if (change == NULL)
1122289177Speter    return;
1123289177Speter
1124289177Speter  /* fix-up of sub-structures */
1125289177Speter  svn_temp_deserializer__resolve(change, (void **)&change->path.data);
1126289177Speter  svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path);
1127289177Speter}
1128289177Speter
1129289177Spetersvn_error_t *
1130289177Spetersvn_fs_x__serialize_changes(void **data,
1131289177Speter                            apr_size_t *data_len,
1132289177Speter                            void *in,
1133289177Speter                            apr_pool_t *pool)
1134289177Speter{
1135362181Sdim  svn_fs_x__changes_list_t *changes = in;
1136289177Speter  svn_temp_serializer__context_t *context;
1137289177Speter  svn_stringbuf_t *serialized;
1138289177Speter  int i;
1139289177Speter
1140289177Speter  /* serialize it and all its elements */
1141362181Sdim  context = svn_temp_serializer__init(changes,
1142362181Sdim                                      sizeof(*changes),
1143362181Sdim                                      changes->count * 250,
1144289177Speter                                      pool);
1145289177Speter
1146289177Speter  svn_temp_serializer__push(context,
1147362181Sdim                            (const void * const *)&changes->changes,
1148362181Sdim                            changes->count * sizeof(*changes->changes));
1149289177Speter
1150362181Sdim  for (i = 0; i < changes->count; ++i)
1151362181Sdim    serialize_change(context, &changes->changes[i]);
1152289177Speter
1153289177Speter  svn_temp_serializer__pop(context);
1154289177Speter
1155289177Speter  /* return the serialized result */
1156289177Speter  serialized = svn_temp_serializer__get(context);
1157289177Speter
1158289177Speter  *data = serialized->data;
1159289177Speter  *data_len = serialized->len;
1160289177Speter
1161289177Speter  return SVN_NO_ERROR;
1162289177Speter}
1163289177Speter
1164289177Spetersvn_error_t *
1165289177Spetersvn_fs_x__deserialize_changes(void **out,
1166289177Speter                              void *data,
1167289177Speter                              apr_size_t data_len,
1168362181Sdim                              apr_pool_t *result_pool)
1169289177Speter{
1170289177Speter  int i;
1171362181Sdim  svn_fs_x__changes_list_t *changes = (svn_fs_x__changes_list_t *)data;
1172289177Speter
1173289177Speter  /* de-serialize our auxiliary data structure */
1174289177Speter  svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
1175289177Speter
1176289177Speter  /* de-serialize each entry and add it to the array */
1177289177Speter  for (i = 0; i < changes->count; ++i)
1178289177Speter    deserialize_change(changes->changes,
1179362181Sdim                       (svn_fs_x__change_t **)&changes->changes[i]);
1180289177Speter
1181289177Speter  /* done */
1182362181Sdim  *out = changes;
1183289177Speter
1184289177Speter  return SVN_NO_ERROR;
1185289177Speter}
1186