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