Deleted Added
full compact
temp_serializer.c (302408) temp_serializer.c (362181)
1/* temp_serializer.c: serialization functions for caching of FSX structures
2 *
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the

--- 57 unchanged lines hidden (view full) ---

66
67 /* return the last written position */
68 return key_buffer;
69}
70
71const char*
72svn_fs_x__combine_number_and_string(apr_int64_t number,
73 const char *string,
1/* temp_serializer.c: serialization functions for caching of FSX structures
2 *
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the

--- 57 unchanged lines hidden (view full) ---

66
67 /* return the last written position */
68 return key_buffer;
69}
70
71const char*
72svn_fs_x__combine_number_and_string(apr_int64_t number,
73 const char *string,
74 apr_pool_t *pool)
74 apr_pool_t *result_pool)
75{
76 apr_size_t len = strlen(string);
77
78 /* number part requires max. 10x7 bits + 1 space.
79 * Add another 1 for the terminal 0 */
75{
76 apr_size_t len = strlen(string);
77
78 /* number part requires max. 10x7 bits + 1 space.
79 * Add another 1 for the terminal 0 */
80 char *key_buffer = apr_palloc(pool, len + 12);
80 char *key_buffer = apr_palloc(result_pool, len + 12);
81 const char *key = key_buffer;
82
83 /* Prepend the number to the string and separate them by space. No other
84 * number can result in the same prefix, no other string in the same
85 * postfix nor can the boundary between them be ambiguous. */
86 key_buffer = encode_number(number, key_buffer);
87 *++key_buffer = ' ';
88 memcpy(++key_buffer, string, len+1);

--- 26 unchanged lines hidden (view full) ---

115
116 /* back to the caller's nesting level */
117 svn_temp_serializer__pop(context);
118}
119
120/* Utility function to deserialize the STRING inside the BUFFER.
121 */
122static void
81 const char *key = key_buffer;
82
83 /* Prepend the number to the string and separate them by space. No other
84 * number can result in the same prefix, no other string in the same
85 * postfix nor can the boundary between them be ambiguous. */
86 key_buffer = encode_number(number, key_buffer);
87 *++key_buffer = ' ';
88 memcpy(++key_buffer, string, len+1);

--- 26 unchanged lines hidden (view full) ---

115
116 /* back to the caller's nesting level */
117 svn_temp_serializer__pop(context);
118}
119
120/* Utility function to deserialize the STRING inside the BUFFER.
121 */
122static void
123deserialize_svn_string(void *buffer, svn_string_t **string)
123deserialize_svn_string(const void *buffer, svn_string_t **string)
124{
125 svn_temp_deserializer__resolve(buffer, (void **)string);
126 if (*string == NULL)
127 return;
128
129 svn_temp_deserializer__resolve(*string, (void **)&(*string)->data);
130}
131

--- 36 unchanged lines hidden (view full) ---

168
169 /* back to the caller's nesting level */
170 svn_temp_serializer__pop(context);
171}
172
173void
174svn_fs_x__deserialize_apr_array(void *buffer,
175 apr_array_header_t **array,
124{
125 svn_temp_deserializer__resolve(buffer, (void **)string);
126 if (*string == NULL)
127 return;
128
129 svn_temp_deserializer__resolve(*string, (void **)&(*string)->data);
130}
131

--- 36 unchanged lines hidden (view full) ---

168
169 /* back to the caller's nesting level */
170 svn_temp_serializer__pop(context);
171}
172
173void
174svn_fs_x__deserialize_apr_array(void *buffer,
175 apr_array_header_t **array,
176 apr_pool_t *pool)
176 apr_pool_t *result_pool)
177{
178 svn_temp_deserializer__resolve(buffer, (void **)array);
179 if (*array == NULL)
180 return;
181
182 svn_temp_deserializer__resolve(*array, (void **)&(*array)->elts);
177{
178 svn_temp_deserializer__resolve(buffer, (void **)array);
179 if (*array == NULL)
180 return;
181
182 svn_temp_deserializer__resolve(*array, (void **)&(*array)->elts);
183 (*array)->pool = pool;
183 (*array)->pool = result_pool;
184}
185
186/* auxilliary structure representing the content of a directory array */
187typedef struct dir_data_t
188{
189 /* number of entries in the directory
190 * (it's int because the directory is an APR array) */
191 int count;
192
184}
185
186/* auxilliary structure representing the content of a directory array */
187typedef struct dir_data_t
188{
189 /* number of entries in the directory
190 * (it's int because the directory is an APR array) */
191 int count;
192
193 /** Current length of the in-txn in-disk representation of the directory.
194 * SVN_INVALID_FILESIZE if unknown (i.e. committed data). */
195 svn_filesize_t txn_filesize;
196
193 /* number of unused dir entry buckets in the index */
194 apr_size_t over_provision;
195
196 /* internal modifying operations counter
197 * (used to repack data once in a while) */
198 apr_size_t operations;
199
200 /* size of the serialization buffer actually used.

--- 18 unchanged lines hidden (view full) ---

219 svn_fs_x__dirent_t **entry_p,
220 apr_uint32_t *length)
221{
222 svn_fs_x__dirent_t *entry = *entry_p;
223 apr_size_t initial_length = svn_temp_serializer__get_length(context);
224
225 svn_temp_serializer__push(context,
226 (const void * const *)entry_p,
197 /* number of unused dir entry buckets in the index */
198 apr_size_t over_provision;
199
200 /* internal modifying operations counter
201 * (used to repack data once in a while) */
202 apr_size_t operations;
203
204 /* size of the serialization buffer actually used.

--- 18 unchanged lines hidden (view full) ---

223 svn_fs_x__dirent_t **entry_p,
224 apr_uint32_t *length)
225{
226 svn_fs_x__dirent_t *entry = *entry_p;
227 apr_size_t initial_length = svn_temp_serializer__get_length(context);
228
229 svn_temp_serializer__push(context,
230 (const void * const *)entry_p,
227 sizeof(svn_fs_x__dirent_t));
231 sizeof(**entry_p));
228
229 svn_temp_serializer__add_string(context, &entry->name);
230
231 *length = (apr_uint32_t)( svn_temp_serializer__get_length(context)
232 - APR_ALIGN_DEFAULT(initial_length));
233
234 svn_temp_serializer__pop(context);
235}
236
232
233 svn_temp_serializer__add_string(context, &entry->name);
234
235 *length = (apr_uint32_t)( svn_temp_serializer__get_length(context)
236 - APR_ALIGN_DEFAULT(initial_length));
237
238 svn_temp_serializer__pop(context);
239}
240
237/* Utility function to serialize the ENTRIES into a new serialization
241/* Utility function to serialize the DIR into a new serialization
238 * context to be returned.
239 *
240 * Temporary allocation will be made form SCRATCH_POOL.
241 */
242static svn_temp_serializer__context_t *
242 * context to be returned.
243 *
244 * Temporary allocation will be made form SCRATCH_POOL.
245 */
246static svn_temp_serializer__context_t *
243serialize_dir(apr_array_header_t *entries,
247serialize_dir(svn_fs_x__dir_data_t *dir,
244 apr_pool_t *scratch_pool)
245{
246 dir_data_t dir_data;
247 int i = 0;
248 svn_temp_serializer__context_t *context;
248 apr_pool_t *scratch_pool)
249{
250 dir_data_t dir_data;
251 int i = 0;
252 svn_temp_serializer__context_t *context;
253 apr_array_header_t *entries = dir->entries;
249
250 /* calculate sizes */
251 int count = entries->nelts;
252 apr_size_t over_provision = 2 + count / 4;
253 apr_size_t entries_len = (count + over_provision)
254 * sizeof(svn_fs_x__dirent_t*);
255 apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
256
254
255 /* calculate sizes */
256 int count = entries->nelts;
257 apr_size_t over_provision = 2 + count / 4;
258 apr_size_t entries_len = (count + over_provision)
259 * sizeof(svn_fs_x__dirent_t*);
260 apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
261
262 /* Estimate the size of a directory entry + its name. */
263 enum { ENTRY_SIZE = sizeof(svn_fs_x__dirent_t) + 32 };
264
257 /* copy the hash entries to an auxiliary struct of known layout */
258 dir_data.count = count;
265 /* copy the hash entries to an auxiliary struct of known layout */
266 dir_data.count = count;
267 dir_data.txn_filesize = dir->txn_filesize;
259 dir_data.over_provision = over_provision;
260 dir_data.operations = 0;
261 dir_data.entries = apr_palloc(scratch_pool, entries_len);
262 dir_data.lengths = apr_palloc(scratch_pool, lengths_len);
263
264 for (i = 0; i < count; ++i)
265 dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_x__dirent_t *);
266
267 /* Serialize that aux. structure into a new one. Also, provide a good
268 * estimate for the size of the buffer that we will need. */
269 context = svn_temp_serializer__init(&dir_data,
270 sizeof(dir_data),
268 dir_data.over_provision = over_provision;
269 dir_data.operations = 0;
270 dir_data.entries = apr_palloc(scratch_pool, entries_len);
271 dir_data.lengths = apr_palloc(scratch_pool, lengths_len);
272
273 for (i = 0; i < count; ++i)
274 dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_x__dirent_t *);
275
276 /* Serialize that aux. structure into a new one. Also, provide a good
277 * estimate for the size of the buffer that we will need. */
278 context = svn_temp_serializer__init(&dir_data,
279 sizeof(dir_data),
271 50 + count * 200 + entries_len,
280 50 + count * ENTRY_SIZE
281 + entries_len + lengths_len,
272 scratch_pool);
273
274 /* serialize entries references */
275 svn_temp_serializer__push(context,
276 (const void * const *)&dir_data.entries,
277 entries_len);
278
279 /* serialize the individual entries and their sub-structures */

--- 7 unchanged lines hidden (view full) ---

287 /* serialize entries references */
288 svn_temp_serializer__push(context,
289 (const void * const *)&dir_data.lengths,
290 lengths_len);
291
292 return context;
293}
294
282 scratch_pool);
283
284 /* serialize entries references */
285 svn_temp_serializer__push(context,
286 (const void * const *)&dir_data.entries,
287 entries_len);
288
289 /* serialize the individual entries and their sub-structures */

--- 7 unchanged lines hidden (view full) ---

297 /* serialize entries references */
298 svn_temp_serializer__push(context,
299 (const void * const *)&dir_data.lengths,
300 lengths_len);
301
302 return context;
303}
304
295/* Utility function to reconstruct a dir entries array from serialized data
296 * in BUFFER and DIR_DATA. Allocation will be made form POOL.
305/* Utility function to reconstruct a dir entries struct from serialized data
306 * in BUFFER and DIR_DATA. Allocation will be made form RESULT_POOL.
297 */
307 */
298static apr_array_header_t *
299deserialize_dir(void *buffer, dir_data_t *dir_data, apr_pool_t *pool)
308static svn_fs_x__dir_data_t *
309deserialize_dir(void *buffer,
310 dir_data_t *dir_data,
311 apr_pool_t *result_pool)
300{
312{
301 apr_array_header_t *result
302 = apr_array_make(pool, dir_data->count, sizeof(svn_fs_x__dirent_t *));
313 svn_fs_x__dir_data_t *result;
303 apr_size_t i;
304 apr_size_t count;
305 svn_fs_x__dirent_t *entry;
306 svn_fs_x__dirent_t **entries;
307
314 apr_size_t i;
315 apr_size_t count;
316 svn_fs_x__dirent_t *entry;
317 svn_fs_x__dirent_t **entries;
318
319 /* Construct empty directory object. */
320 result = apr_pcalloc(result_pool, sizeof(*result));
321 result->entries
322 = apr_array_make(result_pool, dir_data->count,
323 sizeof(svn_fs_x__dirent_t *));
324 result->txn_filesize = dir_data->txn_filesize;
325
308 /* resolve the reference to the entries array */
309 svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
310 entries = dir_data->entries;
311
326 /* resolve the reference to the entries array */
327 svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
328 entries = dir_data->entries;
329
312 /* fixup the references within each entry and add it to the hash */
330 /* fixup the references within each entry and add it to the RESULT */
313 for (i = 0, count = dir_data->count; i < count; ++i)
314 {
315 svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
316 entry = dir_data->entries[i];
317
318 /* pointer fixup */
319 svn_temp_deserializer__resolve(entry, (void **)&entry->name);
320
321 /* add the entry to the hash */
331 for (i = 0, count = dir_data->count; i < count; ++i)
332 {
333 svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
334 entry = dir_data->entries[i];
335
336 /* pointer fixup */
337 svn_temp_deserializer__resolve(entry, (void **)&entry->name);
338
339 /* add the entry to the hash */
322 APR_ARRAY_PUSH(result, svn_fs_x__dirent_t *) = entry;
340 APR_ARRAY_PUSH(result->entries, svn_fs_x__dirent_t *) = entry;
323 }
324
325 /* return the now complete hash */
326 return result;
327}
328
341 }
342
343 /* return the now complete hash */
344 return result;
345}
346
329void
330svn_fs_x__noderev_serialize(svn_temp_serializer__context_t *context,
331 svn_fs_x__noderev_t * const *noderev_p)
347/**
348 * Serialize a NODEREV_P within the serialization CONTEXT.
349 */
350static void
351noderev_serialize(svn_temp_serializer__context_t *context,
352 svn_fs_x__noderev_t * const *noderev_p)
332{
333 const svn_fs_x__noderev_t *noderev = *noderev_p;
334 if (noderev == NULL)
335 return;
336
337 /* serialize the representation struct itself */
338 svn_temp_serializer__push(context,
339 (const void * const *)noderev_p,

--- 6 unchanged lines hidden (view full) ---

346 svn_temp_serializer__add_string(context, &noderev->copyfrom_path);
347 svn_temp_serializer__add_string(context, &noderev->copyroot_path);
348 svn_temp_serializer__add_string(context, &noderev->created_path);
349
350 /* return to the caller's nesting level */
351 svn_temp_serializer__pop(context);
352}
353
353{
354 const svn_fs_x__noderev_t *noderev = *noderev_p;
355 if (noderev == NULL)
356 return;
357
358 /* serialize the representation struct itself */
359 svn_temp_serializer__push(context,
360 (const void * const *)noderev_p,

--- 6 unchanged lines hidden (view full) ---

367 svn_temp_serializer__add_string(context, &noderev->copyfrom_path);
368 svn_temp_serializer__add_string(context, &noderev->copyroot_path);
369 svn_temp_serializer__add_string(context, &noderev->created_path);
370
371 /* return to the caller's nesting level */
372 svn_temp_serializer__pop(context);
373}
374
354
355void
356svn_fs_x__noderev_deserialize(void *buffer,
357 svn_fs_x__noderev_t **noderev_p,
358 apr_pool_t *pool)
375/**
376 * Deserialize a NODEREV_P within the BUFFER and associate it with.
377 */
378static void
379noderev_deserialize(void *buffer,
380 svn_fs_x__noderev_t **noderev_p)
359{
360 svn_fs_x__noderev_t *noderev;
361
362 /* fixup the reference to the representation itself,
363 * if this is part of a parent structure. */
364 if (buffer != *noderev_p)
365 svn_temp_deserializer__resolve(buffer, (void **)noderev_p);
366

--- 79 unchanged lines hidden (view full) ---

446
447 return SVN_NO_ERROR;
448}
449
450svn_error_t *
451svn_fs_x__deserialize_txdelta_window(void **item,
452 void *buffer,
453 apr_size_t buffer_size,
381{
382 svn_fs_x__noderev_t *noderev;
383
384 /* fixup the reference to the representation itself,
385 * if this is part of a parent structure. */
386 if (buffer != *noderev_p)
387 svn_temp_deserializer__resolve(buffer, (void **)noderev_p);
388

--- 79 unchanged lines hidden (view full) ---

468
469 return SVN_NO_ERROR;
470}
471
472svn_error_t *
473svn_fs_x__deserialize_txdelta_window(void **item,
474 void *buffer,
475 apr_size_t buffer_size,
454 apr_pool_t *pool)
476 apr_pool_t *result_pool)
455{
456 svn_txdelta_window_t *window;
457
458 /* Copy the _full_ buffer as it also contains the sub-structures. */
459 svn_fs_x__txdelta_cached_window_t *window_info =
460 (svn_fs_x__txdelta_cached_window_t *)buffer;
461
462 /* pointer reference fixup */

--- 6 unchanged lines hidden (view full) ---

469 deserialize_svn_string(window, (svn_string_t**)&window->new_data);
470
471 /* done */
472 *item = window_info;
473
474 return SVN_NO_ERROR;
475}
476
477{
478 svn_txdelta_window_t *window;
479
480 /* Copy the _full_ buffer as it also contains the sub-structures. */
481 svn_fs_x__txdelta_cached_window_t *window_info =
482 (svn_fs_x__txdelta_cached_window_t *)buffer;
483
484 /* pointer reference fixup */

--- 6 unchanged lines hidden (view full) ---

491 deserialize_svn_string(window, (svn_string_t**)&window->new_data);
492
493 /* done */
494 *item = window_info;
495
496 return SVN_NO_ERROR;
497}
498
477svn_error_t *
478svn_fs_x__serialize_manifest(void **data,
479 apr_size_t *data_len,
480 void *in,
481 apr_pool_t *pool)
482{
483 apr_array_header_t *manifest = in;
484
485 *data_len = sizeof(apr_off_t) *manifest->nelts;
486 *data = apr_palloc(pool, *data_len);
487 memcpy(*data, manifest->elts, *data_len);
488
489 return SVN_NO_ERROR;
490}
491
492svn_error_t *
493svn_fs_x__deserialize_manifest(void **out,
494 void *data,
495 apr_size_t data_len,
496 apr_pool_t *pool)
497{
498 apr_array_header_t *manifest = apr_array_make(pool, 1, sizeof(apr_off_t));
499
500 manifest->nelts = (int) (data_len / sizeof(apr_off_t));
501 manifest->nalloc = (int) (data_len / sizeof(apr_off_t));
502 manifest->elts = (char*)data;
503
504 *out = manifest;
505
506 return SVN_NO_ERROR;
507}
508
509/* Auxiliary structure representing the content of a properties hash.
510 This structure is much easier to (de-)serialize than an apr_hash.
511 */
512typedef struct properties_data_t
513{
514 /* number of entries in the hash */
515 apr_size_t count;
516

--- 57 unchanged lines hidden (view full) ---

574 svn_temp_serializer__context_t *context;
575 apr_hash_index_t *hi;
576 svn_stringbuf_t *serialized;
577 apr_size_t i;
578
579 /* create our auxiliary data structure */
580 properties.count = apr_hash_count(hash);
581 properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
499/* Auxiliary structure representing the content of a properties hash.
500 This structure is much easier to (de-)serialize than an apr_hash.
501 */
502typedef struct properties_data_t
503{
504 /* number of entries in the hash */
505 apr_size_t count;
506

--- 57 unchanged lines hidden (view full) ---

564 svn_temp_serializer__context_t *context;
565 apr_hash_index_t *hi;
566 svn_stringbuf_t *serialized;
567 apr_size_t i;
568
569 /* create our auxiliary data structure */
570 properties.count = apr_hash_count(hash);
571 properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
582 properties.values = apr_palloc(pool, sizeof(const char*) * properties.count);
572 properties.values = apr_palloc(pool, sizeof(const svn_string_t *) * properties.count);
583
584 /* populate it with the hash entries */
585 for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i)
586 {
587 properties.keys[i] = apr_hash_this_key(hi);
588 properties.values[i] = apr_hash_this_val(hi);
589 }
590

--- 15 unchanged lines hidden (view full) ---

606
607 return SVN_NO_ERROR;
608}
609
610svn_error_t *
611svn_fs_x__deserialize_properties(void **out,
612 void *data,
613 apr_size_t data_len,
573
574 /* populate it with the hash entries */
575 for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i)
576 {
577 properties.keys[i] = apr_hash_this_key(hi);
578 properties.values[i] = apr_hash_this_val(hi);
579 }
580

--- 15 unchanged lines hidden (view full) ---

596
597 return SVN_NO_ERROR;
598}
599
600svn_error_t *
601svn_fs_x__deserialize_properties(void **out,
602 void *data,
603 apr_size_t data_len,
614 apr_pool_t *pool)
604 apr_pool_t *result_pool)
615{
605{
616 apr_hash_t *hash = svn_hash__make(pool);
606 apr_hash_t *hash = svn_hash__make(result_pool);
617 properties_data_t *properties = (properties_data_t *)data;
618 size_t i;
619
620 /* de-serialize our auxiliary data structure */
621 svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
622 svn_temp_deserializer__resolve(properties, (void**)&properties->values);
623
624 /* de-serialize each entry and put it into the hash */

--- 31 unchanged lines hidden (view full) ---

656 /* create an (empty) serialization context with plenty of (initial)
657 * buffer space. */
658 svn_temp_serializer__context_t *context =
659 svn_temp_serializer__init(NULL, 0,
660 1024 - SVN_TEMP_SERIALIZER__OVERHEAD,
661 pool);
662
663 /* serialize the noderev */
607 properties_data_t *properties = (properties_data_t *)data;
608 size_t i;
609
610 /* de-serialize our auxiliary data structure */
611 svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
612 svn_temp_deserializer__resolve(properties, (void**)&properties->values);
613
614 /* de-serialize each entry and put it into the hash */

--- 31 unchanged lines hidden (view full) ---

646 /* create an (empty) serialization context with plenty of (initial)
647 * buffer space. */
648 svn_temp_serializer__context_t *context =
649 svn_temp_serializer__init(NULL, 0,
650 1024 - SVN_TEMP_SERIALIZER__OVERHEAD,
651 pool);
652
653 /* serialize the noderev */
664 svn_fs_x__noderev_serialize(context, &noderev);
654 noderev_serialize(context, &noderev);
665
666 /* return serialized data */
667 serialized = svn_temp_serializer__get(context);
668 *buffer = serialized->data;
669 *buffer_size = serialized->len;
670
671 return SVN_NO_ERROR;
672}
673
674svn_error_t *
675svn_fs_x__deserialize_node_revision(void **item,
676 void *buffer,
677 apr_size_t buffer_size,
655
656 /* return serialized data */
657 serialized = svn_temp_serializer__get(context);
658 *buffer = serialized->data;
659 *buffer_size = serialized->len;
660
661 return SVN_NO_ERROR;
662}
663
664svn_error_t *
665svn_fs_x__deserialize_node_revision(void **item,
666 void *buffer,
667 apr_size_t buffer_size,
678 apr_pool_t *pool)
668 apr_pool_t *result_pool)
679{
680 /* Copy the _full_ buffer as it also contains the sub-structures. */
681 svn_fs_x__noderev_t *noderev = (svn_fs_x__noderev_t *)buffer;
682
683 /* fixup of all pointers etc. */
669{
670 /* Copy the _full_ buffer as it also contains the sub-structures. */
671 svn_fs_x__noderev_t *noderev = (svn_fs_x__noderev_t *)buffer;
672
673 /* fixup of all pointers etc. */
684 svn_fs_x__noderev_deserialize(noderev, &noderev, pool);
674 noderev_deserialize(noderev, &noderev);
685
686 /* done */
687 *item = noderev;
688 return SVN_NO_ERROR;
689}
690
691/* Utility function that returns the directory serialized inside CONTEXT
675
676 /* done */
677 *item = noderev;
678 return SVN_NO_ERROR;
679}
680
681/* Utility function that returns the directory serialized inside CONTEXT
692 * to DATA and DATA_LEN. */
682 * to DATA and DATA_LEN. If OVERPROVISION is set, allocate some extra
683 * room for future in-place changes by svn_fs_x__replace_dir_entry. */
693static svn_error_t *
694return_serialized_dir_context(svn_temp_serializer__context_t *context,
695 void **data,
684static svn_error_t *
685return_serialized_dir_context(svn_temp_serializer__context_t *context,
686 void **data,
696 apr_size_t *data_len)
687 apr_size_t *data_len,
688 svn_boolean_t overprovision)
697{
698 svn_stringbuf_t *serialized = svn_temp_serializer__get(context);
699
700 *data = serialized->data;
689{
690 svn_stringbuf_t *serialized = svn_temp_serializer__get(context);
691
692 *data = serialized->data;
701 *data_len = serialized->blocksize;
693 *data_len = overprovision ? serialized->blocksize : serialized->len;
702 ((dir_data_t *)serialized->data)->len = serialized->len;
703
704 return SVN_NO_ERROR;
705}
706
707svn_error_t *
708svn_fs_x__serialize_dir_entries(void **data,
709 apr_size_t *data_len,
710 void *in,
711 apr_pool_t *pool)
712{
694 ((dir_data_t *)serialized->data)->len = serialized->len;
695
696 return SVN_NO_ERROR;
697}
698
699svn_error_t *
700svn_fs_x__serialize_dir_entries(void **data,
701 apr_size_t *data_len,
702 void *in,
703 apr_pool_t *pool)
704{
713 apr_array_header_t *dir = in;
705 svn_fs_x__dir_data_t *dir = in;
714
715 /* serialize the dir content into a new serialization context
716 * and return the serialized data */
717 return return_serialized_dir_context(serialize_dir(dir, pool),
718 data,
706
707 /* serialize the dir content into a new serialization context
708 * and return the serialized data */
709 return return_serialized_dir_context(serialize_dir(dir, pool),
710 data,
719 data_len);
711 data_len,
712 FALSE);
720}
721
722svn_error_t *
723svn_fs_x__deserialize_dir_entries(void **out,
724 void *data,
725 apr_size_t data_len,
713}
714
715svn_error_t *
716svn_fs_x__deserialize_dir_entries(void **out,
717 void *data,
718 apr_size_t data_len,
726 apr_pool_t *pool)
719 apr_pool_t *result_pool)
727{
728 /* Copy the _full_ buffer as it also contains the sub-structures. */
729 dir_data_t *dir_data = (dir_data_t *)data;
730
731 /* reconstruct the hash from the serialized data */
720{
721 /* Copy the _full_ buffer as it also contains the sub-structures. */
722 dir_data_t *dir_data = (dir_data_t *)data;
723
724 /* reconstruct the hash from the serialized data */
732 *out = deserialize_dir(dir_data, dir_data, pool);
725 *out = deserialize_dir(dir_data, dir_data, result_pool);
733
734 return SVN_NO_ERROR;
735}
736
737svn_error_t *
738svn_fs_x__get_sharded_offset(void **out,
739 const void *data,
740 apr_size_t data_len,
741 void *baton,
742 apr_pool_t *pool)
743{
744 const apr_off_t *manifest = data;
745 apr_int64_t shard_pos = *(apr_int64_t *)baton;
746
747 *(apr_off_t *)out = manifest[shard_pos];
748
749 return SVN_NO_ERROR;
750}
751
726
727 return SVN_NO_ERROR;
728}
729
730svn_error_t *
731svn_fs_x__get_sharded_offset(void **out,
732 const void *data,
733 apr_size_t data_len,
734 void *baton,
735 apr_pool_t *pool)
736{
737 const apr_off_t *manifest = data;
738 apr_int64_t shard_pos = *(apr_int64_t *)baton;
739
740 *(apr_off_t *)out = manifest[shard_pos];
741
742 return SVN_NO_ERROR;
743}
744
745svn_error_t *
746svn_fs_x__extract_dir_filesize(void **out,
747 const void *data,
748 apr_size_t data_len,
749 void *baton,
750 apr_pool_t *pool)
751{
752 const dir_data_t *dir_data = data;
753
754 *(svn_filesize_t *)out = dir_data->txn_filesize;
755
756 return SVN_NO_ERROR;
757}
758
752/* Utility function that returns the lowest index of the first entry in
753 * *ENTRIES that points to a dir entry with a name equal or larger than NAME.
754 * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
755 * the number of valid entries in ENTRIES.
756 */
757static apr_size_t
758find_entry(svn_fs_x__dirent_t **entries,
759 const char *name,

--- 67 unchanged lines hidden (view full) ---

827 /* resolve the reference to the entries array */
828 const svn_fs_x__dirent_t * const *entries =
829 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries);
830
831 /* resolve the reference to the lengths array */
832 const apr_uint32_t *lengths =
833 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
834
759/* Utility function that returns the lowest index of the first entry in
760 * *ENTRIES that points to a dir entry with a name equal or larger than NAME.
761 * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
762 * the number of valid entries in ENTRIES.
763 */
764static apr_size_t
765find_entry(svn_fs_x__dirent_t **entries,
766 const char *name,

--- 67 unchanged lines hidden (view full) ---

834 /* resolve the reference to the entries array */
835 const svn_fs_x__dirent_t * const *entries =
836 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries);
837
838 /* resolve the reference to the lengths array */
839 const apr_uint32_t *lengths =
840 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
841
842 /* Before we return, make sure we tell the caller this data is even still
843 relevant. */
844 b->out_of_date = dir_data->txn_filesize != b->txn_filesize;
845
835 /* Special case: Early out for empty directories.
836 That simplifies tests further down the road. */
837 *out = NULL;
838 if (dir_data->count == 0)
839 return SVN_NO_ERROR;
840
841 /* HINT _might_ be the position we hit last time.
842 If within valid range, check whether HINT+1 is a hit. */

--- 10 unchanged lines hidden (view full) ---

853 pos = find_entry((svn_fs_x__dirent_t **)entries, b->name,
854 dir_data->count, &found);
855 }
856
857 /* Remember the hit index - if we FOUND the entry. */
858 if (found)
859 b->hint = pos;
860
846 /* Special case: Early out for empty directories.
847 That simplifies tests further down the road. */
848 *out = NULL;
849 if (dir_data->count == 0)
850 return SVN_NO_ERROR;
851
852 /* HINT _might_ be the position we hit last time.
853 If within valid range, check whether HINT+1 is a hit. */

--- 10 unchanged lines hidden (view full) ---

864 pos = find_entry((svn_fs_x__dirent_t **)entries, b->name,
865 dir_data->count, &found);
866 }
867
868 /* Remember the hit index - if we FOUND the entry. */
869 if (found)
870 b->hint = pos;
871
861 /* de-serialize that entry or return NULL, if no match has been found */
862 if (found)
872 /* de-serialize that entry or return NULL, if no match has been found.
873 * Be sure to check that the directory contents is still up-to-date. */
874 if (found && !b->out_of_date)
863 {
864 const svn_fs_x__dirent_t *source =
865 svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
866
867 /* Entries have been serialized one-by-one, each time including all
868 * nested structures and strings. Therefore, they occupy a single
869 * block of memory whose end-offset is either the beginning of the
870 * next entry or the end of the buffer
871 */
872 apr_size_t size = lengths[pos];
873
874 /* copy & deserialize the entry */
875 {
876 const svn_fs_x__dirent_t *source =
877 svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
878
879 /* Entries have been serialized one-by-one, each time including all
880 * nested structures and strings. Therefore, they occupy a single
881 * block of memory whose end-offset is either the beginning of the
882 * next entry or the end of the buffer
883 */
884 apr_size_t size = lengths[pos];
885
886 /* copy & deserialize the entry */
875 svn_fs_x__dirent_t *new_entry = apr_palloc(pool, size);
876 memcpy(new_entry, source, size);
887 svn_fs_x__dirent_t *new_entry = apr_pmemdup(pool, source, size);
877
878 svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name);
879 *(svn_fs_x__dirent_t **)out = new_entry;
880 }
881
882 return SVN_NO_ERROR;
883}
884
885/* Utility function for svn_fs_x__replace_dir_entry that implements the
886 * modification as a simply deserialize / modify / serialize sequence.
887 */
888static svn_error_t *
889slowly_replace_dir_entry(void **data,
890 apr_size_t *data_len,
891 void *baton,
892 apr_pool_t *pool)
893{
894 replace_baton_t *replace_baton = (replace_baton_t *)baton;
895 dir_data_t *dir_data = (dir_data_t *)*data;
888
889 svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name);
890 *(svn_fs_x__dirent_t **)out = new_entry;
891 }
892
893 return SVN_NO_ERROR;
894}
895
896/* Utility function for svn_fs_x__replace_dir_entry that implements the
897 * modification as a simply deserialize / modify / serialize sequence.
898 */
899static svn_error_t *
900slowly_replace_dir_entry(void **data,
901 apr_size_t *data_len,
902 void *baton,
903 apr_pool_t *pool)
904{
905 replace_baton_t *replace_baton = (replace_baton_t *)baton;
906 dir_data_t *dir_data = (dir_data_t *)*data;
896 apr_array_header_t *dir;
907 svn_fs_x__dir_data_t *dir;
897 int idx = -1;
898 svn_fs_x__dirent_t *entry;
908 int idx = -1;
909 svn_fs_x__dirent_t *entry;
910 apr_array_header_t *entries;
899
900 SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir,
901 *data,
902 dir_data->len,
903 pool));
904
911
912 SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir,
913 *data,
914 dir_data->len,
915 pool));
916
905 entry = svn_fs_x__find_dir_entry(dir, replace_baton->name, &idx);
917 entries = dir->entries;
918 entry = svn_fs_x__find_dir_entry(entries, replace_baton->name, &idx);
906
907 /* Replacement or removal? */
908 if (replace_baton->new_entry)
909 {
910 /* Replace ENTRY with / insert the NEW_ENTRY */
911 if (entry)
919
920 /* Replacement or removal? */
921 if (replace_baton->new_entry)
922 {
923 /* Replace ENTRY with / insert the NEW_ENTRY */
924 if (entry)
912 APR_ARRAY_IDX(dir, idx, svn_fs_x__dirent_t *)
925 APR_ARRAY_IDX(entries, idx, svn_fs_x__dirent_t *)
913 = replace_baton->new_entry;
914 else
926 = replace_baton->new_entry;
927 else
915 svn_sort__array_insert(dir, &replace_baton->new_entry, idx);
928 SVN_ERR(svn_sort__array_insert2(entries, &replace_baton->new_entry, idx));
916 }
917 else
918 {
919 /* Remove the old ENTRY. */
920 if (entry)
929 }
930 else
931 {
932 /* Remove the old ENTRY. */
933 if (entry)
921 svn_sort__array_delete(dir, idx, 1);
934 SVN_ERR(svn_sort__array_delete2(entries, idx, 1));
922 }
923
924 return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool);
925}
926
927svn_error_t *
928svn_fs_x__replace_dir_entry(void **data,
929 apr_size_t *data_len,

--- 5 unchanged lines hidden (view full) ---

935 svn_boolean_t found;
936 svn_fs_x__dirent_t **entries;
937 apr_uint32_t *lengths;
938 apr_uint32_t length;
939 apr_size_t pos;
940
941 svn_temp_serializer__context_t *context;
942
935 }
936
937 return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool);
938}
939
940svn_error_t *
941svn_fs_x__replace_dir_entry(void **data,
942 apr_size_t *data_len,

--- 5 unchanged lines hidden (view full) ---

948 svn_boolean_t found;
949 svn_fs_x__dirent_t **entries;
950 apr_uint32_t *lengths;
951 apr_uint32_t length;
952 apr_size_t pos;
953
954 svn_temp_serializer__context_t *context;
955
956 /* update the cached file length info.
957 * Because we are writing to the cache, it is fair to assume that the
958 * caller made sure that the current contents is consistent with the
959 * previous state of the directory file. */
960 dir_data->txn_filesize = replace_baton->txn_filesize;
961
943 /* after quite a number of operations, let's re-pack everything.
944 * This is to limit the number of wasted space as we cannot overwrite
945 * existing data but must always append. */
946 if (dir_data->operations > 2 + dir_data->count / 4)
947 return slowly_replace_dir_entry(data, data_len, baton, pool);
948
949 /* resolve the reference to the entries array */
950 entries = (svn_fs_x__dirent_t **)

--- 56 unchanged lines hidden (view full) ---

1007 context = svn_temp_serializer__init_append(dir_data,
1008 entries,
1009 dir_data->len,
1010 *data_len,
1011 pool);
1012 serialize_dir_entry(context, &entries[pos], &length);
1013
1014 /* return the updated serialized data */
962 /* after quite a number of operations, let's re-pack everything.
963 * This is to limit the number of wasted space as we cannot overwrite
964 * existing data but must always append. */
965 if (dir_data->operations > 2 + dir_data->count / 4)
966 return slowly_replace_dir_entry(data, data_len, baton, pool);
967
968 /* resolve the reference to the entries array */
969 entries = (svn_fs_x__dirent_t **)

--- 56 unchanged lines hidden (view full) ---

1026 context = svn_temp_serializer__init_append(dir_data,
1027 entries,
1028 dir_data->len,
1029 *data_len,
1030 pool);
1031 serialize_dir_entry(context, &entries[pos], &length);
1032
1033 /* return the updated serialized data */
1015 SVN_ERR (return_serialized_dir_context(context,
1016 data,
1017 data_len));
1034 SVN_ERR(return_serialized_dir_context(context, data, data_len, TRUE));
1018
1019 /* since the previous call may have re-allocated the buffer, the lengths
1020 * pointer may no longer point to the entry in that buffer. Therefore,
1021 * re-map it again and store the length value after that. */
1022
1023 dir_data = (dir_data_t *)*data;
1024 lengths = (apr_uint32_t *)
1025 svn_temp_deserializer__ptr((const char *)dir_data,
1026 (const void *const *)&dir_data->lengths);
1027 lengths[pos] = length;
1028
1029 return SVN_NO_ERROR;
1030}
1031
1035
1036 /* since the previous call may have re-allocated the buffer, the lengths
1037 * pointer may no longer point to the entry in that buffer. Therefore,
1038 * re-map it again and store the length value after that. */
1039
1040 dir_data = (dir_data_t *)*data;
1041 lengths = (apr_uint32_t *)
1042 svn_temp_deserializer__ptr((const char *)dir_data,
1043 (const void *const *)&dir_data->lengths);
1044 lengths[pos] = length;
1045
1046 return SVN_NO_ERROR;
1047}
1048
1049svn_error_t *
1050svn_fs_x__reset_txn_filesize(void **data,
1051 apr_size_t *data_len,
1052 void *baton,
1053 apr_pool_t *pool)
1054{
1055 dir_data_t *dir_data = (dir_data_t *)*data;
1056 dir_data->txn_filesize = SVN_INVALID_FILESIZE;
1057
1058 return SVN_NO_ERROR;
1059}
1060
1032svn_error_t *
1033svn_fs_x__serialize_rep_header(void **data,
1034 apr_size_t *data_len,
1035 void *in,
1036 apr_pool_t *pool)
1037{
1061svn_error_t *
1062svn_fs_x__serialize_rep_header(void **data,
1063 apr_size_t *data_len,
1064 void *in,
1065 apr_pool_t *pool)
1066{
1038 svn_fs_x__rep_header_t *copy = apr_palloc(pool, sizeof(*copy));
1039 *copy = *(svn_fs_x__rep_header_t *)in;
1040
1041 *data_len = sizeof(svn_fs_x__rep_header_t);
1067 *data_len = sizeof(svn_fs_x__rep_header_t);
1042 *data = copy;
1068 *data = in;
1043
1044 return SVN_NO_ERROR;
1045}
1046
1047svn_error_t *
1048svn_fs_x__deserialize_rep_header(void **out,
1049 void *data,
1050 apr_size_t data_len,
1069
1070 return SVN_NO_ERROR;
1071}
1072
1073svn_error_t *
1074svn_fs_x__deserialize_rep_header(void **out,
1075 void *data,
1076 apr_size_t data_len,
1051 apr_pool_t *pool)
1077 apr_pool_t *result_pool)
1052{
1078{
1053 svn_fs_x__rep_header_t *copy = apr_palloc(pool, sizeof(*copy));
1054 SVN_ERR_ASSERT(data_len == sizeof(*copy));
1055
1056 *copy = *(svn_fs_x__rep_header_t *)data;
1057 *out = data;
1058
1059 return SVN_NO_ERROR;
1060}
1061
1062/* Utility function to serialize change CHANGE_P in the given serialization
1063 * CONTEXT.
1064 */

--- 18 unchanged lines hidden (view full) ---

1083 svn_temp_serializer__pop(context);
1084}
1085
1086/* Utility function to serialize the CHANGE_P within the given
1087 * serialization CONTEXT.
1088 */
1089static void
1090deserialize_change(void *buffer,
1079 *out = data;
1080
1081 return SVN_NO_ERROR;
1082}
1083
1084/* Utility function to serialize change CHANGE_P in the given serialization
1085 * CONTEXT.
1086 */

--- 18 unchanged lines hidden (view full) ---

1105 svn_temp_serializer__pop(context);
1106}
1107
1108/* Utility function to serialize the CHANGE_P within the given
1109 * serialization CONTEXT.
1110 */
1111static void
1112deserialize_change(void *buffer,
1091 svn_fs_x__change_t **change_p,
1092 apr_pool_t *pool)
1113 svn_fs_x__change_t **change_p)
1093{
1094 svn_fs_x__change_t * change;
1095
1096 /* fix-up of the pointer to the struct in question */
1097 svn_temp_deserializer__resolve(buffer, (void **)change_p);
1098
1099 change = *change_p;
1100 if (change == NULL)
1101 return;
1102
1103 /* fix-up of sub-structures */
1104 svn_temp_deserializer__resolve(change, (void **)&change->path.data);
1105 svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path);
1106}
1107
1114{
1115 svn_fs_x__change_t * change;
1116
1117 /* fix-up of the pointer to the struct in question */
1118 svn_temp_deserializer__resolve(buffer, (void **)change_p);
1119
1120 change = *change_p;
1121 if (change == NULL)
1122 return;
1123
1124 /* fix-up of sub-structures */
1125 svn_temp_deserializer__resolve(change, (void **)&change->path.data);
1126 svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path);
1127}
1128
1108/* Auxiliary structure representing the content of a svn_fs_x__change_t array.
1109 This structure is much easier to (de-)serialize than an APR array.
1110 */
1111typedef struct changes_data_t
1112{
1113 /* number of entries in the array */
1114 int count;
1115
1116 /* reference to the changes */
1117 svn_fs_x__change_t **changes;
1118} changes_data_t;
1119
1120svn_error_t *
1121svn_fs_x__serialize_changes(void **data,
1122 apr_size_t *data_len,
1123 void *in,
1124 apr_pool_t *pool)
1125{
1129svn_error_t *
1130svn_fs_x__serialize_changes(void **data,
1131 apr_size_t *data_len,
1132 void *in,
1133 apr_pool_t *pool)
1134{
1126 apr_array_header_t *array = in;
1127 changes_data_t changes;
1135 svn_fs_x__changes_list_t *changes = in;
1128 svn_temp_serializer__context_t *context;
1129 svn_stringbuf_t *serialized;
1130 int i;
1131
1136 svn_temp_serializer__context_t *context;
1137 svn_stringbuf_t *serialized;
1138 int i;
1139
1132 /* initialize our auxiliary data structure and link it to the
1133 * array elements */
1134 changes.count = array->nelts;
1135 changes.changes = (svn_fs_x__change_t **)array->elts;
1136
1137 /* serialize it and all its elements */
1140 /* serialize it and all its elements */
1138 context = svn_temp_serializer__init(&changes,
1139 sizeof(changes),
1140 changes.count * 250,
1141 context = svn_temp_serializer__init(changes,
1142 sizeof(*changes),
1143 changes->count * 250,
1141 pool);
1142
1143 svn_temp_serializer__push(context,
1144 pool);
1145
1146 svn_temp_serializer__push(context,
1144 (const void * const *)&changes.changes,
1145 changes.count * sizeof(svn_fs_x__change_t*));
1147 (const void * const *)&changes->changes,
1148 changes->count * sizeof(*changes->changes));
1146
1149
1147 for (i = 0; i < changes.count; ++i)
1148 serialize_change(context, &changes.changes[i]);
1150 for (i = 0; i < changes->count; ++i)
1151 serialize_change(context, &changes->changes[i]);
1149
1150 svn_temp_serializer__pop(context);
1151
1152 /* return the serialized result */
1153 serialized = svn_temp_serializer__get(context);
1154
1155 *data = serialized->data;
1156 *data_len = serialized->len;
1157
1158 return SVN_NO_ERROR;
1159}
1160
1161svn_error_t *
1162svn_fs_x__deserialize_changes(void **out,
1163 void *data,
1164 apr_size_t data_len,
1152
1153 svn_temp_serializer__pop(context);
1154
1155 /* return the serialized result */
1156 serialized = svn_temp_serializer__get(context);
1157
1158 *data = serialized->data;
1159 *data_len = serialized->len;
1160
1161 return SVN_NO_ERROR;
1162}
1163
1164svn_error_t *
1165svn_fs_x__deserialize_changes(void **out,
1166 void *data,
1167 apr_size_t data_len,
1165 apr_pool_t *pool)
1168 apr_pool_t *result_pool)
1166{
1167 int i;
1169{
1170 int i;
1168 changes_data_t *changes = (changes_data_t *)data;
1169 apr_array_header_t *array = apr_array_make(pool, 0,
1170 sizeof(svn_fs_x__change_t *));
1171 svn_fs_x__changes_list_t *changes = (svn_fs_x__changes_list_t *)data;
1171
1172 /* de-serialize our auxiliary data structure */
1173 svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
1174
1175 /* de-serialize each entry and add it to the array */
1176 for (i = 0; i < changes->count; ++i)
1177 deserialize_change(changes->changes,
1172
1173 /* de-serialize our auxiliary data structure */
1174 svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
1175
1176 /* de-serialize each entry and add it to the array */
1177 for (i = 0; i < changes->count; ++i)
1178 deserialize_change(changes->changes,
1178 (svn_fs_x__change_t **)&changes->changes[i],
1179 pool);
1179 (svn_fs_x__change_t **)&changes->changes[i]);
1180
1180
1181 /* Use the changes buffer as the array's data buffer
1182 * (DATA remains valid for at least as long as POOL). */
1183 array->elts = (char *)changes->changes;
1184 array->nelts = changes->count;
1185 array->nalloc = changes->count;
1186
1187 /* done */
1181 /* done */
1188 *out = array;
1182 *out = changes;
1189
1190 return SVN_NO_ERROR;
1191}
1183
1184 return SVN_NO_ERROR;
1185}
1192
1193/* Auxiliary structure representing the content of a svn_mergeinfo_t hash.
1194 This structure is much easier to (de-)serialize than an APR array.
1195 */
1196typedef struct mergeinfo_data_t
1197{
1198 /* number of paths in the hash */
1199 unsigned count;
1200
1201 /* COUNT keys (paths) */
1202 const char **keys;
1203
1204 /* COUNT keys lengths (strlen of path) */
1205 apr_ssize_t *key_lengths;
1206
1207 /* COUNT entries, each giving the number of ranges for the key */
1208 int *range_counts;
1209
1210 /* all ranges in a single, concatenated buffer */
1211 svn_merge_range_t *ranges;
1212} mergeinfo_data_t;
1213
1214svn_error_t *
1215svn_fs_x__serialize_mergeinfo(void **data,
1216 apr_size_t *data_len,
1217 void *in,
1218 apr_pool_t *pool)
1219{
1220 svn_mergeinfo_t mergeinfo = in;
1221 mergeinfo_data_t merges;
1222 svn_temp_serializer__context_t *context;
1223 svn_stringbuf_t *serialized;
1224 apr_hash_index_t *hi;
1225 unsigned i;
1226 int k;
1227 apr_size_t range_count;
1228
1229 /* initialize our auxiliary data structure */
1230 merges.count = apr_hash_count(mergeinfo);
1231 merges.keys = apr_palloc(pool, sizeof(*merges.keys) * merges.count);
1232 merges.key_lengths = apr_palloc(pool, sizeof(*merges.key_lengths) *
1233 merges.count);
1234 merges.range_counts = apr_palloc(pool, sizeof(*merges.range_counts) *
1235 merges.count);
1236
1237 i = 0;
1238 range_count = 0;
1239 for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi), ++i)
1240 {
1241 svn_rangelist_t *ranges;
1242 apr_hash_this(hi, (const void**)&merges.keys[i],
1243 &merges.key_lengths[i],
1244 (void **)&ranges);
1245 merges.range_counts[i] = ranges->nelts;
1246 range_count += ranges->nelts;
1247 }
1248
1249 merges.ranges = apr_palloc(pool, sizeof(*merges.ranges) * range_count);
1250
1251 i = 0;
1252 for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
1253 {
1254 svn_rangelist_t *ranges = apr_hash_this_val(hi);
1255 for (k = 0; k < ranges->nelts; ++k, ++i)
1256 merges.ranges[i] = *APR_ARRAY_IDX(ranges, k, svn_merge_range_t*);
1257 }
1258
1259 /* serialize it and all its elements */
1260 context = svn_temp_serializer__init(&merges,
1261 sizeof(merges),
1262 range_count * 30,
1263 pool);
1264
1265 /* keys array */
1266 svn_temp_serializer__push(context,
1267 (const void * const *)&merges.keys,
1268 merges.count * sizeof(*merges.keys));
1269
1270 for (i = 0; i < merges.count; ++i)
1271 svn_temp_serializer__add_string(context, &merges.keys[i]);
1272
1273 svn_temp_serializer__pop(context);
1274
1275 /* key lengths array */
1276 svn_temp_serializer__add_leaf(context,
1277 (const void * const *)&merges.key_lengths,
1278 merges.count * sizeof(*merges.key_lengths));
1279
1280 /* range counts array */
1281 svn_temp_serializer__add_leaf(context,
1282 (const void * const *)&merges.range_counts,
1283 merges.count * sizeof(*merges.range_counts));
1284
1285 /* ranges */
1286 svn_temp_serializer__add_leaf(context,
1287 (const void * const *)&merges.ranges,
1288 range_count * sizeof(*merges.ranges));
1289
1290 /* return the serialized result */
1291 serialized = svn_temp_serializer__get(context);
1292
1293 *data = serialized->data;
1294 *data_len = serialized->len;
1295
1296 return SVN_NO_ERROR;
1297}
1298
1299svn_error_t *
1300svn_fs_x__deserialize_mergeinfo(void **out,
1301 void *data,
1302 apr_size_t data_len,
1303 apr_pool_t *pool)
1304{
1305 unsigned i;
1306 int k, n;
1307 mergeinfo_data_t *merges = (mergeinfo_data_t *)data;
1308 svn_mergeinfo_t mergeinfo;
1309
1310 /* de-serialize our auxiliary data structure */
1311 svn_temp_deserializer__resolve(merges, (void**)&merges->keys);
1312 svn_temp_deserializer__resolve(merges, (void**)&merges->key_lengths);
1313 svn_temp_deserializer__resolve(merges, (void**)&merges->range_counts);
1314 svn_temp_deserializer__resolve(merges, (void**)&merges->ranges);
1315
1316 /* de-serialize keys and add entries to the result */
1317 n = 0;
1318 mergeinfo = svn_hash__make(pool);
1319 for (i = 0; i < merges->count; ++i)
1320 {
1321 svn_rangelist_t *ranges = apr_array_make(pool,
1322 merges->range_counts[i],
1323 sizeof(svn_merge_range_t*));
1324 for (k = 0; k < merges->range_counts[i]; ++k, ++n)
1325 APR_ARRAY_PUSH(ranges, svn_merge_range_t*) = &merges->ranges[n];
1326
1327 svn_temp_deserializer__resolve(merges->keys,
1328 (void**)&merges->keys[i]);
1329 apr_hash_set(mergeinfo, merges->keys[i], merges->key_lengths[i], ranges);
1330 }
1331
1332 /* done */
1333 *out = mergeinfo;
1334
1335 return SVN_NO_ERROR;
1336}
1337