temp_serializer.c (302408) | temp_serializer.c (362181) |
---|---|
1/* temp_serializer.c: serialization functions for caching of FSX structures 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the --- 57 unchanged lines hidden (view full) --- 66 67 /* return the last written position */ 68 return key_buffer; 69} 70 71const char* 72svn_fs_x__combine_number_and_string(apr_int64_t number, 73 const char *string, | 1/* temp_serializer.c: serialization functions for caching of FSX structures 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the --- 57 unchanged lines hidden (view full) --- 66 67 /* return the last written position */ 68 return key_buffer; 69} 70 71const char* 72svn_fs_x__combine_number_and_string(apr_int64_t number, 73 const char *string, |
74 apr_pool_t *pool) | 74 apr_pool_t *result_pool) |
75{ 76 apr_size_t len = strlen(string); 77 78 /* number part requires max. 10x7 bits + 1 space. 79 * Add another 1 for the terminal 0 */ | 75{ 76 apr_size_t len = strlen(string); 77 78 /* number part requires max. 10x7 bits + 1 space. 79 * Add another 1 for the terminal 0 */ |
80 char *key_buffer = apr_palloc(pool, len + 12); | 80 char *key_buffer = apr_palloc(result_pool, len + 12); |
81 const char *key = key_buffer; 82 83 /* Prepend the number to the string and separate them by space. No other 84 * number can result in the same prefix, no other string in the same 85 * postfix nor can the boundary between them be ambiguous. */ 86 key_buffer = encode_number(number, key_buffer); 87 *++key_buffer = ' '; 88 memcpy(++key_buffer, string, len+1); --- 26 unchanged lines hidden (view full) --- 115 116 /* back to the caller's nesting level */ 117 svn_temp_serializer__pop(context); 118} 119 120/* Utility function to deserialize the STRING inside the BUFFER. 121 */ 122static void | 81 const char *key = key_buffer; 82 83 /* Prepend the number to the string and separate them by space. No other 84 * number can result in the same prefix, no other string in the same 85 * postfix nor can the boundary between them be ambiguous. */ 86 key_buffer = encode_number(number, key_buffer); 87 *++key_buffer = ' '; 88 memcpy(++key_buffer, string, len+1); --- 26 unchanged lines hidden (view full) --- 115 116 /* back to the caller's nesting level */ 117 svn_temp_serializer__pop(context); 118} 119 120/* Utility function to deserialize the STRING inside the BUFFER. 121 */ 122static void |
123deserialize_svn_string(void *buffer, svn_string_t **string) | 123deserialize_svn_string(const void *buffer, svn_string_t **string) |
124{ 125 svn_temp_deserializer__resolve(buffer, (void **)string); 126 if (*string == NULL) 127 return; 128 129 svn_temp_deserializer__resolve(*string, (void **)&(*string)->data); 130} 131 --- 36 unchanged lines hidden (view full) --- 168 169 /* back to the caller's nesting level */ 170 svn_temp_serializer__pop(context); 171} 172 173void 174svn_fs_x__deserialize_apr_array(void *buffer, 175 apr_array_header_t **array, | 124{ 125 svn_temp_deserializer__resolve(buffer, (void **)string); 126 if (*string == NULL) 127 return; 128 129 svn_temp_deserializer__resolve(*string, (void **)&(*string)->data); 130} 131 --- 36 unchanged lines hidden (view full) --- 168 169 /* back to the caller's nesting level */ 170 svn_temp_serializer__pop(context); 171} 172 173void 174svn_fs_x__deserialize_apr_array(void *buffer, 175 apr_array_header_t **array, |
176 apr_pool_t *pool) | 176 apr_pool_t *result_pool) |
177{ 178 svn_temp_deserializer__resolve(buffer, (void **)array); 179 if (*array == NULL) 180 return; 181 182 svn_temp_deserializer__resolve(*array, (void **)&(*array)->elts); | 177{ 178 svn_temp_deserializer__resolve(buffer, (void **)array); 179 if (*array == NULL) 180 return; 181 182 svn_temp_deserializer__resolve(*array, (void **)&(*array)->elts); |
183 (*array)->pool = pool; | 183 (*array)->pool = result_pool; |
184} 185 186/* auxilliary structure representing the content of a directory array */ 187typedef struct dir_data_t 188{ 189 /* number of entries in the directory 190 * (it's int because the directory is an APR array) */ 191 int count; 192 | 184} 185 186/* auxilliary structure representing the content of a directory array */ 187typedef struct dir_data_t 188{ 189 /* number of entries in the directory 190 * (it's int because the directory is an APR array) */ 191 int count; 192 |
193 /** Current length of the in-txn in-disk representation of the directory. 194 * SVN_INVALID_FILESIZE if unknown (i.e. committed data). */ 195 svn_filesize_t txn_filesize; 196 |
|
193 /* number of unused dir entry buckets in the index */ 194 apr_size_t over_provision; 195 196 /* internal modifying operations counter 197 * (used to repack data once in a while) */ 198 apr_size_t operations; 199 200 /* size of the serialization buffer actually used. --- 18 unchanged lines hidden (view full) --- 219 svn_fs_x__dirent_t **entry_p, 220 apr_uint32_t *length) 221{ 222 svn_fs_x__dirent_t *entry = *entry_p; 223 apr_size_t initial_length = svn_temp_serializer__get_length(context); 224 225 svn_temp_serializer__push(context, 226 (const void * const *)entry_p, | 197 /* number of unused dir entry buckets in the index */ 198 apr_size_t over_provision; 199 200 /* internal modifying operations counter 201 * (used to repack data once in a while) */ 202 apr_size_t operations; 203 204 /* size of the serialization buffer actually used. --- 18 unchanged lines hidden (view full) --- 223 svn_fs_x__dirent_t **entry_p, 224 apr_uint32_t *length) 225{ 226 svn_fs_x__dirent_t *entry = *entry_p; 227 apr_size_t initial_length = svn_temp_serializer__get_length(context); 228 229 svn_temp_serializer__push(context, 230 (const void * const *)entry_p, |
227 sizeof(svn_fs_x__dirent_t)); | 231 sizeof(**entry_p)); |
228 229 svn_temp_serializer__add_string(context, &entry->name); 230 231 *length = (apr_uint32_t)( svn_temp_serializer__get_length(context) 232 - APR_ALIGN_DEFAULT(initial_length)); 233 234 svn_temp_serializer__pop(context); 235} 236 | 232 233 svn_temp_serializer__add_string(context, &entry->name); 234 235 *length = (apr_uint32_t)( svn_temp_serializer__get_length(context) 236 - APR_ALIGN_DEFAULT(initial_length)); 237 238 svn_temp_serializer__pop(context); 239} 240 |
237/* Utility function to serialize the ENTRIES into a new serialization | 241/* Utility function to serialize the DIR into a new serialization |
238 * context to be returned. 239 * 240 * Temporary allocation will be made form SCRATCH_POOL. 241 */ 242static svn_temp_serializer__context_t * | 242 * context to be returned. 243 * 244 * Temporary allocation will be made form SCRATCH_POOL. 245 */ 246static svn_temp_serializer__context_t * |
243serialize_dir(apr_array_header_t *entries, | 247serialize_dir(svn_fs_x__dir_data_t *dir, |
244 apr_pool_t *scratch_pool) 245{ 246 dir_data_t dir_data; 247 int i = 0; 248 svn_temp_serializer__context_t *context; | 248 apr_pool_t *scratch_pool) 249{ 250 dir_data_t dir_data; 251 int i = 0; 252 svn_temp_serializer__context_t *context; |
253 apr_array_header_t *entries = dir->entries; |
|
249 250 /* calculate sizes */ 251 int count = entries->nelts; 252 apr_size_t over_provision = 2 + count / 4; 253 apr_size_t entries_len = (count + over_provision) 254 * sizeof(svn_fs_x__dirent_t*); 255 apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t); 256 | 254 255 /* calculate sizes */ 256 int count = entries->nelts; 257 apr_size_t over_provision = 2 + count / 4; 258 apr_size_t entries_len = (count + over_provision) 259 * sizeof(svn_fs_x__dirent_t*); 260 apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t); 261 |
262 /* Estimate the size of a directory entry + its name. */ 263 enum { ENTRY_SIZE = sizeof(svn_fs_x__dirent_t) + 32 }; 264 |
|
257 /* copy the hash entries to an auxiliary struct of known layout */ 258 dir_data.count = count; | 265 /* copy the hash entries to an auxiliary struct of known layout */ 266 dir_data.count = count; |
267 dir_data.txn_filesize = dir->txn_filesize; |
|
259 dir_data.over_provision = over_provision; 260 dir_data.operations = 0; 261 dir_data.entries = apr_palloc(scratch_pool, entries_len); 262 dir_data.lengths = apr_palloc(scratch_pool, lengths_len); 263 264 for (i = 0; i < count; ++i) 265 dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_x__dirent_t *); 266 267 /* Serialize that aux. structure into a new one. Also, provide a good 268 * estimate for the size of the buffer that we will need. */ 269 context = svn_temp_serializer__init(&dir_data, 270 sizeof(dir_data), | 268 dir_data.over_provision = over_provision; 269 dir_data.operations = 0; 270 dir_data.entries = apr_palloc(scratch_pool, entries_len); 271 dir_data.lengths = apr_palloc(scratch_pool, lengths_len); 272 273 for (i = 0; i < count; ++i) 274 dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_x__dirent_t *); 275 276 /* Serialize that aux. structure into a new one. Also, provide a good 277 * estimate for the size of the buffer that we will need. */ 278 context = svn_temp_serializer__init(&dir_data, 279 sizeof(dir_data), |
271 50 + count * 200 + entries_len, | 280 50 + count * ENTRY_SIZE 281 + entries_len + lengths_len, |
272 scratch_pool); 273 274 /* serialize entries references */ 275 svn_temp_serializer__push(context, 276 (const void * const *)&dir_data.entries, 277 entries_len); 278 279 /* serialize the individual entries and their sub-structures */ --- 7 unchanged lines hidden (view full) --- 287 /* serialize entries references */ 288 svn_temp_serializer__push(context, 289 (const void * const *)&dir_data.lengths, 290 lengths_len); 291 292 return context; 293} 294 | 282 scratch_pool); 283 284 /* serialize entries references */ 285 svn_temp_serializer__push(context, 286 (const void * const *)&dir_data.entries, 287 entries_len); 288 289 /* serialize the individual entries and their sub-structures */ --- 7 unchanged lines hidden (view full) --- 297 /* serialize entries references */ 298 svn_temp_serializer__push(context, 299 (const void * const *)&dir_data.lengths, 300 lengths_len); 301 302 return context; 303} 304 |
295/* Utility function to reconstruct a dir entries array from serialized data 296 * in BUFFER and DIR_DATA. Allocation will be made form POOL. | 305/* Utility function to reconstruct a dir entries struct from serialized data 306 * in BUFFER and DIR_DATA. Allocation will be made form RESULT_POOL. |
297 */ | 307 */ |
298static apr_array_header_t * 299deserialize_dir(void *buffer, dir_data_t *dir_data, apr_pool_t *pool) | 308static svn_fs_x__dir_data_t * 309deserialize_dir(void *buffer, 310 dir_data_t *dir_data, 311 apr_pool_t *result_pool) |
300{ | 312{ |
301 apr_array_header_t *result 302 = apr_array_make(pool, dir_data->count, sizeof(svn_fs_x__dirent_t *)); | 313 svn_fs_x__dir_data_t *result; |
303 apr_size_t i; 304 apr_size_t count; 305 svn_fs_x__dirent_t *entry; 306 svn_fs_x__dirent_t **entries; 307 | 314 apr_size_t i; 315 apr_size_t count; 316 svn_fs_x__dirent_t *entry; 317 svn_fs_x__dirent_t **entries; 318 |
319 /* Construct empty directory object. */ 320 result = apr_pcalloc(result_pool, sizeof(*result)); 321 result->entries 322 = apr_array_make(result_pool, dir_data->count, 323 sizeof(svn_fs_x__dirent_t *)); 324 result->txn_filesize = dir_data->txn_filesize; 325 |
|
308 /* resolve the reference to the entries array */ 309 svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries); 310 entries = dir_data->entries; 311 | 326 /* resolve the reference to the entries array */ 327 svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries); 328 entries = dir_data->entries; 329 |
312 /* fixup the references within each entry and add it to the hash */ | 330 /* fixup the references within each entry and add it to the RESULT */ |
313 for (i = 0, count = dir_data->count; i < count; ++i) 314 { 315 svn_temp_deserializer__resolve(entries, (void **)&entries[i]); 316 entry = dir_data->entries[i]; 317 318 /* pointer fixup */ 319 svn_temp_deserializer__resolve(entry, (void **)&entry->name); 320 321 /* add the entry to the hash */ | 331 for (i = 0, count = dir_data->count; i < count; ++i) 332 { 333 svn_temp_deserializer__resolve(entries, (void **)&entries[i]); 334 entry = dir_data->entries[i]; 335 336 /* pointer fixup */ 337 svn_temp_deserializer__resolve(entry, (void **)&entry->name); 338 339 /* add the entry to the hash */ |
322 APR_ARRAY_PUSH(result, svn_fs_x__dirent_t *) = entry; | 340 APR_ARRAY_PUSH(result->entries, svn_fs_x__dirent_t *) = entry; |
323 } 324 325 /* return the now complete hash */ 326 return result; 327} 328 | 341 } 342 343 /* return the now complete hash */ 344 return result; 345} 346 |
329void 330svn_fs_x__noderev_serialize(svn_temp_serializer__context_t *context, 331 svn_fs_x__noderev_t * const *noderev_p) | 347/** 348 * Serialize a NODEREV_P within the serialization CONTEXT. 349 */ 350static void 351noderev_serialize(svn_temp_serializer__context_t *context, 352 svn_fs_x__noderev_t * const *noderev_p) |
332{ 333 const svn_fs_x__noderev_t *noderev = *noderev_p; 334 if (noderev == NULL) 335 return; 336 337 /* serialize the representation struct itself */ 338 svn_temp_serializer__push(context, 339 (const void * const *)noderev_p, --- 6 unchanged lines hidden (view full) --- 346 svn_temp_serializer__add_string(context, &noderev->copyfrom_path); 347 svn_temp_serializer__add_string(context, &noderev->copyroot_path); 348 svn_temp_serializer__add_string(context, &noderev->created_path); 349 350 /* return to the caller's nesting level */ 351 svn_temp_serializer__pop(context); 352} 353 | 353{ 354 const svn_fs_x__noderev_t *noderev = *noderev_p; 355 if (noderev == NULL) 356 return; 357 358 /* serialize the representation struct itself */ 359 svn_temp_serializer__push(context, 360 (const void * const *)noderev_p, --- 6 unchanged lines hidden (view full) --- 367 svn_temp_serializer__add_string(context, &noderev->copyfrom_path); 368 svn_temp_serializer__add_string(context, &noderev->copyroot_path); 369 svn_temp_serializer__add_string(context, &noderev->created_path); 370 371 /* return to the caller's nesting level */ 372 svn_temp_serializer__pop(context); 373} 374 |
354 355void 356svn_fs_x__noderev_deserialize(void *buffer, 357 svn_fs_x__noderev_t **noderev_p, 358 apr_pool_t *pool) | 375/** 376 * Deserialize a NODEREV_P within the BUFFER and associate it with. 377 */ 378static void 379noderev_deserialize(void *buffer, 380 svn_fs_x__noderev_t **noderev_p) |
359{ 360 svn_fs_x__noderev_t *noderev; 361 362 /* fixup the reference to the representation itself, 363 * if this is part of a parent structure. */ 364 if (buffer != *noderev_p) 365 svn_temp_deserializer__resolve(buffer, (void **)noderev_p); 366 --- 79 unchanged lines hidden (view full) --- 446 447 return SVN_NO_ERROR; 448} 449 450svn_error_t * 451svn_fs_x__deserialize_txdelta_window(void **item, 452 void *buffer, 453 apr_size_t buffer_size, | 381{ 382 svn_fs_x__noderev_t *noderev; 383 384 /* fixup the reference to the representation itself, 385 * if this is part of a parent structure. */ 386 if (buffer != *noderev_p) 387 svn_temp_deserializer__resolve(buffer, (void **)noderev_p); 388 --- 79 unchanged lines hidden (view full) --- 468 469 return SVN_NO_ERROR; 470} 471 472svn_error_t * 473svn_fs_x__deserialize_txdelta_window(void **item, 474 void *buffer, 475 apr_size_t buffer_size, |
454 apr_pool_t *pool) | 476 apr_pool_t *result_pool) |
455{ 456 svn_txdelta_window_t *window; 457 458 /* Copy the _full_ buffer as it also contains the sub-structures. */ 459 svn_fs_x__txdelta_cached_window_t *window_info = 460 (svn_fs_x__txdelta_cached_window_t *)buffer; 461 462 /* pointer reference fixup */ --- 6 unchanged lines hidden (view full) --- 469 deserialize_svn_string(window, (svn_string_t**)&window->new_data); 470 471 /* done */ 472 *item = window_info; 473 474 return SVN_NO_ERROR; 475} 476 | 477{ 478 svn_txdelta_window_t *window; 479 480 /* Copy the _full_ buffer as it also contains the sub-structures. */ 481 svn_fs_x__txdelta_cached_window_t *window_info = 482 (svn_fs_x__txdelta_cached_window_t *)buffer; 483 484 /* pointer reference fixup */ --- 6 unchanged lines hidden (view full) --- 491 deserialize_svn_string(window, (svn_string_t**)&window->new_data); 492 493 /* done */ 494 *item = window_info; 495 496 return SVN_NO_ERROR; 497} 498 |
477svn_error_t * 478svn_fs_x__serialize_manifest(void **data, 479 apr_size_t *data_len, 480 void *in, 481 apr_pool_t *pool) 482{ 483 apr_array_header_t *manifest = in; 484 485 *data_len = sizeof(apr_off_t) *manifest->nelts; 486 *data = apr_palloc(pool, *data_len); 487 memcpy(*data, manifest->elts, *data_len); 488 489 return SVN_NO_ERROR; 490} 491 492svn_error_t * 493svn_fs_x__deserialize_manifest(void **out, 494 void *data, 495 apr_size_t data_len, 496 apr_pool_t *pool) 497{ 498 apr_array_header_t *manifest = apr_array_make(pool, 1, sizeof(apr_off_t)); 499 500 manifest->nelts = (int) (data_len / sizeof(apr_off_t)); 501 manifest->nalloc = (int) (data_len / sizeof(apr_off_t)); 502 manifest->elts = (char*)data; 503 504 *out = manifest; 505 506 return SVN_NO_ERROR; 507} 508 | |
509/* Auxiliary structure representing the content of a properties hash. 510 This structure is much easier to (de-)serialize than an apr_hash. 511 */ 512typedef struct properties_data_t 513{ 514 /* number of entries in the hash */ 515 apr_size_t count; 516 --- 57 unchanged lines hidden (view full) --- 574 svn_temp_serializer__context_t *context; 575 apr_hash_index_t *hi; 576 svn_stringbuf_t *serialized; 577 apr_size_t i; 578 579 /* create our auxiliary data structure */ 580 properties.count = apr_hash_count(hash); 581 properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1)); | 499/* Auxiliary structure representing the content of a properties hash. 500 This structure is much easier to (de-)serialize than an apr_hash. 501 */ 502typedef struct properties_data_t 503{ 504 /* number of entries in the hash */ 505 apr_size_t count; 506 --- 57 unchanged lines hidden (view full) --- 564 svn_temp_serializer__context_t *context; 565 apr_hash_index_t *hi; 566 svn_stringbuf_t *serialized; 567 apr_size_t i; 568 569 /* create our auxiliary data structure */ 570 properties.count = apr_hash_count(hash); 571 properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1)); |
582 properties.values = apr_palloc(pool, sizeof(const char*) * properties.count); | 572 properties.values = apr_palloc(pool, sizeof(const svn_string_t *) * properties.count); |
583 584 /* populate it with the hash entries */ 585 for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i) 586 { 587 properties.keys[i] = apr_hash_this_key(hi); 588 properties.values[i] = apr_hash_this_val(hi); 589 } 590 --- 15 unchanged lines hidden (view full) --- 606 607 return SVN_NO_ERROR; 608} 609 610svn_error_t * 611svn_fs_x__deserialize_properties(void **out, 612 void *data, 613 apr_size_t data_len, | 573 574 /* populate it with the hash entries */ 575 for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i) 576 { 577 properties.keys[i] = apr_hash_this_key(hi); 578 properties.values[i] = apr_hash_this_val(hi); 579 } 580 --- 15 unchanged lines hidden (view full) --- 596 597 return SVN_NO_ERROR; 598} 599 600svn_error_t * 601svn_fs_x__deserialize_properties(void **out, 602 void *data, 603 apr_size_t data_len, |
614 apr_pool_t *pool) | 604 apr_pool_t *result_pool) |
615{ | 605{ |
616 apr_hash_t *hash = svn_hash__make(pool); | 606 apr_hash_t *hash = svn_hash__make(result_pool); |
617 properties_data_t *properties = (properties_data_t *)data; 618 size_t i; 619 620 /* de-serialize our auxiliary data structure */ 621 svn_temp_deserializer__resolve(properties, (void**)&properties->keys); 622 svn_temp_deserializer__resolve(properties, (void**)&properties->values); 623 624 /* de-serialize each entry and put it into the hash */ --- 31 unchanged lines hidden (view full) --- 656 /* create an (empty) serialization context with plenty of (initial) 657 * buffer space. */ 658 svn_temp_serializer__context_t *context = 659 svn_temp_serializer__init(NULL, 0, 660 1024 - SVN_TEMP_SERIALIZER__OVERHEAD, 661 pool); 662 663 /* serialize the noderev */ | 607 properties_data_t *properties = (properties_data_t *)data; 608 size_t i; 609 610 /* de-serialize our auxiliary data structure */ 611 svn_temp_deserializer__resolve(properties, (void**)&properties->keys); 612 svn_temp_deserializer__resolve(properties, (void**)&properties->values); 613 614 /* de-serialize each entry and put it into the hash */ --- 31 unchanged lines hidden (view full) --- 646 /* create an (empty) serialization context with plenty of (initial) 647 * buffer space. */ 648 svn_temp_serializer__context_t *context = 649 svn_temp_serializer__init(NULL, 0, 650 1024 - SVN_TEMP_SERIALIZER__OVERHEAD, 651 pool); 652 653 /* serialize the noderev */ |
664 svn_fs_x__noderev_serialize(context, &noderev); | 654 noderev_serialize(context, &noderev); |
665 666 /* return serialized data */ 667 serialized = svn_temp_serializer__get(context); 668 *buffer = serialized->data; 669 *buffer_size = serialized->len; 670 671 return SVN_NO_ERROR; 672} 673 674svn_error_t * 675svn_fs_x__deserialize_node_revision(void **item, 676 void *buffer, 677 apr_size_t buffer_size, | 655 656 /* return serialized data */ 657 serialized = svn_temp_serializer__get(context); 658 *buffer = serialized->data; 659 *buffer_size = serialized->len; 660 661 return SVN_NO_ERROR; 662} 663 664svn_error_t * 665svn_fs_x__deserialize_node_revision(void **item, 666 void *buffer, 667 apr_size_t buffer_size, |
678 apr_pool_t *pool) | 668 apr_pool_t *result_pool) |
679{ 680 /* Copy the _full_ buffer as it also contains the sub-structures. */ 681 svn_fs_x__noderev_t *noderev = (svn_fs_x__noderev_t *)buffer; 682 683 /* fixup of all pointers etc. */ | 669{ 670 /* Copy the _full_ buffer as it also contains the sub-structures. */ 671 svn_fs_x__noderev_t *noderev = (svn_fs_x__noderev_t *)buffer; 672 673 /* fixup of all pointers etc. */ |
684 svn_fs_x__noderev_deserialize(noderev, &noderev, pool); | 674 noderev_deserialize(noderev, &noderev); |
685 686 /* done */ 687 *item = noderev; 688 return SVN_NO_ERROR; 689} 690 691/* Utility function that returns the directory serialized inside CONTEXT | 675 676 /* done */ 677 *item = noderev; 678 return SVN_NO_ERROR; 679} 680 681/* Utility function that returns the directory serialized inside CONTEXT |
692 * to DATA and DATA_LEN. */ | 682 * to DATA and DATA_LEN. If OVERPROVISION is set, allocate some extra 683 * room for future in-place changes by svn_fs_x__replace_dir_entry. */ |
693static svn_error_t * 694return_serialized_dir_context(svn_temp_serializer__context_t *context, 695 void **data, | 684static svn_error_t * 685return_serialized_dir_context(svn_temp_serializer__context_t *context, 686 void **data, |
696 apr_size_t *data_len) | 687 apr_size_t *data_len, 688 svn_boolean_t overprovision) |
697{ 698 svn_stringbuf_t *serialized = svn_temp_serializer__get(context); 699 700 *data = serialized->data; | 689{ 690 svn_stringbuf_t *serialized = svn_temp_serializer__get(context); 691 692 *data = serialized->data; |
701 *data_len = serialized->blocksize; | 693 *data_len = overprovision ? serialized->blocksize : serialized->len; |
702 ((dir_data_t *)serialized->data)->len = serialized->len; 703 704 return SVN_NO_ERROR; 705} 706 707svn_error_t * 708svn_fs_x__serialize_dir_entries(void **data, 709 apr_size_t *data_len, 710 void *in, 711 apr_pool_t *pool) 712{ | 694 ((dir_data_t *)serialized->data)->len = serialized->len; 695 696 return SVN_NO_ERROR; 697} 698 699svn_error_t * 700svn_fs_x__serialize_dir_entries(void **data, 701 apr_size_t *data_len, 702 void *in, 703 apr_pool_t *pool) 704{ |
713 apr_array_header_t *dir = in; | 705 svn_fs_x__dir_data_t *dir = in; |
714 715 /* serialize the dir content into a new serialization context 716 * and return the serialized data */ 717 return return_serialized_dir_context(serialize_dir(dir, pool), 718 data, | 706 707 /* serialize the dir content into a new serialization context 708 * and return the serialized data */ 709 return return_serialized_dir_context(serialize_dir(dir, pool), 710 data, |
719 data_len); | 711 data_len, 712 FALSE); |
720} 721 722svn_error_t * 723svn_fs_x__deserialize_dir_entries(void **out, 724 void *data, 725 apr_size_t data_len, | 713} 714 715svn_error_t * 716svn_fs_x__deserialize_dir_entries(void **out, 717 void *data, 718 apr_size_t data_len, |
726 apr_pool_t *pool) | 719 apr_pool_t *result_pool) |
727{ 728 /* Copy the _full_ buffer as it also contains the sub-structures. */ 729 dir_data_t *dir_data = (dir_data_t *)data; 730 731 /* reconstruct the hash from the serialized data */ | 720{ 721 /* Copy the _full_ buffer as it also contains the sub-structures. */ 722 dir_data_t *dir_data = (dir_data_t *)data; 723 724 /* reconstruct the hash from the serialized data */ |
732 *out = deserialize_dir(dir_data, dir_data, pool); | 725 *out = deserialize_dir(dir_data, dir_data, result_pool); |
733 734 return SVN_NO_ERROR; 735} 736 737svn_error_t * 738svn_fs_x__get_sharded_offset(void **out, 739 const void *data, 740 apr_size_t data_len, 741 void *baton, 742 apr_pool_t *pool) 743{ 744 const apr_off_t *manifest = data; 745 apr_int64_t shard_pos = *(apr_int64_t *)baton; 746 747 *(apr_off_t *)out = manifest[shard_pos]; 748 749 return SVN_NO_ERROR; 750} 751 | 726 727 return SVN_NO_ERROR; 728} 729 730svn_error_t * 731svn_fs_x__get_sharded_offset(void **out, 732 const void *data, 733 apr_size_t data_len, 734 void *baton, 735 apr_pool_t *pool) 736{ 737 const apr_off_t *manifest = data; 738 apr_int64_t shard_pos = *(apr_int64_t *)baton; 739 740 *(apr_off_t *)out = manifest[shard_pos]; 741 742 return SVN_NO_ERROR; 743} 744 |
745svn_error_t * 746svn_fs_x__extract_dir_filesize(void **out, 747 const void *data, 748 apr_size_t data_len, 749 void *baton, 750 apr_pool_t *pool) 751{ 752 const dir_data_t *dir_data = data; 753 754 *(svn_filesize_t *)out = dir_data->txn_filesize; 755 756 return SVN_NO_ERROR; 757} 758 |
|
752/* Utility function that returns the lowest index of the first entry in 753 * *ENTRIES that points to a dir entry with a name equal or larger than NAME. 754 * If an exact match has been found, *FOUND will be set to TRUE. COUNT is 755 * the number of valid entries in ENTRIES. 756 */ 757static apr_size_t 758find_entry(svn_fs_x__dirent_t **entries, 759 const char *name, --- 67 unchanged lines hidden (view full) --- 827 /* resolve the reference to the entries array */ 828 const svn_fs_x__dirent_t * const *entries = 829 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries); 830 831 /* resolve the reference to the lengths array */ 832 const apr_uint32_t *lengths = 833 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths); 834 | 759/* Utility function that returns the lowest index of the first entry in 760 * *ENTRIES that points to a dir entry with a name equal or larger than NAME. 761 * If an exact match has been found, *FOUND will be set to TRUE. COUNT is 762 * the number of valid entries in ENTRIES. 763 */ 764static apr_size_t 765find_entry(svn_fs_x__dirent_t **entries, 766 const char *name, --- 67 unchanged lines hidden (view full) --- 834 /* resolve the reference to the entries array */ 835 const svn_fs_x__dirent_t * const *entries = 836 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries); 837 838 /* resolve the reference to the lengths array */ 839 const apr_uint32_t *lengths = 840 svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths); 841 |
842 /* Before we return, make sure we tell the caller this data is even still 843 relevant. */ 844 b->out_of_date = dir_data->txn_filesize != b->txn_filesize; 845 |
|
835 /* Special case: Early out for empty directories. 836 That simplifies tests further down the road. */ 837 *out = NULL; 838 if (dir_data->count == 0) 839 return SVN_NO_ERROR; 840 841 /* HINT _might_ be the position we hit last time. 842 If within valid range, check whether HINT+1 is a hit. */ --- 10 unchanged lines hidden (view full) --- 853 pos = find_entry((svn_fs_x__dirent_t **)entries, b->name, 854 dir_data->count, &found); 855 } 856 857 /* Remember the hit index - if we FOUND the entry. */ 858 if (found) 859 b->hint = pos; 860 | 846 /* Special case: Early out for empty directories. 847 That simplifies tests further down the road. */ 848 *out = NULL; 849 if (dir_data->count == 0) 850 return SVN_NO_ERROR; 851 852 /* HINT _might_ be the position we hit last time. 853 If within valid range, check whether HINT+1 is a hit. */ --- 10 unchanged lines hidden (view full) --- 864 pos = find_entry((svn_fs_x__dirent_t **)entries, b->name, 865 dir_data->count, &found); 866 } 867 868 /* Remember the hit index - if we FOUND the entry. */ 869 if (found) 870 b->hint = pos; 871 |
861 /* de-serialize that entry or return NULL, if no match has been found */ 862 if (found) | 872 /* de-serialize that entry or return NULL, if no match has been found. 873 * Be sure to check that the directory contents is still up-to-date. */ 874 if (found && !b->out_of_date) |
863 { 864 const svn_fs_x__dirent_t *source = 865 svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]); 866 867 /* Entries have been serialized one-by-one, each time including all 868 * nested structures and strings. Therefore, they occupy a single 869 * block of memory whose end-offset is either the beginning of the 870 * next entry or the end of the buffer 871 */ 872 apr_size_t size = lengths[pos]; 873 874 /* copy & deserialize the entry */ | 875 { 876 const svn_fs_x__dirent_t *source = 877 svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]); 878 879 /* Entries have been serialized one-by-one, each time including all 880 * nested structures and strings. Therefore, they occupy a single 881 * block of memory whose end-offset is either the beginning of the 882 * next entry or the end of the buffer 883 */ 884 apr_size_t size = lengths[pos]; 885 886 /* copy & deserialize the entry */ |
875 svn_fs_x__dirent_t *new_entry = apr_palloc(pool, size); 876 memcpy(new_entry, source, size); | 887 svn_fs_x__dirent_t *new_entry = apr_pmemdup(pool, source, size); |
877 878 svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name); 879 *(svn_fs_x__dirent_t **)out = new_entry; 880 } 881 882 return SVN_NO_ERROR; 883} 884 885/* Utility function for svn_fs_x__replace_dir_entry that implements the 886 * modification as a simply deserialize / modify / serialize sequence. 887 */ 888static svn_error_t * 889slowly_replace_dir_entry(void **data, 890 apr_size_t *data_len, 891 void *baton, 892 apr_pool_t *pool) 893{ 894 replace_baton_t *replace_baton = (replace_baton_t *)baton; 895 dir_data_t *dir_data = (dir_data_t *)*data; | 888 889 svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name); 890 *(svn_fs_x__dirent_t **)out = new_entry; 891 } 892 893 return SVN_NO_ERROR; 894} 895 896/* Utility function for svn_fs_x__replace_dir_entry that implements the 897 * modification as a simply deserialize / modify / serialize sequence. 898 */ 899static svn_error_t * 900slowly_replace_dir_entry(void **data, 901 apr_size_t *data_len, 902 void *baton, 903 apr_pool_t *pool) 904{ 905 replace_baton_t *replace_baton = (replace_baton_t *)baton; 906 dir_data_t *dir_data = (dir_data_t *)*data; |
896 apr_array_header_t *dir; | 907 svn_fs_x__dir_data_t *dir; |
897 int idx = -1; 898 svn_fs_x__dirent_t *entry; | 908 int idx = -1; 909 svn_fs_x__dirent_t *entry; |
910 apr_array_header_t *entries; |
|
899 900 SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir, 901 *data, 902 dir_data->len, 903 pool)); 904 | 911 912 SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir, 913 *data, 914 dir_data->len, 915 pool)); 916 |
905 entry = svn_fs_x__find_dir_entry(dir, replace_baton->name, &idx); | 917 entries = dir->entries; 918 entry = svn_fs_x__find_dir_entry(entries, replace_baton->name, &idx); |
906 907 /* Replacement or removal? */ 908 if (replace_baton->new_entry) 909 { 910 /* Replace ENTRY with / insert the NEW_ENTRY */ 911 if (entry) | 919 920 /* Replacement or removal? */ 921 if (replace_baton->new_entry) 922 { 923 /* Replace ENTRY with / insert the NEW_ENTRY */ 924 if (entry) |
912 APR_ARRAY_IDX(dir, idx, svn_fs_x__dirent_t *) | 925 APR_ARRAY_IDX(entries, idx, svn_fs_x__dirent_t *) |
913 = replace_baton->new_entry; 914 else | 926 = replace_baton->new_entry; 927 else |
915 svn_sort__array_insert(dir, &replace_baton->new_entry, idx); | 928 SVN_ERR(svn_sort__array_insert2(entries, &replace_baton->new_entry, idx)); |
916 } 917 else 918 { 919 /* Remove the old ENTRY. */ 920 if (entry) | 929 } 930 else 931 { 932 /* Remove the old ENTRY. */ 933 if (entry) |
921 svn_sort__array_delete(dir, idx, 1); | 934 SVN_ERR(svn_sort__array_delete2(entries, idx, 1)); |
922 } 923 924 return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool); 925} 926 927svn_error_t * 928svn_fs_x__replace_dir_entry(void **data, 929 apr_size_t *data_len, --- 5 unchanged lines hidden (view full) --- 935 svn_boolean_t found; 936 svn_fs_x__dirent_t **entries; 937 apr_uint32_t *lengths; 938 apr_uint32_t length; 939 apr_size_t pos; 940 941 svn_temp_serializer__context_t *context; 942 | 935 } 936 937 return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool); 938} 939 940svn_error_t * 941svn_fs_x__replace_dir_entry(void **data, 942 apr_size_t *data_len, --- 5 unchanged lines hidden (view full) --- 948 svn_boolean_t found; 949 svn_fs_x__dirent_t **entries; 950 apr_uint32_t *lengths; 951 apr_uint32_t length; 952 apr_size_t pos; 953 954 svn_temp_serializer__context_t *context; 955 |
956 /* update the cached file length info. 957 * Because we are writing to the cache, it is fair to assume that the 958 * caller made sure that the current contents is consistent with the 959 * previous state of the directory file. */ 960 dir_data->txn_filesize = replace_baton->txn_filesize; 961 |
|
943 /* after quite a number of operations, let's re-pack everything. 944 * This is to limit the number of wasted space as we cannot overwrite 945 * existing data but must always append. */ 946 if (dir_data->operations > 2 + dir_data->count / 4) 947 return slowly_replace_dir_entry(data, data_len, baton, pool); 948 949 /* resolve the reference to the entries array */ 950 entries = (svn_fs_x__dirent_t **) --- 56 unchanged lines hidden (view full) --- 1007 context = svn_temp_serializer__init_append(dir_data, 1008 entries, 1009 dir_data->len, 1010 *data_len, 1011 pool); 1012 serialize_dir_entry(context, &entries[pos], &length); 1013 1014 /* return the updated serialized data */ | 962 /* after quite a number of operations, let's re-pack everything. 963 * This is to limit the number of wasted space as we cannot overwrite 964 * existing data but must always append. */ 965 if (dir_data->operations > 2 + dir_data->count / 4) 966 return slowly_replace_dir_entry(data, data_len, baton, pool); 967 968 /* resolve the reference to the entries array */ 969 entries = (svn_fs_x__dirent_t **) --- 56 unchanged lines hidden (view full) --- 1026 context = svn_temp_serializer__init_append(dir_data, 1027 entries, 1028 dir_data->len, 1029 *data_len, 1030 pool); 1031 serialize_dir_entry(context, &entries[pos], &length); 1032 1033 /* return the updated serialized data */ |
1015 SVN_ERR (return_serialized_dir_context(context, 1016 data, 1017 data_len)); | 1034 SVN_ERR(return_serialized_dir_context(context, data, data_len, TRUE)); |
1018 1019 /* since the previous call may have re-allocated the buffer, the lengths 1020 * pointer may no longer point to the entry in that buffer. Therefore, 1021 * re-map it again and store the length value after that. */ 1022 1023 dir_data = (dir_data_t *)*data; 1024 lengths = (apr_uint32_t *) 1025 svn_temp_deserializer__ptr((const char *)dir_data, 1026 (const void *const *)&dir_data->lengths); 1027 lengths[pos] = length; 1028 1029 return SVN_NO_ERROR; 1030} 1031 | 1035 1036 /* since the previous call may have re-allocated the buffer, the lengths 1037 * pointer may no longer point to the entry in that buffer. Therefore, 1038 * re-map it again and store the length value after that. */ 1039 1040 dir_data = (dir_data_t *)*data; 1041 lengths = (apr_uint32_t *) 1042 svn_temp_deserializer__ptr((const char *)dir_data, 1043 (const void *const *)&dir_data->lengths); 1044 lengths[pos] = length; 1045 1046 return SVN_NO_ERROR; 1047} 1048 |
1049svn_error_t * 1050svn_fs_x__reset_txn_filesize(void **data, 1051 apr_size_t *data_len, 1052 void *baton, 1053 apr_pool_t *pool) 1054{ 1055 dir_data_t *dir_data = (dir_data_t *)*data; 1056 dir_data->txn_filesize = SVN_INVALID_FILESIZE; 1057 1058 return SVN_NO_ERROR; 1059} 1060 |
|
1032svn_error_t * 1033svn_fs_x__serialize_rep_header(void **data, 1034 apr_size_t *data_len, 1035 void *in, 1036 apr_pool_t *pool) 1037{ | 1061svn_error_t * 1062svn_fs_x__serialize_rep_header(void **data, 1063 apr_size_t *data_len, 1064 void *in, 1065 apr_pool_t *pool) 1066{ |
1038 svn_fs_x__rep_header_t *copy = apr_palloc(pool, sizeof(*copy)); 1039 *copy = *(svn_fs_x__rep_header_t *)in; 1040 | |
1041 *data_len = sizeof(svn_fs_x__rep_header_t); | 1067 *data_len = sizeof(svn_fs_x__rep_header_t); |
1042 *data = copy; | 1068 *data = in; |
1043 1044 return SVN_NO_ERROR; 1045} 1046 1047svn_error_t * 1048svn_fs_x__deserialize_rep_header(void **out, 1049 void *data, 1050 apr_size_t data_len, | 1069 1070 return SVN_NO_ERROR; 1071} 1072 1073svn_error_t * 1074svn_fs_x__deserialize_rep_header(void **out, 1075 void *data, 1076 apr_size_t data_len, |
1051 apr_pool_t *pool) | 1077 apr_pool_t *result_pool) |
1052{ | 1078{ |
1053 svn_fs_x__rep_header_t *copy = apr_palloc(pool, sizeof(*copy)); 1054 SVN_ERR_ASSERT(data_len == sizeof(*copy)); 1055 1056 *copy = *(svn_fs_x__rep_header_t *)data; | |
1057 *out = data; 1058 1059 return SVN_NO_ERROR; 1060} 1061 1062/* Utility function to serialize change CHANGE_P in the given serialization 1063 * CONTEXT. 1064 */ --- 18 unchanged lines hidden (view full) --- 1083 svn_temp_serializer__pop(context); 1084} 1085 1086/* Utility function to serialize the CHANGE_P within the given 1087 * serialization CONTEXT. 1088 */ 1089static void 1090deserialize_change(void *buffer, | 1079 *out = data; 1080 1081 return SVN_NO_ERROR; 1082} 1083 1084/* Utility function to serialize change CHANGE_P in the given serialization 1085 * CONTEXT. 1086 */ --- 18 unchanged lines hidden (view full) --- 1105 svn_temp_serializer__pop(context); 1106} 1107 1108/* Utility function to serialize the CHANGE_P within the given 1109 * serialization CONTEXT. 1110 */ 1111static void 1112deserialize_change(void *buffer, |
1091 svn_fs_x__change_t **change_p, 1092 apr_pool_t *pool) | 1113 svn_fs_x__change_t **change_p) |
1093{ 1094 svn_fs_x__change_t * change; 1095 1096 /* fix-up of the pointer to the struct in question */ 1097 svn_temp_deserializer__resolve(buffer, (void **)change_p); 1098 1099 change = *change_p; 1100 if (change == NULL) 1101 return; 1102 1103 /* fix-up of sub-structures */ 1104 svn_temp_deserializer__resolve(change, (void **)&change->path.data); 1105 svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path); 1106} 1107 | 1114{ 1115 svn_fs_x__change_t * change; 1116 1117 /* fix-up of the pointer to the struct in question */ 1118 svn_temp_deserializer__resolve(buffer, (void **)change_p); 1119 1120 change = *change_p; 1121 if (change == NULL) 1122 return; 1123 1124 /* fix-up of sub-structures */ 1125 svn_temp_deserializer__resolve(change, (void **)&change->path.data); 1126 svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path); 1127} 1128 |
1108/* Auxiliary structure representing the content of a svn_fs_x__change_t array. 1109 This structure is much easier to (de-)serialize than an APR array. 1110 */ 1111typedef struct changes_data_t 1112{ 1113 /* number of entries in the array */ 1114 int count; 1115 1116 /* reference to the changes */ 1117 svn_fs_x__change_t **changes; 1118} changes_data_t; 1119 | |
1120svn_error_t * 1121svn_fs_x__serialize_changes(void **data, 1122 apr_size_t *data_len, 1123 void *in, 1124 apr_pool_t *pool) 1125{ | 1129svn_error_t * 1130svn_fs_x__serialize_changes(void **data, 1131 apr_size_t *data_len, 1132 void *in, 1133 apr_pool_t *pool) 1134{ |
1126 apr_array_header_t *array = in; 1127 changes_data_t changes; | 1135 svn_fs_x__changes_list_t *changes = in; |
1128 svn_temp_serializer__context_t *context; 1129 svn_stringbuf_t *serialized; 1130 int i; 1131 | 1136 svn_temp_serializer__context_t *context; 1137 svn_stringbuf_t *serialized; 1138 int i; 1139 |
1132 /* initialize our auxiliary data structure and link it to the 1133 * array elements */ 1134 changes.count = array->nelts; 1135 changes.changes = (svn_fs_x__change_t **)array->elts; 1136 | |
1137 /* serialize it and all its elements */ | 1140 /* serialize it and all its elements */ |
1138 context = svn_temp_serializer__init(&changes, 1139 sizeof(changes), 1140 changes.count * 250, | 1141 context = svn_temp_serializer__init(changes, 1142 sizeof(*changes), 1143 changes->count * 250, |
1141 pool); 1142 1143 svn_temp_serializer__push(context, | 1144 pool); 1145 1146 svn_temp_serializer__push(context, |
1144 (const void * const *)&changes.changes, 1145 changes.count * sizeof(svn_fs_x__change_t*)); | 1147 (const void * const *)&changes->changes, 1148 changes->count * sizeof(*changes->changes)); |
1146 | 1149 |
1147 for (i = 0; i < changes.count; ++i) 1148 serialize_change(context, &changes.changes[i]); | 1150 for (i = 0; i < changes->count; ++i) 1151 serialize_change(context, &changes->changes[i]); |
1149 1150 svn_temp_serializer__pop(context); 1151 1152 /* return the serialized result */ 1153 serialized = svn_temp_serializer__get(context); 1154 1155 *data = serialized->data; 1156 *data_len = serialized->len; 1157 1158 return SVN_NO_ERROR; 1159} 1160 1161svn_error_t * 1162svn_fs_x__deserialize_changes(void **out, 1163 void *data, 1164 apr_size_t data_len, | 1152 1153 svn_temp_serializer__pop(context); 1154 1155 /* return the serialized result */ 1156 serialized = svn_temp_serializer__get(context); 1157 1158 *data = serialized->data; 1159 *data_len = serialized->len; 1160 1161 return SVN_NO_ERROR; 1162} 1163 1164svn_error_t * 1165svn_fs_x__deserialize_changes(void **out, 1166 void *data, 1167 apr_size_t data_len, |
1165 apr_pool_t *pool) | 1168 apr_pool_t *result_pool) |
1166{ 1167 int i; | 1169{ 1170 int i; |
1168 changes_data_t *changes = (changes_data_t *)data; 1169 apr_array_header_t *array = apr_array_make(pool, 0, 1170 sizeof(svn_fs_x__change_t *)); | 1171 svn_fs_x__changes_list_t *changes = (svn_fs_x__changes_list_t *)data; |
1171 1172 /* de-serialize our auxiliary data structure */ 1173 svn_temp_deserializer__resolve(changes, (void**)&changes->changes); 1174 1175 /* de-serialize each entry and add it to the array */ 1176 for (i = 0; i < changes->count; ++i) 1177 deserialize_change(changes->changes, | 1172 1173 /* de-serialize our auxiliary data structure */ 1174 svn_temp_deserializer__resolve(changes, (void**)&changes->changes); 1175 1176 /* de-serialize each entry and add it to the array */ 1177 for (i = 0; i < changes->count; ++i) 1178 deserialize_change(changes->changes, |
1178 (svn_fs_x__change_t **)&changes->changes[i], 1179 pool); | 1179 (svn_fs_x__change_t **)&changes->changes[i]); |
1180 | 1180 |
1181 /* Use the changes buffer as the array's data buffer 1182 * (DATA remains valid for at least as long as POOL). */ 1183 array->elts = (char *)changes->changes; 1184 array->nelts = changes->count; 1185 array->nalloc = changes->count; 1186 | |
1187 /* done */ | 1181 /* done */ |
1188 *out = array; | 1182 *out = changes; |
1189 1190 return SVN_NO_ERROR; 1191} | 1183 1184 return SVN_NO_ERROR; 1185} |
1192 1193/* Auxiliary structure representing the content of a svn_mergeinfo_t hash. 1194 This structure is much easier to (de-)serialize than an APR array. 1195 */ 1196typedef struct mergeinfo_data_t 1197{ 1198 /* number of paths in the hash */ 1199 unsigned count; 1200 1201 /* COUNT keys (paths) */ 1202 const char **keys; 1203 1204 /* COUNT keys lengths (strlen of path) */ 1205 apr_ssize_t *key_lengths; 1206 1207 /* COUNT entries, each giving the number of ranges for the key */ 1208 int *range_counts; 1209 1210 /* all ranges in a single, concatenated buffer */ 1211 svn_merge_range_t *ranges; 1212} mergeinfo_data_t; 1213 1214svn_error_t * 1215svn_fs_x__serialize_mergeinfo(void **data, 1216 apr_size_t *data_len, 1217 void *in, 1218 apr_pool_t *pool) 1219{ 1220 svn_mergeinfo_t mergeinfo = in; 1221 mergeinfo_data_t merges; 1222 svn_temp_serializer__context_t *context; 1223 svn_stringbuf_t *serialized; 1224 apr_hash_index_t *hi; 1225 unsigned i; 1226 int k; 1227 apr_size_t range_count; 1228 1229 /* initialize our auxiliary data structure */ 1230 merges.count = apr_hash_count(mergeinfo); 1231 merges.keys = apr_palloc(pool, sizeof(*merges.keys) * merges.count); 1232 merges.key_lengths = apr_palloc(pool, sizeof(*merges.key_lengths) * 1233 merges.count); 1234 merges.range_counts = apr_palloc(pool, sizeof(*merges.range_counts) * 1235 merges.count); 1236 1237 i = 0; 1238 range_count = 0; 1239 for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi), ++i) 1240 { 1241 svn_rangelist_t *ranges; 1242 apr_hash_this(hi, (const void**)&merges.keys[i], 1243 &merges.key_lengths[i], 1244 (void **)&ranges); 1245 merges.range_counts[i] = ranges->nelts; 1246 range_count += ranges->nelts; 1247 } 1248 1249 merges.ranges = apr_palloc(pool, sizeof(*merges.ranges) * range_count); 1250 1251 i = 0; 1252 for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi)) 1253 { 1254 svn_rangelist_t *ranges = apr_hash_this_val(hi); 1255 for (k = 0; k < ranges->nelts; ++k, ++i) 1256 merges.ranges[i] = *APR_ARRAY_IDX(ranges, k, svn_merge_range_t*); 1257 } 1258 1259 /* serialize it and all its elements */ 1260 context = svn_temp_serializer__init(&merges, 1261 sizeof(merges), 1262 range_count * 30, 1263 pool); 1264 1265 /* keys array */ 1266 svn_temp_serializer__push(context, 1267 (const void * const *)&merges.keys, 1268 merges.count * sizeof(*merges.keys)); 1269 1270 for (i = 0; i < merges.count; ++i) 1271 svn_temp_serializer__add_string(context, &merges.keys[i]); 1272 1273 svn_temp_serializer__pop(context); 1274 1275 /* key lengths array */ 1276 svn_temp_serializer__add_leaf(context, 1277 (const void * const *)&merges.key_lengths, 1278 merges.count * sizeof(*merges.key_lengths)); 1279 1280 /* range counts array */ 1281 svn_temp_serializer__add_leaf(context, 1282 (const void * const *)&merges.range_counts, 1283 merges.count * sizeof(*merges.range_counts)); 1284 1285 /* ranges */ 1286 svn_temp_serializer__add_leaf(context, 1287 (const void * const *)&merges.ranges, 1288 range_count * sizeof(*merges.ranges)); 1289 1290 /* return the serialized result */ 1291 serialized = svn_temp_serializer__get(context); 1292 1293 *data = serialized->data; 1294 *data_len = serialized->len; 1295 1296 return SVN_NO_ERROR; 1297} 1298 1299svn_error_t * 1300svn_fs_x__deserialize_mergeinfo(void **out, 1301 void *data, 1302 apr_size_t data_len, 1303 apr_pool_t *pool) 1304{ 1305 unsigned i; 1306 int k, n; 1307 mergeinfo_data_t *merges = (mergeinfo_data_t *)data; 1308 svn_mergeinfo_t mergeinfo; 1309 1310 /* de-serialize our auxiliary data structure */ 1311 svn_temp_deserializer__resolve(merges, (void**)&merges->keys); 1312 svn_temp_deserializer__resolve(merges, (void**)&merges->key_lengths); 1313 svn_temp_deserializer__resolve(merges, (void**)&merges->range_counts); 1314 svn_temp_deserializer__resolve(merges, (void**)&merges->ranges); 1315 1316 /* de-serialize keys and add entries to the result */ 1317 n = 0; 1318 mergeinfo = svn_hash__make(pool); 1319 for (i = 0; i < merges->count; ++i) 1320 { 1321 svn_rangelist_t *ranges = apr_array_make(pool, 1322 merges->range_counts[i], 1323 sizeof(svn_merge_range_t*)); 1324 for (k = 0; k < merges->range_counts[i]; ++k, ++n) 1325 APR_ARRAY_PUSH(ranges, svn_merge_range_t*) = &merges->ranges[n]; 1326 1327 svn_temp_deserializer__resolve(merges->keys, 1328 (void**)&merges->keys[i]); 1329 apr_hash_set(mergeinfo, merges->keys[i], merges->key_lengths[i], ranges); 1330 } 1331 1332 /* done */ 1333 *out = mergeinfo; 1334 1335 return SVN_NO_ERROR; 1336} 1337 | |