1251881Speter/* temp_serializer.c: serialization functions for caching of FSFS structures 2251881Speter * 3251881Speter * ==================================================================== 4251881Speter * Licensed to the Apache Software Foundation (ASF) under one 5251881Speter * or more contributor license agreements. See the NOTICE file 6251881Speter * distributed with this work for additional information 7251881Speter * regarding copyright ownership. The ASF licenses this file 8251881Speter * to you under the Apache License, Version 2.0 (the 9251881Speter * "License"); you may not use this file except in compliance 10251881Speter * with the License. You may obtain a copy of the License at 11251881Speter * 12251881Speter * http://www.apache.org/licenses/LICENSE-2.0 13251881Speter * 14251881Speter * Unless required by applicable law or agreed to in writing, 15251881Speter * software distributed under the License is distributed on an 16251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17251881Speter * KIND, either express or implied. See the License for the 18251881Speter * specific language governing permissions and limitations 19251881Speter * under the License. 20251881Speter * ==================================================================== 21251881Speter */ 22251881Speter 23251881Speter#include <apr_pools.h> 24251881Speter 25251881Speter#include "svn_pools.h" 26251881Speter#include "svn_hash.h" 27251881Speter 28251881Speter#include "id.h" 29251881Speter#include "svn_fs.h" 30251881Speter 31251881Speter#include "private/svn_fs_util.h" 32251881Speter#include "private/svn_temp_serializer.h" 33251881Speter#include "private/svn_subr_private.h" 34251881Speter 35251881Speter#include "temp_serializer.h" 36251881Speter 37251881Speter/* Utility to encode a signed NUMBER into a variable-length sequence of 38251881Speter * 8-bit chars in KEY_BUFFER and return the last writen position. 39251881Speter * 40251881Speter * Numbers will be stored in 7 bits / byte and using byte values above 41251881Speter * 32 (' ') to make them combinable with other string by simply separating 42251881Speter * individual parts with spaces. 43251881Speter */ 44251881Speterstatic char* 45251881Speterencode_number(apr_int64_t number, char *key_buffer) 46251881Speter{ 47251881Speter /* encode the sign in the first byte */ 48251881Speter if (number < 0) 49251881Speter { 50251881Speter number = -number; 51251881Speter *key_buffer = (char)((number & 63) + ' ' + 65); 52251881Speter } 53251881Speter else 54251881Speter *key_buffer = (char)((number & 63) + ' ' + 1); 55251881Speter number /= 64; 56251881Speter 57251881Speter /* write 7 bits / byte until no significant bits are left */ 58251881Speter while (number) 59251881Speter { 60251881Speter *++key_buffer = (char)((number & 127) + ' ' + 1); 61251881Speter number /= 128; 62251881Speter } 63251881Speter 64251881Speter /* return the last written position */ 65251881Speter return key_buffer; 66251881Speter} 67251881Speter 68251881Speterconst char* 69251881Spetersvn_fs_fs__combine_number_and_string(apr_int64_t number, 70251881Speter const char *string, 71251881Speter apr_pool_t *pool) 72251881Speter{ 73251881Speter apr_size_t len = strlen(string); 74251881Speter 75251881Speter /* number part requires max. 10x7 bits + 1 space. 76251881Speter * Add another 1 for the terminal 0 */ 77251881Speter char *key_buffer = apr_palloc(pool, len + 12); 78251881Speter const char *key = key_buffer; 79251881Speter 80251881Speter /* Prepend the number to the string and separate them by space. No other 81251881Speter * number can result in the same prefix, no other string in the same 82251881Speter * postfix nor can the boundary between them be ambiguous. */ 83251881Speter key_buffer = encode_number(number, key_buffer); 84251881Speter *++key_buffer = ' '; 85251881Speter memcpy(++key_buffer, string, len+1); 86251881Speter 87251881Speter /* return the start of the key */ 88251881Speter return key; 89251881Speter} 90251881Speter 91251881Speter/* Utility function to serialize string S in the given serialization CONTEXT. 92251881Speter */ 93251881Speterstatic void 94251881Speterserialize_svn_string(svn_temp_serializer__context_t *context, 95251881Speter const svn_string_t * const *s) 96251881Speter{ 97251881Speter const svn_string_t *string = *s; 98251881Speter 99251881Speter /* Nothing to do for NULL string references. */ 100251881Speter if (string == NULL) 101251881Speter return; 102251881Speter 103251881Speter svn_temp_serializer__push(context, 104251881Speter (const void * const *)s, 105251881Speter sizeof(*string)); 106251881Speter 107251881Speter /* the "string" content may actually be arbitrary binary data. 108251881Speter * Thus, we cannot use svn_temp_serializer__add_string. */ 109251881Speter svn_temp_serializer__push(context, 110251881Speter (const void * const *)&string->data, 111251881Speter string->len + 1); 112251881Speter 113251881Speter /* back to the caller's nesting level */ 114251881Speter svn_temp_serializer__pop(context); 115251881Speter svn_temp_serializer__pop(context); 116251881Speter} 117251881Speter 118251881Speter/* Utility function to deserialize the STRING inside the BUFFER. 119251881Speter */ 120251881Speterstatic void 121251881Speterdeserialize_svn_string(void *buffer, svn_string_t **string) 122251881Speter{ 123251881Speter svn_temp_deserializer__resolve(buffer, (void **)string); 124251881Speter if (*string == NULL) 125251881Speter return; 126251881Speter 127251881Speter svn_temp_deserializer__resolve(*string, (void **)&(*string)->data); 128251881Speter} 129251881Speter 130251881Speter/* Utility function to serialize checkum CS within the given serialization 131251881Speter * CONTEXT. 132251881Speter */ 133251881Speterstatic void 134251881Speterserialize_checksum(svn_temp_serializer__context_t *context, 135251881Speter svn_checksum_t * const *cs) 136251881Speter{ 137251881Speter const svn_checksum_t *checksum = *cs; 138251881Speter if (checksum == NULL) 139251881Speter return; 140251881Speter 141251881Speter svn_temp_serializer__push(context, 142251881Speter (const void * const *)cs, 143251881Speter sizeof(*checksum)); 144251881Speter 145251881Speter /* The digest is arbitrary binary data. 146251881Speter * Thus, we cannot use svn_temp_serializer__add_string. */ 147251881Speter svn_temp_serializer__push(context, 148251881Speter (const void * const *)&checksum->digest, 149251881Speter svn_checksum_size(checksum)); 150251881Speter 151251881Speter /* return to the caller's nesting level */ 152251881Speter svn_temp_serializer__pop(context); 153251881Speter svn_temp_serializer__pop(context); 154251881Speter} 155251881Speter 156251881Speter/* Utility function to deserialize the checksum CS inside the BUFFER. 157251881Speter */ 158251881Speterstatic void 159251881Speterdeserialize_checksum(void *buffer, svn_checksum_t **cs) 160251881Speter{ 161251881Speter svn_temp_deserializer__resolve(buffer, (void **)cs); 162251881Speter if (*cs == NULL) 163251881Speter return; 164251881Speter 165251881Speter svn_temp_deserializer__resolve(*cs, (void **)&(*cs)->digest); 166251881Speter} 167251881Speter 168251881Speter/* Utility function to serialize the REPRESENTATION within the given 169251881Speter * serialization CONTEXT. 170251881Speter */ 171251881Speterstatic void 172251881Speterserialize_representation(svn_temp_serializer__context_t *context, 173251881Speter representation_t * const *representation) 174251881Speter{ 175251881Speter const representation_t * rep = *representation; 176251881Speter if (rep == NULL) 177251881Speter return; 178251881Speter 179251881Speter /* serialize the representation struct itself */ 180251881Speter svn_temp_serializer__push(context, 181251881Speter (const void * const *)representation, 182251881Speter sizeof(*rep)); 183251881Speter 184251881Speter /* serialize sub-structures */ 185251881Speter serialize_checksum(context, &rep->md5_checksum); 186251881Speter serialize_checksum(context, &rep->sha1_checksum); 187251881Speter 188251881Speter svn_temp_serializer__add_string(context, &rep->txn_id); 189251881Speter svn_temp_serializer__add_string(context, &rep->uniquifier); 190251881Speter 191251881Speter /* return to the caller's nesting level */ 192251881Speter svn_temp_serializer__pop(context); 193251881Speter} 194251881Speter 195251881Speter/* Utility function to deserialize the REPRESENTATIONS inside the BUFFER. 196251881Speter */ 197251881Speterstatic void 198251881Speterdeserialize_representation(void *buffer, 199251881Speter representation_t **representation) 200251881Speter{ 201251881Speter representation_t *rep; 202251881Speter 203251881Speter /* fixup the reference to the representation itself */ 204251881Speter svn_temp_deserializer__resolve(buffer, (void **)representation); 205251881Speter rep = *representation; 206251881Speter if (rep == NULL) 207251881Speter return; 208251881Speter 209251881Speter /* fixup of sub-structures */ 210251881Speter deserialize_checksum(rep, &rep->md5_checksum); 211251881Speter deserialize_checksum(rep, &rep->sha1_checksum); 212251881Speter 213251881Speter svn_temp_deserializer__resolve(rep, (void **)&rep->txn_id); 214251881Speter svn_temp_deserializer__resolve(rep, (void **)&rep->uniquifier); 215251881Speter} 216251881Speter 217251881Speter/* auxilliary structure representing the content of a directory hash */ 218251881Spetertypedef struct hash_data_t 219251881Speter{ 220251881Speter /* number of entries in the directory */ 221251881Speter apr_size_t count; 222251881Speter 223251881Speter /* number of unused dir entry buckets in the index */ 224251881Speter apr_size_t over_provision; 225251881Speter 226251881Speter /* internal modifying operations counter 227251881Speter * (used to repack data once in a while) */ 228251881Speter apr_size_t operations; 229251881Speter 230251881Speter /* size of the serialization buffer actually used. 231251881Speter * (we will allocate more than we actually need such that we may 232251881Speter * append more data in situ later) */ 233251881Speter apr_size_t len; 234251881Speter 235251881Speter /* reference to the entries */ 236251881Speter svn_fs_dirent_t **entries; 237251881Speter 238251881Speter /* size of the serialized entries and don't be too wasteful 239251881Speter * (needed since the entries are no longer in sequence) */ 240251881Speter apr_uint32_t *lengths; 241251881Speter} hash_data_t; 242251881Speter 243251881Speterstatic int 244251881Spetercompare_dirent_id_names(const void *lhs, const void *rhs) 245251881Speter{ 246251881Speter return strcmp((*(const svn_fs_dirent_t *const *)lhs)->name, 247251881Speter (*(const svn_fs_dirent_t *const *)rhs)->name); 248251881Speter} 249251881Speter 250251881Speter/* Utility function to serialize the *ENTRY_P into a the given 251251881Speter * serialization CONTEXT. Return the serialized size of the 252251881Speter * dir entry in *LENGTH. 253251881Speter */ 254251881Speterstatic void 255251881Speterserialize_dir_entry(svn_temp_serializer__context_t *context, 256251881Speter svn_fs_dirent_t **entry_p, 257251881Speter apr_uint32_t *length) 258251881Speter{ 259251881Speter svn_fs_dirent_t *entry = *entry_p; 260251881Speter apr_size_t initial_length = svn_temp_serializer__get_length(context); 261251881Speter 262251881Speter svn_temp_serializer__push(context, 263251881Speter (const void * const *)entry_p, 264251881Speter sizeof(svn_fs_dirent_t)); 265251881Speter 266251881Speter svn_fs_fs__id_serialize(context, &entry->id); 267251881Speter svn_temp_serializer__add_string(context, &entry->name); 268251881Speter 269251881Speter *length = (apr_uint32_t)( svn_temp_serializer__get_length(context) 270251881Speter - APR_ALIGN_DEFAULT(initial_length)); 271251881Speter 272251881Speter svn_temp_serializer__pop(context); 273251881Speter} 274251881Speter 275251881Speter/* Utility function to serialize the ENTRIES into a new serialization 276251881Speter * context to be returned. Allocation will be made form POOL. 277251881Speter */ 278251881Speterstatic svn_temp_serializer__context_t * 279251881Speterserialize_dir(apr_hash_t *entries, apr_pool_t *pool) 280251881Speter{ 281251881Speter hash_data_t hash_data; 282251881Speter apr_hash_index_t *hi; 283251881Speter apr_size_t i = 0; 284251881Speter svn_temp_serializer__context_t *context; 285251881Speter 286251881Speter /* calculate sizes */ 287251881Speter apr_size_t count = apr_hash_count(entries); 288251881Speter apr_size_t over_provision = 2 + count / 4; 289251881Speter apr_size_t entries_len = (count + over_provision) * sizeof(svn_fs_dirent_t*); 290251881Speter apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t); 291251881Speter 292251881Speter /* copy the hash entries to an auxilliary struct of known layout */ 293251881Speter hash_data.count = count; 294251881Speter hash_data.over_provision = over_provision; 295251881Speter hash_data.operations = 0; 296251881Speter hash_data.entries = apr_palloc(pool, entries_len); 297251881Speter hash_data.lengths = apr_palloc(pool, lengths_len); 298251881Speter 299251881Speter for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi), ++i) 300251881Speter hash_data.entries[i] = svn__apr_hash_index_val(hi); 301251881Speter 302251881Speter /* sort entry index by ID name */ 303251881Speter qsort(hash_data.entries, 304251881Speter count, 305251881Speter sizeof(*hash_data.entries), 306251881Speter compare_dirent_id_names); 307251881Speter 308251881Speter /* Serialize that aux. structure into a new one. Also, provide a good 309251881Speter * estimate for the size of the buffer that we will need. */ 310251881Speter context = svn_temp_serializer__init(&hash_data, 311251881Speter sizeof(hash_data), 312251881Speter 50 + count * 200 + entries_len, 313251881Speter pool); 314251881Speter 315251881Speter /* serialize entries references */ 316251881Speter svn_temp_serializer__push(context, 317251881Speter (const void * const *)&hash_data.entries, 318251881Speter entries_len); 319251881Speter 320251881Speter /* serialize the individual entries and their sub-structures */ 321251881Speter for (i = 0; i < count; ++i) 322251881Speter serialize_dir_entry(context, 323251881Speter &hash_data.entries[i], 324251881Speter &hash_data.lengths[i]); 325251881Speter 326251881Speter svn_temp_serializer__pop(context); 327251881Speter 328251881Speter /* serialize entries references */ 329251881Speter svn_temp_serializer__push(context, 330251881Speter (const void * const *)&hash_data.lengths, 331251881Speter lengths_len); 332251881Speter 333251881Speter return context; 334251881Speter} 335251881Speter 336251881Speter/* Utility function to reconstruct a dir entries hash from serialized data 337251881Speter * in BUFFER and HASH_DATA. Allocation will be made form POOL. 338251881Speter */ 339251881Speterstatic apr_hash_t * 340251881Speterdeserialize_dir(void *buffer, hash_data_t *hash_data, apr_pool_t *pool) 341251881Speter{ 342251881Speter apr_hash_t *result = svn_hash__make(pool); 343251881Speter apr_size_t i; 344251881Speter apr_size_t count; 345251881Speter svn_fs_dirent_t *entry; 346251881Speter svn_fs_dirent_t **entries; 347251881Speter 348251881Speter /* resolve the reference to the entries array */ 349251881Speter svn_temp_deserializer__resolve(buffer, (void **)&hash_data->entries); 350251881Speter entries = hash_data->entries; 351251881Speter 352251881Speter /* fixup the references within each entry and add it to the hash */ 353251881Speter for (i = 0, count = hash_data->count; i < count; ++i) 354251881Speter { 355251881Speter svn_temp_deserializer__resolve(entries, (void **)&entries[i]); 356251881Speter entry = hash_data->entries[i]; 357251881Speter 358251881Speter /* pointer fixup */ 359251881Speter svn_temp_deserializer__resolve(entry, (void **)&entry->name); 360251881Speter svn_fs_fs__id_deserialize(entry, (svn_fs_id_t **)&entry->id); 361251881Speter 362251881Speter /* add the entry to the hash */ 363251881Speter svn_hash_sets(result, entry->name, entry); 364251881Speter } 365251881Speter 366251881Speter /* return the now complete hash */ 367251881Speter return result; 368251881Speter} 369251881Speter 370251881Spetervoid 371251881Spetersvn_fs_fs__noderev_serialize(svn_temp_serializer__context_t *context, 372251881Speter node_revision_t * const *noderev_p) 373251881Speter{ 374251881Speter const node_revision_t *noderev = *noderev_p; 375251881Speter if (noderev == NULL) 376251881Speter return; 377251881Speter 378251881Speter /* serialize the representation struct itself */ 379251881Speter svn_temp_serializer__push(context, 380251881Speter (const void * const *)noderev_p, 381251881Speter sizeof(*noderev)); 382251881Speter 383251881Speter /* serialize sub-structures */ 384251881Speter svn_fs_fs__id_serialize(context, &noderev->id); 385251881Speter svn_fs_fs__id_serialize(context, &noderev->predecessor_id); 386251881Speter serialize_representation(context, &noderev->prop_rep); 387251881Speter serialize_representation(context, &noderev->data_rep); 388251881Speter 389251881Speter svn_temp_serializer__add_string(context, &noderev->copyfrom_path); 390251881Speter svn_temp_serializer__add_string(context, &noderev->copyroot_path); 391251881Speter svn_temp_serializer__add_string(context, &noderev->created_path); 392251881Speter 393251881Speter /* return to the caller's nesting level */ 394251881Speter svn_temp_serializer__pop(context); 395251881Speter} 396251881Speter 397251881Speter 398251881Spetervoid 399251881Spetersvn_fs_fs__noderev_deserialize(void *buffer, 400251881Speter node_revision_t **noderev_p) 401251881Speter{ 402251881Speter node_revision_t *noderev; 403251881Speter 404251881Speter /* fixup the reference to the representation itself, 405251881Speter * if this is part of a parent structure. */ 406251881Speter if (buffer != *noderev_p) 407251881Speter svn_temp_deserializer__resolve(buffer, (void **)noderev_p); 408251881Speter 409251881Speter noderev = *noderev_p; 410251881Speter if (noderev == NULL) 411251881Speter return; 412251881Speter 413251881Speter /* fixup of sub-structures */ 414251881Speter svn_fs_fs__id_deserialize(noderev, (svn_fs_id_t **)&noderev->id); 415251881Speter svn_fs_fs__id_deserialize(noderev, (svn_fs_id_t **)&noderev->predecessor_id); 416251881Speter deserialize_representation(noderev, &noderev->prop_rep); 417251881Speter deserialize_representation(noderev, &noderev->data_rep); 418251881Speter 419251881Speter svn_temp_deserializer__resolve(noderev, (void **)&noderev->copyfrom_path); 420251881Speter svn_temp_deserializer__resolve(noderev, (void **)&noderev->copyroot_path); 421251881Speter svn_temp_deserializer__resolve(noderev, (void **)&noderev->created_path); 422251881Speter} 423251881Speter 424251881Speter 425251881Speter/* Utility function to serialize COUNT svn_txdelta_op_t objects 426251881Speter * at OPS in the given serialization CONTEXT. 427251881Speter */ 428251881Speterstatic void 429251881Speterserialize_txdelta_ops(svn_temp_serializer__context_t *context, 430251881Speter const svn_txdelta_op_t * const * ops, 431251881Speter apr_size_t count) 432251881Speter{ 433251881Speter if (*ops == NULL) 434251881Speter return; 435251881Speter 436251881Speter /* the ops form a contiguous chunk of memory with no further references */ 437251881Speter svn_temp_serializer__push(context, 438251881Speter (const void * const *)ops, 439251881Speter count * sizeof(svn_txdelta_op_t)); 440251881Speter svn_temp_serializer__pop(context); 441251881Speter} 442251881Speter 443251881Speter/* Utility function to serialize W in the given serialization CONTEXT. 444251881Speter */ 445251881Speterstatic void 446251881Speterserialize_txdeltawindow(svn_temp_serializer__context_t *context, 447251881Speter svn_txdelta_window_t * const * w) 448251881Speter{ 449251881Speter svn_txdelta_window_t *window = *w; 450251881Speter 451251881Speter /* serialize the window struct itself */ 452251881Speter svn_temp_serializer__push(context, 453251881Speter (const void * const *)w, 454251881Speter sizeof(svn_txdelta_window_t)); 455251881Speter 456251881Speter /* serialize its sub-structures */ 457251881Speter serialize_txdelta_ops(context, &window->ops, window->num_ops); 458251881Speter serialize_svn_string(context, &window->new_data); 459251881Speter 460251881Speter svn_temp_serializer__pop(context); 461251881Speter} 462251881Speter 463251881Spetersvn_error_t * 464251881Spetersvn_fs_fs__serialize_txdelta_window(void **buffer, 465251881Speter apr_size_t *buffer_size, 466251881Speter void *item, 467251881Speter apr_pool_t *pool) 468251881Speter{ 469251881Speter svn_fs_fs__txdelta_cached_window_t *window_info = item; 470251881Speter svn_stringbuf_t *serialized; 471251881Speter 472251881Speter /* initialize the serialization process and allocate a buffer large 473251881Speter * enough to do without the need of re-allocations in most cases. */ 474251881Speter apr_size_t text_len = window_info->window->new_data 475251881Speter ? window_info->window->new_data->len 476251881Speter : 0; 477251881Speter svn_temp_serializer__context_t *context = 478251881Speter svn_temp_serializer__init(window_info, 479251881Speter sizeof(*window_info), 480251881Speter 500 + text_len, 481251881Speter pool); 482251881Speter 483251881Speter /* serialize the sub-structure(s) */ 484251881Speter serialize_txdeltawindow(context, &window_info->window); 485251881Speter 486251881Speter /* return the serialized result */ 487251881Speter serialized = svn_temp_serializer__get(context); 488251881Speter 489251881Speter *buffer = serialized->data; 490251881Speter *buffer_size = serialized->len; 491251881Speter 492251881Speter return SVN_NO_ERROR; 493251881Speter} 494251881Speter 495251881Spetersvn_error_t * 496251881Spetersvn_fs_fs__deserialize_txdelta_window(void **item, 497251881Speter void *buffer, 498251881Speter apr_size_t buffer_size, 499251881Speter apr_pool_t *pool) 500251881Speter{ 501251881Speter svn_txdelta_window_t *window; 502251881Speter 503251881Speter /* Copy the _full_ buffer as it also contains the sub-structures. */ 504251881Speter svn_fs_fs__txdelta_cached_window_t *window_info = 505251881Speter (svn_fs_fs__txdelta_cached_window_t *)buffer; 506251881Speter 507251881Speter /* pointer reference fixup */ 508251881Speter svn_temp_deserializer__resolve(window_info, 509251881Speter (void **)&window_info->window); 510251881Speter window = window_info->window; 511251881Speter 512251881Speter svn_temp_deserializer__resolve(window, (void **)&window->ops); 513251881Speter 514251881Speter deserialize_svn_string(window, (svn_string_t**)&window->new_data); 515251881Speter 516251881Speter /* done */ 517251881Speter *item = window_info; 518251881Speter 519251881Speter return SVN_NO_ERROR; 520251881Speter} 521251881Speter 522251881Spetersvn_error_t * 523251881Spetersvn_fs_fs__serialize_manifest(void **data, 524251881Speter apr_size_t *data_len, 525251881Speter void *in, 526251881Speter apr_pool_t *pool) 527251881Speter{ 528251881Speter apr_array_header_t *manifest = in; 529251881Speter 530251881Speter *data_len = sizeof(apr_off_t) *manifest->nelts; 531251881Speter *data = apr_palloc(pool, *data_len); 532251881Speter memcpy(*data, manifest->elts, *data_len); 533251881Speter 534251881Speter return SVN_NO_ERROR; 535251881Speter} 536251881Speter 537251881Spetersvn_error_t * 538251881Spetersvn_fs_fs__deserialize_manifest(void **out, 539251881Speter void *data, 540251881Speter apr_size_t data_len, 541251881Speter apr_pool_t *pool) 542251881Speter{ 543251881Speter apr_array_header_t *manifest = apr_array_make(pool, 1, sizeof(apr_off_t)); 544251881Speter 545251881Speter manifest->nelts = (int) (data_len / sizeof(apr_off_t)); 546251881Speter manifest->nalloc = (int) (data_len / sizeof(apr_off_t)); 547251881Speter manifest->elts = (char*)data; 548251881Speter 549251881Speter *out = manifest; 550251881Speter 551251881Speter return SVN_NO_ERROR; 552251881Speter} 553251881Speter 554251881Speter/* Auxilliary structure representing the content of a properties hash. 555251881Speter This structure is much easier to (de-)serialize than an apr_hash. 556251881Speter */ 557251881Spetertypedef struct properties_data_t 558251881Speter{ 559251881Speter /* number of entries in the hash */ 560251881Speter apr_size_t count; 561251881Speter 562251881Speter /* reference to the keys */ 563251881Speter const char **keys; 564251881Speter 565251881Speter /* reference to the values */ 566251881Speter const svn_string_t **values; 567251881Speter} properties_data_t; 568251881Speter 569251881Speter/* Serialize COUNT C-style strings from *STRINGS into CONTEXT. */ 570251881Speterstatic void 571251881Speterserialize_cstring_array(svn_temp_serializer__context_t *context, 572251881Speter const char ***strings, 573251881Speter apr_size_t count) 574251881Speter{ 575251881Speter apr_size_t i; 576251881Speter const char **entries = *strings; 577251881Speter 578251881Speter /* serialize COUNT entries pointers (the array) */ 579251881Speter svn_temp_serializer__push(context, 580251881Speter (const void * const *)strings, 581251881Speter count * sizeof(const char*)); 582251881Speter 583251881Speter /* serialize array elements */ 584251881Speter for (i = 0; i < count; ++i) 585251881Speter svn_temp_serializer__add_string(context, &entries[i]); 586251881Speter 587251881Speter svn_temp_serializer__pop(context); 588251881Speter} 589251881Speter 590251881Speter/* Serialize COUNT svn_string_t* items from *STRINGS into CONTEXT. */ 591251881Speterstatic void 592251881Speterserialize_svn_string_array(svn_temp_serializer__context_t *context, 593251881Speter const svn_string_t ***strings, 594251881Speter apr_size_t count) 595251881Speter{ 596251881Speter apr_size_t i; 597251881Speter const svn_string_t **entries = *strings; 598251881Speter 599251881Speter /* serialize COUNT entries pointers (the array) */ 600251881Speter svn_temp_serializer__push(context, 601251881Speter (const void * const *)strings, 602251881Speter count * sizeof(const char*)); 603251881Speter 604251881Speter /* serialize array elements */ 605251881Speter for (i = 0; i < count; ++i) 606251881Speter serialize_svn_string(context, &entries[i]); 607251881Speter 608251881Speter svn_temp_serializer__pop(context); 609251881Speter} 610251881Speter 611251881Spetersvn_error_t * 612251881Spetersvn_fs_fs__serialize_properties(void **data, 613251881Speter apr_size_t *data_len, 614251881Speter void *in, 615251881Speter apr_pool_t *pool) 616251881Speter{ 617251881Speter apr_hash_t *hash = in; 618251881Speter properties_data_t properties; 619251881Speter svn_temp_serializer__context_t *context; 620251881Speter apr_hash_index_t *hi; 621251881Speter svn_stringbuf_t *serialized; 622251881Speter apr_size_t i; 623251881Speter 624251881Speter /* create our auxilliary data structure */ 625251881Speter properties.count = apr_hash_count(hash); 626251881Speter properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1)); 627251881Speter properties.values = apr_palloc(pool, sizeof(const char*) * properties.count); 628251881Speter 629251881Speter /* populate it with the hash entries */ 630251881Speter for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i) 631251881Speter { 632251881Speter properties.keys[i] = svn__apr_hash_index_key(hi); 633251881Speter properties.values[i] = svn__apr_hash_index_val(hi); 634251881Speter } 635251881Speter 636251881Speter /* serialize it */ 637251881Speter context = svn_temp_serializer__init(&properties, 638251881Speter sizeof(properties), 639251881Speter properties.count * 100, 640251881Speter pool); 641251881Speter 642251881Speter properties.keys[i] = ""; 643251881Speter serialize_cstring_array(context, &properties.keys, properties.count + 1); 644251881Speter serialize_svn_string_array(context, &properties.values, properties.count); 645251881Speter 646251881Speter /* return the serialized result */ 647251881Speter serialized = svn_temp_serializer__get(context); 648251881Speter 649251881Speter *data = serialized->data; 650251881Speter *data_len = serialized->len; 651251881Speter 652251881Speter return SVN_NO_ERROR; 653251881Speter} 654251881Speter 655251881Spetersvn_error_t * 656251881Spetersvn_fs_fs__deserialize_properties(void **out, 657251881Speter void *data, 658251881Speter apr_size_t data_len, 659251881Speter apr_pool_t *pool) 660251881Speter{ 661251881Speter apr_hash_t *hash = svn_hash__make(pool); 662251881Speter properties_data_t *properties = (properties_data_t *)data; 663251881Speter size_t i; 664251881Speter 665251881Speter /* de-serialize our auxilliary data structure */ 666251881Speter svn_temp_deserializer__resolve(properties, (void**)&properties->keys); 667251881Speter svn_temp_deserializer__resolve(properties, (void**)&properties->values); 668251881Speter 669251881Speter /* de-serialize each entry and put it into the hash */ 670251881Speter for (i = 0; i < properties->count; ++i) 671251881Speter { 672251881Speter apr_size_t len = properties->keys[i+1] - properties->keys[i] - 1; 673251881Speter svn_temp_deserializer__resolve((void*)properties->keys, 674251881Speter (void**)&properties->keys[i]); 675251881Speter 676251881Speter deserialize_svn_string((void*)properties->values, 677251881Speter (svn_string_t **)&properties->values[i]); 678251881Speter 679251881Speter apr_hash_set(hash, 680251881Speter properties->keys[i], len, 681251881Speter properties->values[i]); 682251881Speter } 683251881Speter 684251881Speter /* done */ 685251881Speter *out = hash; 686251881Speter 687251881Speter return SVN_NO_ERROR; 688251881Speter} 689251881Speter 690251881Spetersvn_error_t * 691251881Spetersvn_fs_fs__serialize_id(void **data, 692251881Speter apr_size_t *data_len, 693251881Speter void *in, 694251881Speter apr_pool_t *pool) 695251881Speter{ 696251881Speter const svn_fs_id_t *id = in; 697251881Speter svn_stringbuf_t *serialized; 698251881Speter 699251881Speter /* create an (empty) serialization context with plenty of buffer space */ 700251881Speter svn_temp_serializer__context_t *context = 701251881Speter svn_temp_serializer__init(NULL, 0, 250, pool); 702251881Speter 703251881Speter /* serialize the id */ 704251881Speter svn_fs_fs__id_serialize(context, &id); 705251881Speter 706251881Speter /* return serialized data */ 707251881Speter serialized = svn_temp_serializer__get(context); 708251881Speter *data = serialized->data; 709251881Speter *data_len = serialized->len; 710251881Speter 711251881Speter return SVN_NO_ERROR; 712251881Speter} 713251881Speter 714251881Spetersvn_error_t * 715251881Spetersvn_fs_fs__deserialize_id(void **out, 716251881Speter void *data, 717251881Speter apr_size_t data_len, 718251881Speter apr_pool_t *pool) 719251881Speter{ 720251881Speter /* Copy the _full_ buffer as it also contains the sub-structures. */ 721251881Speter svn_fs_id_t *id = (svn_fs_id_t *)data; 722251881Speter 723251881Speter /* fixup of all pointers etc. */ 724251881Speter svn_fs_fs__id_deserialize(id, &id); 725251881Speter 726251881Speter /* done */ 727251881Speter *out = id; 728251881Speter return SVN_NO_ERROR; 729251881Speter} 730251881Speter 731251881Speter/** Caching node_revision_t objects. **/ 732251881Speter 733251881Spetersvn_error_t * 734251881Spetersvn_fs_fs__serialize_node_revision(void **buffer, 735251881Speter apr_size_t *buffer_size, 736251881Speter void *item, 737251881Speter apr_pool_t *pool) 738251881Speter{ 739251881Speter svn_stringbuf_t *serialized; 740251881Speter node_revision_t *noderev = item; 741251881Speter 742251881Speter /* create an (empty) serialization context with plenty of (initial) 743251881Speter * buffer space. */ 744251881Speter svn_temp_serializer__context_t *context = 745251881Speter svn_temp_serializer__init(NULL, 0, 746251881Speter 1024 - SVN_TEMP_SERIALIZER__OVERHEAD, 747251881Speter pool); 748251881Speter 749251881Speter /* serialize the noderev */ 750251881Speter svn_fs_fs__noderev_serialize(context, &noderev); 751251881Speter 752251881Speter /* return serialized data */ 753251881Speter serialized = svn_temp_serializer__get(context); 754251881Speter *buffer = serialized->data; 755251881Speter *buffer_size = serialized->len; 756251881Speter 757251881Speter return SVN_NO_ERROR; 758251881Speter} 759251881Speter 760251881Spetersvn_error_t * 761251881Spetersvn_fs_fs__deserialize_node_revision(void **item, 762251881Speter void *buffer, 763251881Speter apr_size_t buffer_size, 764251881Speter apr_pool_t *pool) 765251881Speter{ 766251881Speter /* Copy the _full_ buffer as it also contains the sub-structures. */ 767251881Speter node_revision_t *noderev = (node_revision_t *)buffer; 768251881Speter 769251881Speter /* fixup of all pointers etc. */ 770251881Speter svn_fs_fs__noderev_deserialize(noderev, &noderev); 771251881Speter 772251881Speter /* done */ 773251881Speter *item = noderev; 774251881Speter return SVN_NO_ERROR; 775251881Speter} 776251881Speter 777251881Speter/* Utility function that returns the directory serialized inside CONTEXT 778251881Speter * to DATA and DATA_LEN. */ 779251881Speterstatic svn_error_t * 780251881Speterreturn_serialized_dir_context(svn_temp_serializer__context_t *context, 781251881Speter void **data, 782251881Speter apr_size_t *data_len) 783251881Speter{ 784251881Speter svn_stringbuf_t *serialized = svn_temp_serializer__get(context); 785251881Speter 786251881Speter *data = serialized->data; 787251881Speter *data_len = serialized->blocksize; 788251881Speter ((hash_data_t *)serialized->data)->len = serialized->len; 789251881Speter 790251881Speter return SVN_NO_ERROR; 791251881Speter} 792251881Speter 793251881Spetersvn_error_t * 794251881Spetersvn_fs_fs__serialize_dir_entries(void **data, 795251881Speter apr_size_t *data_len, 796251881Speter void *in, 797251881Speter apr_pool_t *pool) 798251881Speter{ 799251881Speter apr_hash_t *dir = in; 800251881Speter 801251881Speter /* serialize the dir content into a new serialization context 802251881Speter * and return the serialized data */ 803251881Speter return return_serialized_dir_context(serialize_dir(dir, pool), 804251881Speter data, 805251881Speter data_len); 806251881Speter} 807251881Speter 808251881Spetersvn_error_t * 809251881Spetersvn_fs_fs__deserialize_dir_entries(void **out, 810251881Speter void *data, 811251881Speter apr_size_t data_len, 812251881Speter apr_pool_t *pool) 813251881Speter{ 814251881Speter /* Copy the _full_ buffer as it also contains the sub-structures. */ 815251881Speter hash_data_t *hash_data = (hash_data_t *)data; 816251881Speter 817251881Speter /* reconstruct the hash from the serialized data */ 818251881Speter *out = deserialize_dir(hash_data, hash_data, pool); 819251881Speter 820251881Speter return SVN_NO_ERROR; 821251881Speter} 822251881Speter 823251881Spetersvn_error_t * 824251881Spetersvn_fs_fs__get_sharded_offset(void **out, 825251881Speter const void *data, 826251881Speter apr_size_t data_len, 827251881Speter void *baton, 828251881Speter apr_pool_t *pool) 829251881Speter{ 830251881Speter const apr_off_t *manifest = data; 831251881Speter apr_int64_t shard_pos = *(apr_int64_t *)baton; 832251881Speter 833251881Speter *(apr_off_t *)out = manifest[shard_pos]; 834251881Speter 835251881Speter return SVN_NO_ERROR; 836251881Speter} 837251881Speter 838251881Speter/* Utility function that returns the lowest index of the first entry in 839251881Speter * *ENTRIES that points to a dir entry with a name equal or larger than NAME. 840251881Speter * If an exact match has been found, *FOUND will be set to TRUE. COUNT is 841251881Speter * the number of valid entries in ENTRIES. 842251881Speter */ 843251881Speterstatic apr_size_t 844251881Speterfind_entry(svn_fs_dirent_t **entries, 845251881Speter const char *name, 846251881Speter apr_size_t count, 847251881Speter svn_boolean_t *found) 848251881Speter{ 849251881Speter /* binary search for the desired entry by name */ 850251881Speter apr_size_t lower = 0; 851251881Speter apr_size_t upper = count; 852251881Speter apr_size_t middle; 853251881Speter 854251881Speter for (middle = upper / 2; lower < upper; middle = (upper + lower) / 2) 855251881Speter { 856251881Speter const svn_fs_dirent_t *entry = 857251881Speter svn_temp_deserializer__ptr(entries, (const void *const *)&entries[middle]); 858251881Speter const char* entry_name = 859251881Speter svn_temp_deserializer__ptr(entry, (const void *const *)&entry->name); 860251881Speter 861251881Speter int diff = strcmp(entry_name, name); 862251881Speter if (diff < 0) 863251881Speter lower = middle + 1; 864251881Speter else 865251881Speter upper = middle; 866251881Speter } 867251881Speter 868251881Speter /* check whether we actually found a match */ 869251881Speter *found = FALSE; 870251881Speter if (lower < count) 871251881Speter { 872251881Speter const svn_fs_dirent_t *entry = 873251881Speter svn_temp_deserializer__ptr(entries, (const void *const *)&entries[lower]); 874251881Speter const char* entry_name = 875251881Speter svn_temp_deserializer__ptr(entry, (const void *const *)&entry->name); 876251881Speter 877251881Speter if (strcmp(entry_name, name) == 0) 878251881Speter *found = TRUE; 879251881Speter } 880251881Speter 881251881Speter return lower; 882251881Speter} 883251881Speter 884251881Spetersvn_error_t * 885251881Spetersvn_fs_fs__extract_dir_entry(void **out, 886251881Speter const void *data, 887251881Speter apr_size_t data_len, 888251881Speter void *baton, 889251881Speter apr_pool_t *pool) 890251881Speter{ 891251881Speter const hash_data_t *hash_data = data; 892251881Speter const char* name = baton; 893251881Speter svn_boolean_t found; 894251881Speter 895251881Speter /* resolve the reference to the entries array */ 896251881Speter const svn_fs_dirent_t * const *entries = 897251881Speter svn_temp_deserializer__ptr(data, (const void *const *)&hash_data->entries); 898251881Speter 899251881Speter /* resolve the reference to the lengths array */ 900251881Speter const apr_uint32_t *lengths = 901251881Speter svn_temp_deserializer__ptr(data, (const void *const *)&hash_data->lengths); 902251881Speter 903251881Speter /* binary search for the desired entry by name */ 904251881Speter apr_size_t pos = find_entry((svn_fs_dirent_t **)entries, 905251881Speter name, 906251881Speter hash_data->count, 907251881Speter &found); 908251881Speter 909251881Speter /* de-serialize that entry or return NULL, if no match has been found */ 910251881Speter *out = NULL; 911251881Speter if (found) 912251881Speter { 913251881Speter const svn_fs_dirent_t *source = 914251881Speter svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]); 915251881Speter 916251881Speter /* Entries have been serialized one-by-one, each time including all 917251881Speter * nested structures and strings. Therefore, they occupy a single 918251881Speter * block of memory whose end-offset is either the beginning of the 919251881Speter * next entry or the end of the buffer 920251881Speter */ 921251881Speter apr_size_t size = lengths[pos]; 922251881Speter 923251881Speter /* copy & deserialize the entry */ 924251881Speter svn_fs_dirent_t *new_entry = apr_palloc(pool, size); 925251881Speter memcpy(new_entry, source, size); 926251881Speter 927251881Speter svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name); 928251881Speter svn_fs_fs__id_deserialize(new_entry, (svn_fs_id_t **)&new_entry->id); 929251881Speter *(svn_fs_dirent_t **)out = new_entry; 930251881Speter } 931251881Speter 932251881Speter return SVN_NO_ERROR; 933251881Speter} 934251881Speter 935251881Speter/* Utility function for svn_fs_fs__replace_dir_entry that implements the 936251881Speter * modification as a simply deserialize / modify / serialize sequence. 937251881Speter */ 938251881Speterstatic svn_error_t * 939251881Speterslowly_replace_dir_entry(void **data, 940251881Speter apr_size_t *data_len, 941251881Speter void *baton, 942251881Speter apr_pool_t *pool) 943251881Speter{ 944251881Speter replace_baton_t *replace_baton = (replace_baton_t *)baton; 945251881Speter hash_data_t *hash_data = (hash_data_t *)*data; 946251881Speter apr_hash_t *dir; 947251881Speter 948251881Speter SVN_ERR(svn_fs_fs__deserialize_dir_entries((void **)&dir, 949251881Speter *data, 950251881Speter hash_data->len, 951251881Speter pool)); 952251881Speter svn_hash_sets(dir, replace_baton->name, replace_baton->new_entry); 953251881Speter 954251881Speter return svn_fs_fs__serialize_dir_entries(data, data_len, dir, pool); 955251881Speter} 956251881Speter 957251881Spetersvn_error_t * 958251881Spetersvn_fs_fs__replace_dir_entry(void **data, 959251881Speter apr_size_t *data_len, 960251881Speter void *baton, 961251881Speter apr_pool_t *pool) 962251881Speter{ 963251881Speter replace_baton_t *replace_baton = (replace_baton_t *)baton; 964251881Speter hash_data_t *hash_data = (hash_data_t *)*data; 965251881Speter svn_boolean_t found; 966251881Speter svn_fs_dirent_t **entries; 967251881Speter apr_uint32_t *lengths; 968251881Speter apr_uint32_t length; 969251881Speter apr_size_t pos; 970251881Speter 971251881Speter svn_temp_serializer__context_t *context; 972251881Speter 973251881Speter /* after quite a number of operations, let's re-pack everything. 974251881Speter * This is to limit the number of vasted space as we cannot overwrite 975251881Speter * existing data but must always append. */ 976251881Speter if (hash_data->operations > 2 + hash_data->count / 4) 977251881Speter return slowly_replace_dir_entry(data, data_len, baton, pool); 978251881Speter 979251881Speter /* resolve the reference to the entries array */ 980251881Speter entries = (svn_fs_dirent_t **) 981251881Speter svn_temp_deserializer__ptr((const char *)hash_data, 982251881Speter (const void *const *)&hash_data->entries); 983251881Speter 984251881Speter /* resolve the reference to the lengths array */ 985251881Speter lengths = (apr_uint32_t *) 986251881Speter svn_temp_deserializer__ptr((const char *)hash_data, 987251881Speter (const void *const *)&hash_data->lengths); 988251881Speter 989251881Speter /* binary search for the desired entry by name */ 990251881Speter pos = find_entry(entries, replace_baton->name, hash_data->count, &found); 991251881Speter 992251881Speter /* handle entry removal (if found at all) */ 993251881Speter if (replace_baton->new_entry == NULL) 994251881Speter { 995251881Speter if (found) 996251881Speter { 997251881Speter /* remove reference to the entry from the index */ 998251881Speter memmove(&entries[pos], 999251881Speter &entries[pos + 1], 1000251881Speter sizeof(entries[pos]) * (hash_data->count - pos)); 1001251881Speter memmove(&lengths[pos], 1002251881Speter &lengths[pos + 1], 1003251881Speter sizeof(lengths[pos]) * (hash_data->count - pos)); 1004251881Speter 1005251881Speter hash_data->count--; 1006251881Speter hash_data->over_provision++; 1007251881Speter hash_data->operations++; 1008251881Speter } 1009251881Speter 1010251881Speter return SVN_NO_ERROR; 1011251881Speter } 1012251881Speter 1013251881Speter /* if not found, prepare to insert the new entry */ 1014251881Speter if (!found) 1015251881Speter { 1016251881Speter /* fallback to slow operation if there is no place left to insert an 1017251881Speter * new entry to index. That will automatically give add some spare 1018251881Speter * entries ("overprovision"). */ 1019251881Speter if (hash_data->over_provision == 0) 1020251881Speter return slowly_replace_dir_entry(data, data_len, baton, pool); 1021251881Speter 1022251881Speter /* make entries[index] available for pointing to the new entry */ 1023251881Speter memmove(&entries[pos + 1], 1024251881Speter &entries[pos], 1025251881Speter sizeof(entries[pos]) * (hash_data->count - pos)); 1026251881Speter memmove(&lengths[pos + 1], 1027251881Speter &lengths[pos], 1028251881Speter sizeof(lengths[pos]) * (hash_data->count - pos)); 1029251881Speter 1030251881Speter hash_data->count++; 1031251881Speter hash_data->over_provision--; 1032251881Speter hash_data->operations++; 1033251881Speter } 1034251881Speter 1035251881Speter /* de-serialize the new entry */ 1036251881Speter entries[pos] = replace_baton->new_entry; 1037251881Speter context = svn_temp_serializer__init_append(hash_data, 1038251881Speter entries, 1039251881Speter hash_data->len, 1040251881Speter *data_len, 1041251881Speter pool); 1042251881Speter serialize_dir_entry(context, &entries[pos], &length); 1043251881Speter 1044251881Speter /* return the updated serialized data */ 1045251881Speter SVN_ERR (return_serialized_dir_context(context, 1046251881Speter data, 1047251881Speter data_len)); 1048251881Speter 1049251881Speter /* since the previous call may have re-allocated the buffer, the lengths 1050251881Speter * pointer may no longer point to the entry in that buffer. Therefore, 1051251881Speter * re-map it again and store the length value after that. */ 1052251881Speter 1053251881Speter hash_data = (hash_data_t *)*data; 1054251881Speter lengths = (apr_uint32_t *) 1055251881Speter svn_temp_deserializer__ptr((const char *)hash_data, 1056251881Speter (const void *const *)&hash_data->lengths); 1057251881Speter lengths[pos] = length; 1058251881Speter 1059251881Speter return SVN_NO_ERROR; 1060251881Speter} 1061251881Speter 1062251881Speter/* Utility function to serialize change CHANGE_P in the given serialization 1063251881Speter * CONTEXT. 1064251881Speter */ 1065251881Speterstatic void 1066251881Speterserialize_change(svn_temp_serializer__context_t *context, 1067251881Speter change_t * const *change_p) 1068251881Speter{ 1069251881Speter const change_t * change = *change_p; 1070251881Speter if (change == NULL) 1071251881Speter return; 1072251881Speter 1073251881Speter /* serialize the change struct itself */ 1074251881Speter svn_temp_serializer__push(context, 1075251881Speter (const void * const *)change_p, 1076251881Speter sizeof(*change)); 1077251881Speter 1078251881Speter /* serialize sub-structures */ 1079251881Speter svn_fs_fs__id_serialize(context, &change->noderev_id); 1080251881Speter 1081251881Speter svn_temp_serializer__add_string(context, &change->path); 1082251881Speter svn_temp_serializer__add_string(context, &change->copyfrom_path); 1083251881Speter 1084251881Speter /* return to the caller's nesting level */ 1085251881Speter svn_temp_serializer__pop(context); 1086251881Speter} 1087251881Speter 1088251881Speter/* Utility function to serialize the CHANGE_P within the given 1089251881Speter * serialization CONTEXT. 1090251881Speter */ 1091251881Speterstatic void 1092251881Speterdeserialize_change(void *buffer, change_t **change_p) 1093251881Speter{ 1094251881Speter change_t * change; 1095251881Speter 1096251881Speter /* fix-up of the pointer to the struct in question */ 1097251881Speter svn_temp_deserializer__resolve(buffer, (void **)change_p); 1098251881Speter 1099251881Speter change = *change_p; 1100251881Speter if (change == NULL) 1101251881Speter return; 1102251881Speter 1103251881Speter /* fix-up of sub-structures */ 1104251881Speter svn_fs_fs__id_deserialize(change, (svn_fs_id_t **)&change->noderev_id); 1105251881Speter 1106251881Speter svn_temp_deserializer__resolve(change, (void **)&change->path); 1107251881Speter svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path); 1108251881Speter} 1109251881Speter 1110251881Speter/* Auxiliary structure representing the content of a change_t array. 1111251881Speter This structure is much easier to (de-)serialize than an APR array. 1112251881Speter */ 1113251881Spetertypedef struct changes_data_t 1114251881Speter{ 1115251881Speter /* number of entries in the array */ 1116251881Speter int count; 1117251881Speter 1118251881Speter /* reference to the changes */ 1119251881Speter change_t **changes; 1120251881Speter} changes_data_t; 1121251881Speter 1122251881Spetersvn_error_t * 1123251881Spetersvn_fs_fs__serialize_changes(void **data, 1124251881Speter apr_size_t *data_len, 1125251881Speter void *in, 1126251881Speter apr_pool_t *pool) 1127251881Speter{ 1128251881Speter apr_array_header_t *array = in; 1129251881Speter changes_data_t changes; 1130251881Speter svn_temp_serializer__context_t *context; 1131251881Speter svn_stringbuf_t *serialized; 1132251881Speter int i; 1133251881Speter 1134251881Speter /* initialize our auxiliary data structure */ 1135251881Speter changes.count = array->nelts; 1136251881Speter changes.changes = apr_palloc(pool, sizeof(change_t*) * changes.count); 1137251881Speter 1138251881Speter /* populate it with the array elements */ 1139251881Speter for (i = 0; i < changes.count; ++i) 1140251881Speter changes.changes[i] = APR_ARRAY_IDX(array, i, change_t*); 1141251881Speter 1142251881Speter /* serialize it and all its elements */ 1143251881Speter context = svn_temp_serializer__init(&changes, 1144251881Speter sizeof(changes), 1145251881Speter changes.count * 100, 1146251881Speter pool); 1147251881Speter 1148251881Speter svn_temp_serializer__push(context, 1149251881Speter (const void * const *)&changes.changes, 1150251881Speter changes.count * sizeof(change_t*)); 1151251881Speter 1152251881Speter for (i = 0; i < changes.count; ++i) 1153251881Speter serialize_change(context, &changes.changes[i]); 1154251881Speter 1155251881Speter svn_temp_serializer__pop(context); 1156251881Speter 1157251881Speter /* return the serialized result */ 1158251881Speter serialized = svn_temp_serializer__get(context); 1159251881Speter 1160251881Speter *data = serialized->data; 1161251881Speter *data_len = serialized->len; 1162251881Speter 1163251881Speter return SVN_NO_ERROR; 1164251881Speter} 1165251881Speter 1166251881Spetersvn_error_t * 1167251881Spetersvn_fs_fs__deserialize_changes(void **out, 1168251881Speter void *data, 1169251881Speter apr_size_t data_len, 1170251881Speter apr_pool_t *pool) 1171251881Speter{ 1172251881Speter int i; 1173251881Speter changes_data_t *changes = (changes_data_t *)data; 1174251881Speter apr_array_header_t *array = apr_array_make(pool, changes->count, 1175251881Speter sizeof(change_t *)); 1176251881Speter 1177251881Speter /* de-serialize our auxiliary data structure */ 1178251881Speter svn_temp_deserializer__resolve(changes, (void**)&changes->changes); 1179251881Speter 1180251881Speter /* de-serialize each entry and add it to the array */ 1181251881Speter for (i = 0; i < changes->count; ++i) 1182251881Speter { 1183251881Speter deserialize_change((void*)changes->changes, 1184251881Speter (change_t **)&changes->changes[i]); 1185251881Speter APR_ARRAY_PUSH(array, change_t *) = changes->changes[i]; 1186251881Speter } 1187251881Speter 1188251881Speter /* done */ 1189251881Speter *out = array; 1190251881Speter 1191251881Speter return SVN_NO_ERROR; 1192251881Speter} 1193251881Speter 1194251881Speter/* Auxiliary structure representing the content of a svn_mergeinfo_t hash. 1195251881Speter This structure is much easier to (de-)serialize than an APR array. 1196251881Speter */ 1197251881Spetertypedef struct mergeinfo_data_t 1198251881Speter{ 1199251881Speter /* number of paths in the hash */ 1200251881Speter unsigned count; 1201251881Speter 1202251881Speter /* COUNT keys (paths) */ 1203251881Speter const char **keys; 1204251881Speter 1205251881Speter /* COUNT keys lengths (strlen of path) */ 1206251881Speter apr_ssize_t *key_lengths; 1207251881Speter 1208251881Speter /* COUNT entries, each giving the number of ranges for the key */ 1209251881Speter int *range_counts; 1210251881Speter 1211251881Speter /* all ranges in a single, concatenated buffer */ 1212251881Speter svn_merge_range_t *ranges; 1213251881Speter} mergeinfo_data_t; 1214251881Speter 1215251881Spetersvn_error_t * 1216251881Spetersvn_fs_fs__serialize_mergeinfo(void **data, 1217251881Speter apr_size_t *data_len, 1218251881Speter void *in, 1219251881Speter apr_pool_t *pool) 1220251881Speter{ 1221251881Speter svn_mergeinfo_t mergeinfo = in; 1222251881Speter mergeinfo_data_t merges; 1223251881Speter svn_temp_serializer__context_t *context; 1224251881Speter svn_stringbuf_t *serialized; 1225251881Speter apr_hash_index_t *hi; 1226251881Speter unsigned i; 1227251881Speter int k; 1228251881Speter apr_size_t range_count; 1229251881Speter 1230251881Speter /* initialize our auxiliary data structure */ 1231251881Speter merges.count = apr_hash_count(mergeinfo); 1232251881Speter merges.keys = apr_palloc(pool, sizeof(*merges.keys) * merges.count); 1233251881Speter merges.key_lengths = apr_palloc(pool, sizeof(*merges.key_lengths) * 1234251881Speter merges.count); 1235251881Speter merges.range_counts = apr_palloc(pool, sizeof(*merges.range_counts) * 1236251881Speter merges.count); 1237251881Speter 1238251881Speter i = 0; 1239251881Speter range_count = 0; 1240251881Speter for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi), ++i) 1241251881Speter { 1242251881Speter svn_rangelist_t *ranges; 1243251881Speter apr_hash_this(hi, (const void**)&merges.keys[i], 1244251881Speter &merges.key_lengths[i], 1245251881Speter (void **)&ranges); 1246251881Speter merges.range_counts[i] = ranges->nelts; 1247251881Speter range_count += ranges->nelts; 1248251881Speter } 1249251881Speter 1250251881Speter merges.ranges = apr_palloc(pool, sizeof(*merges.ranges) * range_count); 1251251881Speter 1252251881Speter i = 0; 1253251881Speter for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi)) 1254251881Speter { 1255251881Speter svn_rangelist_t *ranges = svn__apr_hash_index_val(hi); 1256251881Speter for (k = 0; k < ranges->nelts; ++k, ++i) 1257251881Speter merges.ranges[i] = *APR_ARRAY_IDX(ranges, k, svn_merge_range_t*); 1258251881Speter } 1259251881Speter 1260251881Speter /* serialize it and all its elements */ 1261251881Speter context = svn_temp_serializer__init(&merges, 1262251881Speter sizeof(merges), 1263251881Speter range_count * 30, 1264251881Speter pool); 1265251881Speter 1266251881Speter /* keys array */ 1267251881Speter svn_temp_serializer__push(context, 1268251881Speter (const void * const *)&merges.keys, 1269251881Speter merges.count * sizeof(*merges.keys)); 1270251881Speter 1271251881Speter for (i = 0; i < merges.count; ++i) 1272251881Speter svn_temp_serializer__add_string(context, &merges.keys[i]); 1273251881Speter 1274251881Speter svn_temp_serializer__pop(context); 1275251881Speter 1276251881Speter /* key lengths array */ 1277251881Speter svn_temp_serializer__push(context, 1278251881Speter (const void * const *)&merges.key_lengths, 1279251881Speter merges.count * sizeof(*merges.key_lengths)); 1280251881Speter svn_temp_serializer__pop(context); 1281251881Speter 1282251881Speter /* range counts array */ 1283251881Speter svn_temp_serializer__push(context, 1284251881Speter (const void * const *)&merges.range_counts, 1285251881Speter merges.count * sizeof(*merges.range_counts)); 1286251881Speter svn_temp_serializer__pop(context); 1287251881Speter 1288251881Speter /* ranges */ 1289251881Speter svn_temp_serializer__push(context, 1290251881Speter (const void * const *)&merges.ranges, 1291251881Speter range_count * sizeof(*merges.ranges)); 1292251881Speter svn_temp_serializer__pop(context); 1293251881Speter 1294251881Speter /* return the serialized result */ 1295251881Speter serialized = svn_temp_serializer__get(context); 1296251881Speter 1297251881Speter *data = serialized->data; 1298251881Speter *data_len = serialized->len; 1299251881Speter 1300251881Speter return SVN_NO_ERROR; 1301251881Speter} 1302251881Speter 1303251881Spetersvn_error_t * 1304251881Spetersvn_fs_fs__deserialize_mergeinfo(void **out, 1305251881Speter void *data, 1306251881Speter apr_size_t data_len, 1307251881Speter apr_pool_t *pool) 1308251881Speter{ 1309251881Speter unsigned i; 1310251881Speter int k, n; 1311251881Speter mergeinfo_data_t *merges = (mergeinfo_data_t *)data; 1312251881Speter svn_mergeinfo_t mergeinfo; 1313251881Speter 1314251881Speter /* de-serialize our auxiliary data structure */ 1315251881Speter svn_temp_deserializer__resolve(merges, (void**)&merges->keys); 1316251881Speter svn_temp_deserializer__resolve(merges, (void**)&merges->key_lengths); 1317251881Speter svn_temp_deserializer__resolve(merges, (void**)&merges->range_counts); 1318251881Speter svn_temp_deserializer__resolve(merges, (void**)&merges->ranges); 1319251881Speter 1320251881Speter /* de-serialize keys and add entries to the result */ 1321251881Speter n = 0; 1322251881Speter mergeinfo = svn_hash__make(pool); 1323251881Speter for (i = 0; i < merges->count; ++i) 1324251881Speter { 1325251881Speter svn_rangelist_t *ranges = apr_array_make(pool, 1326251881Speter merges->range_counts[i], 1327251881Speter sizeof(svn_merge_range_t*)); 1328251881Speter for (k = 0; k < merges->range_counts[i]; ++k, ++n) 1329251881Speter APR_ARRAY_PUSH(ranges, svn_merge_range_t*) = &merges->ranges[n]; 1330251881Speter 1331251881Speter svn_temp_deserializer__resolve((void*)merges->keys, 1332251881Speter (void**)&merges->keys[i]); 1333251881Speter apr_hash_set(mergeinfo, merges->keys[i], merges->key_lengths[i], ranges); 1334251881Speter } 1335251881Speter 1336251881Speter /* done */ 1337251881Speter *out = mergeinfo; 1338251881Speter 1339251881Speter return SVN_NO_ERROR; 1340251881Speter} 1341251881Speter 1342