1289177Speter/* noderevs.h --- FSX node revision container 2289177Speter * 3289177Speter * ==================================================================== 4289177Speter * Licensed to the Apache Software Foundation (ASF) under one 5289177Speter * or more contributor license agreements. See the NOTICE file 6289177Speter * distributed with this work for additional information 7289177Speter * regarding copyright ownership. The ASF licenses this file 8289177Speter * to you under the Apache License, Version 2.0 (the 9289177Speter * "License"); you may not use this file except in compliance 10289177Speter * with the License. You may obtain a copy of the License at 11289177Speter * 12289177Speter * http://www.apache.org/licenses/LICENSE-2.0 13289177Speter * 14289177Speter * Unless required by applicable law or agreed to in writing, 15289177Speter * software distributed under the License is distributed on an 16289177Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17289177Speter * KIND, either express or implied. See the License for the 18289177Speter * specific language governing permissions and limitations 19289177Speter * under the License. 20289177Speter * ==================================================================== 21289177Speter */ 22289177Speter 23289177Speter#include "svn_private_config.h" 24289177Speter 25289177Speter#include "private/svn_dep_compat.h" 26289177Speter#include "private/svn_packed_data.h" 27289177Speter#include "private/svn_subr_private.h" 28289177Speter#include "private/svn_temp_serializer.h" 29289177Speter 30289177Speter#include "noderevs.h" 31289177Speter#include "string_table.h" 32289177Speter#include "temp_serializer.h" 33289177Speter 34289177Speter/* These flags will be used with the FLAGS field in binary_noderev_t. 35289177Speter */ 36289177Speter 37289177Speter/* (flags & NODEREV_KIND_MASK) extracts the noderev type */ 38289177Speter#define NODEREV_KIND_MASK 0x00007 39289177Speter 40289177Speter/* the noderev has merge info */ 41289177Speter#define NODEREV_HAS_MINFO 0x00008 42289177Speter 43289177Speter/* the noderev has copy-from-path and revision */ 44289177Speter#define NODEREV_HAS_COPYFROM 0x00010 45289177Speter 46289177Speter/* the noderev has copy-root path and revision */ 47289177Speter#define NODEREV_HAS_COPYROOT 0x00020 48289177Speter 49289177Speter/* the noderev has copy-root path and revision */ 50289177Speter#define NODEREV_HAS_CPATH 0x00040 51289177Speter 52289177Speter/* Our internal representation of a svn_fs_x__noderev_t. 53289177Speter * 54289177Speter * We will store path strings in a string container and reference them 55289177Speter * from here. Similarly, IDs and representations are being stored in 56289177Speter * separate containers and then also referenced here. This eliminates 57289177Speter * the need to store the same IDs and representations more than once. 58289177Speter */ 59289177Spetertypedef struct binary_noderev_t 60289177Speter{ 61289177Speter /* node type and presence indicators */ 62289177Speter apr_uint32_t flags; 63289177Speter 64289177Speter /* Index+1 of the noderev-id for this node-rev. */ 65289177Speter int id; 66289177Speter 67289177Speter /* Index+1 of the node-id for this node-rev. */ 68289177Speter int node_id; 69289177Speter 70289177Speter /* Index+1 of the copy-id for this node-rev. */ 71289177Speter int copy_id; 72289177Speter 73289177Speter /* Index+1 of the predecessor node revision id, or 0 if there is no 74289177Speter predecessor for this node revision */ 75289177Speter int predecessor_id; 76289177Speter 77289177Speter /* number of predecessors this node revision has (recursively), or 78289177Speter -1 if not known (for backward compatibility). */ 79289177Speter int predecessor_count; 80289177Speter 81289177Speter /* If this node-rev is a copy, what revision was it copied from? */ 82289177Speter svn_revnum_t copyfrom_rev; 83289177Speter 84289177Speter /* Helper for history tracing, root revision of the parent tree from 85289177Speter whence this node-rev was copied. */ 86289177Speter svn_revnum_t copyroot_rev; 87289177Speter 88289177Speter /* If this node-rev is a copy, this is the string index+1 of the path 89289177Speter from which that copy way made. 0, otherwise. */ 90289177Speter apr_size_t copyfrom_path; 91289177Speter 92289177Speter /* String index+1 of the root of the parent tree from whence this node- 93289177Speter * rev was copied. */ 94289177Speter apr_size_t copyroot_path; 95289177Speter 96289177Speter /* Index+1 of the representation key for this node's properties. 97289177Speter May be 0 if there are no properties. */ 98289177Speter int prop_rep; 99289177Speter 100289177Speter /* Index+1 of the representation for this node's data. 101289177Speter May be 0 if there is no data. */ 102289177Speter int data_rep; 103289177Speter 104289177Speter /* String index+1 of the path at which this node first came into 105289177Speter existence. */ 106289177Speter apr_size_t created_path; 107289177Speter 108289177Speter /* Number of nodes with svn:mergeinfo properties that are 109289177Speter descendants of this node (including it itself) */ 110289177Speter apr_int64_t mergeinfo_count; 111289177Speter 112289177Speter} binary_noderev_t; 113289177Speter 114289177Speter/* The actual container object. Node revisions are concatenated into 115289177Speter * NODEREVS, referenced representations are stored in DATA_REPS / PROP_REPS 116289177Speter * and the ids in IDs. PATHS is the string table for all paths. 117289177Speter * 118289177Speter * During construction, BUILDER will be used instead of PATHS. IDS_DICT, 119289177Speter * DATA_REPS_DICT and PROP_REPS_DICT are also only used during construction 120289177Speter * and are NULL otherwise. 121289177Speter */ 122289177Speterstruct svn_fs_x__noderevs_t 123289177Speter{ 124289177Speter /* The paths - either in 'builder' mode or finalized mode. 125289177Speter * The respective other pointer will be NULL. */ 126289177Speter string_table_builder_t *builder; 127289177Speter string_table_t *paths; 128289177Speter 129289177Speter /* During construction, maps a full binary_id_t to an index into IDS */ 130289177Speter apr_hash_t *ids_dict; 131289177Speter 132289177Speter /* During construction, maps a full binary_representation_t to an index 133289177Speter * into REPS. */ 134289177Speter apr_hash_t *reps_dict; 135289177Speter 136289177Speter /* array of binary_id_t */ 137289177Speter apr_array_header_t *ids; 138289177Speter 139289177Speter /* array of binary_representation_t */ 140289177Speter apr_array_header_t *reps; 141289177Speter 142289177Speter /* array of binary_noderev_t. */ 143289177Speter apr_array_header_t *noderevs; 144289177Speter}; 145289177Speter 146289177Spetersvn_fs_x__noderevs_t * 147289177Spetersvn_fs_x__noderevs_create(int initial_count, 148289177Speter apr_pool_t* result_pool) 149289177Speter{ 150289177Speter svn_fs_x__noderevs_t *noderevs 151289177Speter = apr_palloc(result_pool, sizeof(*noderevs)); 152289177Speter 153289177Speter noderevs->builder = svn_fs_x__string_table_builder_create(result_pool); 154289177Speter noderevs->ids_dict = svn_hash__make(result_pool); 155289177Speter noderevs->reps_dict = svn_hash__make(result_pool); 156289177Speter noderevs->paths = NULL; 157289177Speter 158289177Speter noderevs->ids 159289177Speter = apr_array_make(result_pool, 2 * initial_count, sizeof(svn_fs_x__id_t)); 160289177Speter noderevs->reps 161289177Speter = apr_array_make(result_pool, 2 * initial_count, 162289177Speter sizeof(svn_fs_x__representation_t)); 163289177Speter noderevs->noderevs 164289177Speter = apr_array_make(result_pool, initial_count, sizeof(binary_noderev_t)); 165289177Speter 166289177Speter return noderevs; 167289177Speter} 168289177Speter 169289177Speter/* Given the ID, return the index+1 into IDS that contains a binary_id 170289177Speter * for it. Returns 0 for NULL IDs. We use DICT to detect duplicates. 171289177Speter */ 172289177Speterstatic int 173289177Speterstore_id(apr_array_header_t *ids, 174289177Speter apr_hash_t *dict, 175289177Speter const svn_fs_x__id_t *id) 176289177Speter{ 177289177Speter int idx; 178289177Speter void *idx_void; 179289177Speter 180289177Speter if (!svn_fs_x__id_used(id)) 181289177Speter return 0; 182289177Speter 183289177Speter idx_void = apr_hash_get(dict, &id, sizeof(id)); 184289177Speter idx = (int)(apr_uintptr_t)idx_void; 185289177Speter if (idx == 0) 186289177Speter { 187289177Speter APR_ARRAY_PUSH(ids, svn_fs_x__id_t) = *id; 188289177Speter idx = ids->nelts; 189289177Speter apr_hash_set(dict, ids->elts + (idx-1) * ids->elt_size, 190289177Speter ids->elt_size, (void*)(apr_uintptr_t)idx); 191289177Speter } 192289177Speter 193289177Speter return idx; 194289177Speter} 195289177Speter 196289177Speter/* Given the REP, return the index+1 into REPS that contains a copy of it. 197289177Speter * Returns 0 for NULL IDs. We use DICT to detect duplicates. 198289177Speter */ 199289177Speterstatic int 200289177Speterstore_representation(apr_array_header_t *reps, 201289177Speter apr_hash_t *dict, 202289177Speter const svn_fs_x__representation_t *rep) 203289177Speter{ 204289177Speter int idx; 205289177Speter void *idx_void; 206289177Speter 207289177Speter if (rep == NULL) 208289177Speter return 0; 209289177Speter 210289177Speter idx_void = apr_hash_get(dict, rep, sizeof(*rep)); 211289177Speter idx = (int)(apr_uintptr_t)idx_void; 212289177Speter if (idx == 0) 213289177Speter { 214289177Speter APR_ARRAY_PUSH(reps, svn_fs_x__representation_t) = *rep; 215289177Speter idx = reps->nelts; 216289177Speter apr_hash_set(dict, reps->elts + (idx-1) * reps->elt_size, 217289177Speter reps->elt_size, (void*)(apr_uintptr_t)idx); 218289177Speter } 219289177Speter 220289177Speter return idx; 221289177Speter} 222289177Speter 223289177Speterapr_size_t 224289177Spetersvn_fs_x__noderevs_add(svn_fs_x__noderevs_t *container, 225289177Speter svn_fs_x__noderev_t *noderev) 226289177Speter{ 227289177Speter binary_noderev_t binary_noderev = { 0 }; 228289177Speter 229289177Speter binary_noderev.flags = (noderev->has_mergeinfo ? NODEREV_HAS_MINFO : 0) 230289177Speter | (noderev->copyfrom_path ? NODEREV_HAS_COPYFROM : 0) 231289177Speter | (noderev->copyroot_path ? NODEREV_HAS_COPYROOT : 0) 232289177Speter | (noderev->created_path ? NODEREV_HAS_CPATH : 0) 233289177Speter | (int)noderev->kind; 234289177Speter 235289177Speter binary_noderev.id 236289177Speter = store_id(container->ids, container->ids_dict, &noderev->noderev_id); 237289177Speter binary_noderev.node_id 238289177Speter = store_id(container->ids, container->ids_dict, &noderev->node_id); 239289177Speter binary_noderev.copy_id 240289177Speter = store_id(container->ids, container->ids_dict, &noderev->copy_id); 241289177Speter binary_noderev.predecessor_id 242289177Speter = store_id(container->ids, container->ids_dict, &noderev->predecessor_id); 243289177Speter 244289177Speter if (noderev->copyfrom_path) 245289177Speter { 246289177Speter binary_noderev.copyfrom_path 247289177Speter = svn_fs_x__string_table_builder_add(container->builder, 248289177Speter noderev->copyfrom_path, 249289177Speter 0); 250289177Speter binary_noderev.copyfrom_rev = noderev->copyfrom_rev; 251289177Speter } 252289177Speter 253289177Speter if (noderev->copyroot_path) 254289177Speter { 255289177Speter binary_noderev.copyroot_path 256289177Speter = svn_fs_x__string_table_builder_add(container->builder, 257289177Speter noderev->copyroot_path, 258289177Speter 0); 259289177Speter binary_noderev.copyroot_rev = noderev->copyroot_rev; 260289177Speter } 261289177Speter 262289177Speter binary_noderev.predecessor_count = noderev->predecessor_count; 263289177Speter binary_noderev.prop_rep = store_representation(container->reps, 264289177Speter container->reps_dict, 265289177Speter noderev->prop_rep); 266289177Speter binary_noderev.data_rep = store_representation(container->reps, 267289177Speter container->reps_dict, 268289177Speter noderev->data_rep); 269289177Speter 270289177Speter if (noderev->created_path) 271289177Speter binary_noderev.created_path 272289177Speter = svn_fs_x__string_table_builder_add(container->builder, 273289177Speter noderev->created_path, 274289177Speter 0); 275289177Speter 276289177Speter binary_noderev.mergeinfo_count = noderev->mergeinfo_count; 277289177Speter 278289177Speter APR_ARRAY_PUSH(container->noderevs, binary_noderev_t) = binary_noderev; 279289177Speter 280289177Speter return container->noderevs->nelts - 1; 281289177Speter} 282289177Speter 283289177Speterapr_size_t 284289177Spetersvn_fs_x__noderevs_estimate_size(const svn_fs_x__noderevs_t *container) 285289177Speter{ 286289177Speter /* CONTAINER must be in 'builder' mode */ 287289177Speter if (container->builder == NULL) 288289177Speter return 0; 289289177Speter 290289177Speter /* string table code makes its own prediction, 291289177Speter * noderevs should be < 16 bytes each, 292289177Speter * id parts < 4 bytes each, 293289177Speter * data representations < 40 bytes each, 294289177Speter * property representations < 30 bytes each, 295289177Speter * some static overhead should be assumed */ 296289177Speter return svn_fs_x__string_table_builder_estimate_size(container->builder) 297289177Speter + container->noderevs->nelts * 16 298289177Speter + container->ids->nelts * 4 299289177Speter + container->reps->nelts * 40 300289177Speter + 100; 301289177Speter} 302289177Speter 303289177Speter/* Set *ID to the ID part stored at index IDX in IDS. 304289177Speter */ 305289177Speterstatic svn_error_t * 306289177Speterget_id(svn_fs_x__id_t *id, 307289177Speter const apr_array_header_t *ids, 308289177Speter int idx) 309289177Speter{ 310289177Speter /* handle NULL IDs */ 311289177Speter if (idx == 0) 312289177Speter { 313289177Speter svn_fs_x__id_reset(id); 314289177Speter return SVN_NO_ERROR; 315289177Speter } 316289177Speter 317289177Speter /* check for corrupted data */ 318289177Speter if (idx < 0 || idx > ids->nelts) 319289177Speter return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, 320289177Speter _("ID part index %d exceeds container size %d"), 321289177Speter idx, ids->nelts); 322289177Speter 323289177Speter /* Return the requested ID. */ 324289177Speter *id = APR_ARRAY_IDX(ids, idx - 1, svn_fs_x__id_t); 325289177Speter 326289177Speter return SVN_NO_ERROR; 327289177Speter} 328289177Speter 329289177Speter/* Create a svn_fs_x__representation_t in *REP, allocated in POOL based on the 330289177Speter * representation stored at index IDX in REPS. 331289177Speter */ 332289177Speterstatic svn_error_t * 333289177Speterget_representation(svn_fs_x__representation_t **rep, 334289177Speter const apr_array_header_t *reps, 335289177Speter int idx, 336289177Speter apr_pool_t *pool) 337289177Speter{ 338289177Speter /* handle NULL representations */ 339289177Speter if (idx == 0) 340289177Speter { 341289177Speter *rep = NULL; 342289177Speter return SVN_NO_ERROR; 343289177Speter } 344289177Speter 345289177Speter /* check for corrupted data */ 346289177Speter if (idx < 0 || idx > reps->nelts) 347289177Speter return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, 348289177Speter _("Node revision ID index %d" 349289177Speter " exceeds container size %d"), 350289177Speter idx, reps->nelts); 351289177Speter 352289177Speter /* no translation required. Just duplicate the info */ 353289177Speter *rep = apr_pmemdup(pool, 354289177Speter &APR_ARRAY_IDX(reps, idx - 1, svn_fs_x__representation_t), 355289177Speter sizeof(**rep)); 356289177Speter 357289177Speter return SVN_NO_ERROR; 358289177Speter} 359289177Speter 360289177Spetersvn_error_t * 361289177Spetersvn_fs_x__noderevs_get(svn_fs_x__noderev_t **noderev_p, 362289177Speter const svn_fs_x__noderevs_t *container, 363289177Speter apr_size_t idx, 364289177Speter apr_pool_t *pool) 365289177Speter{ 366289177Speter svn_fs_x__noderev_t *noderev; 367289177Speter binary_noderev_t *binary_noderev; 368289177Speter 369289177Speter /* CONTAINER must be in 'finalized' mode */ 370289177Speter SVN_ERR_ASSERT(container->builder == NULL); 371289177Speter SVN_ERR_ASSERT(container->paths); 372289177Speter 373289177Speter /* validate index */ 374289177Speter if (idx >= (apr_size_t)container->noderevs->nelts) 375289177Speter return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, 376289177Speter apr_psprintf(pool, 377289177Speter _("Node revision index %%%s" 378289177Speter " exceeds container size %%d"), 379289177Speter APR_SIZE_T_FMT), 380289177Speter idx, container->noderevs->nelts); 381289177Speter 382289177Speter /* allocate result struct and fill it field by field */ 383289177Speter noderev = apr_pcalloc(pool, sizeof(*noderev)); 384289177Speter binary_noderev = &APR_ARRAY_IDX(container->noderevs, idx, binary_noderev_t); 385289177Speter 386289177Speter noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK); 387289177Speter SVN_ERR(get_id(&noderev->noderev_id, container->ids, binary_noderev->id)); 388289177Speter SVN_ERR(get_id(&noderev->node_id, container->ids, 389289177Speter binary_noderev->node_id)); 390289177Speter SVN_ERR(get_id(&noderev->copy_id, container->ids, 391289177Speter binary_noderev->copy_id)); 392289177Speter SVN_ERR(get_id(&noderev->predecessor_id, container->ids, 393289177Speter binary_noderev->predecessor_id)); 394289177Speter 395289177Speter if (binary_noderev->flags & NODEREV_HAS_COPYFROM) 396289177Speter { 397289177Speter noderev->copyfrom_path 398289177Speter = svn_fs_x__string_table_get(container->paths, 399289177Speter binary_noderev->copyfrom_path, 400289177Speter NULL, 401289177Speter pool); 402289177Speter noderev->copyfrom_rev = binary_noderev->copyfrom_rev; 403289177Speter } 404289177Speter else 405289177Speter { 406289177Speter noderev->copyfrom_path = NULL; 407289177Speter noderev->copyfrom_rev = SVN_INVALID_REVNUM; 408289177Speter } 409289177Speter 410289177Speter if (binary_noderev->flags & NODEREV_HAS_COPYROOT) 411289177Speter { 412289177Speter noderev->copyroot_path 413289177Speter = svn_fs_x__string_table_get(container->paths, 414289177Speter binary_noderev->copyroot_path, 415289177Speter NULL, 416289177Speter pool); 417289177Speter noderev->copyroot_rev = binary_noderev->copyroot_rev; 418289177Speter } 419289177Speter else 420289177Speter { 421289177Speter noderev->copyroot_path = NULL; 422289177Speter noderev->copyroot_rev = 0; 423289177Speter } 424289177Speter 425289177Speter noderev->predecessor_count = binary_noderev->predecessor_count; 426289177Speter 427289177Speter SVN_ERR(get_representation(&noderev->prop_rep, container->reps, 428289177Speter binary_noderev->prop_rep, pool)); 429289177Speter SVN_ERR(get_representation(&noderev->data_rep, container->reps, 430289177Speter binary_noderev->data_rep, pool)); 431289177Speter 432289177Speter if (binary_noderev->flags & NODEREV_HAS_CPATH) 433289177Speter noderev->created_path 434289177Speter = svn_fs_x__string_table_get(container->paths, 435289177Speter binary_noderev->created_path, 436289177Speter NULL, 437289177Speter pool); 438289177Speter 439289177Speter noderev->mergeinfo_count = binary_noderev->mergeinfo_count; 440289177Speter 441289177Speter noderev->has_mergeinfo = (binary_noderev->flags & NODEREV_HAS_MINFO) ? 1 : 0; 442289177Speter *noderev_p = noderev; 443289177Speter 444289177Speter return SVN_NO_ERROR; 445289177Speter} 446289177Speter 447289177Speter/* Create and return a stream for representations in PARENT. 448289177Speter * Initialize the sub-streams for all fields, except checksums. 449289177Speter */ 450289177Speterstatic svn_packed__int_stream_t * 451289177Spetercreate_rep_stream(svn_packed__int_stream_t *parent) 452289177Speter{ 453289177Speter svn_packed__int_stream_t *stream 454289177Speter = svn_packed__create_int_substream(parent, FALSE, FALSE); 455289177Speter 456289177Speter /* sub-streams for members - except for checksums */ 457289177Speter /* has_sha1 */ 458289177Speter svn_packed__create_int_substream(stream, FALSE, FALSE); 459289177Speter 460289177Speter /* rev, item_index, size, expanded_size */ 461289177Speter svn_packed__create_int_substream(stream, TRUE, FALSE); 462289177Speter svn_packed__create_int_substream(stream, FALSE, FALSE); 463289177Speter svn_packed__create_int_substream(stream, FALSE, FALSE); 464289177Speter svn_packed__create_int_substream(stream, FALSE, FALSE); 465289177Speter 466289177Speter return stream; 467289177Speter} 468289177Speter 469289177Speter/* Serialize all representations in REP. Store checksums in DIGEST_STREAM, 470289177Speter * put all other fields into REP_STREAM. 471289177Speter */ 472289177Speterstatic void 473289177Speterwrite_reps(svn_packed__int_stream_t *rep_stream, 474289177Speter svn_packed__byte_stream_t *digest_stream, 475289177Speter apr_array_header_t *reps) 476289177Speter{ 477289177Speter int i; 478289177Speter for (i = 0; i < reps->nelts; ++i) 479289177Speter { 480289177Speter svn_fs_x__representation_t *rep 481289177Speter = &APR_ARRAY_IDX(reps, i, svn_fs_x__representation_t); 482289177Speter 483289177Speter svn_packed__add_uint(rep_stream, rep->has_sha1); 484289177Speter 485289177Speter svn_packed__add_uint(rep_stream, rep->id.change_set); 486289177Speter svn_packed__add_uint(rep_stream, rep->id.number); 487289177Speter svn_packed__add_uint(rep_stream, rep->size); 488289177Speter svn_packed__add_uint(rep_stream, rep->expanded_size); 489289177Speter 490289177Speter svn_packed__add_bytes(digest_stream, 491289177Speter (const char *)rep->md5_digest, 492289177Speter sizeof(rep->md5_digest)); 493289177Speter if (rep->has_sha1) 494289177Speter svn_packed__add_bytes(digest_stream, 495289177Speter (const char *)rep->sha1_digest, 496289177Speter sizeof(rep->sha1_digest)); 497289177Speter } 498289177Speter} 499289177Speter 500289177Spetersvn_error_t * 501289177Spetersvn_fs_x__write_noderevs_container(svn_stream_t *stream, 502289177Speter const svn_fs_x__noderevs_t *container, 503289177Speter apr_pool_t *scratch_pool) 504289177Speter{ 505289177Speter int i; 506289177Speter 507289177Speter string_table_t *paths = container->paths 508289177Speter ? container->paths 509289177Speter : svn_fs_x__string_table_create(container->builder, 510289177Speter scratch_pool); 511289177Speter 512289177Speter svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool); 513289177Speter 514289177Speter /* one common top-level stream for all arrays. One sub-stream */ 515289177Speter svn_packed__int_stream_t *structs_stream 516289177Speter = svn_packed__create_int_stream(root, FALSE, FALSE); 517289177Speter svn_packed__int_stream_t *ids_stream 518289177Speter = svn_packed__create_int_substream(structs_stream, FALSE, FALSE); 519289177Speter svn_packed__int_stream_t *reps_stream 520289177Speter = create_rep_stream(structs_stream); 521289177Speter svn_packed__int_stream_t *noderevs_stream 522289177Speter = svn_packed__create_int_substream(structs_stream, FALSE, FALSE); 523289177Speter svn_packed__byte_stream_t *digests_stream 524289177Speter = svn_packed__create_bytes_stream(root); 525289177Speter 526289177Speter /* structure the IDS_STREAM such we can extract much of the redundancy 527289177Speter * from the svn_fs_x__ip_part_t structs */ 528289177Speter for (i = 0; i < 2; ++i) 529289177Speter svn_packed__create_int_substream(ids_stream, TRUE, FALSE); 530289177Speter 531289177Speter /* Same storing binary_noderev_t in the NODEREVS_STREAM */ 532289177Speter svn_packed__create_int_substream(noderevs_stream, FALSE, FALSE); 533289177Speter for (i = 0; i < 13; ++i) 534289177Speter svn_packed__create_int_substream(noderevs_stream, TRUE, FALSE); 535289177Speter 536289177Speter /* serialize ids array */ 537289177Speter for (i = 0; i < container->ids->nelts; ++i) 538289177Speter { 539289177Speter svn_fs_x__id_t *id = &APR_ARRAY_IDX(container->ids, i, svn_fs_x__id_t); 540289177Speter 541289177Speter svn_packed__add_int(ids_stream, id->change_set); 542289177Speter svn_packed__add_uint(ids_stream, id->number); 543289177Speter } 544289177Speter 545289177Speter /* serialize rep arrays */ 546289177Speter write_reps(reps_stream, digests_stream, container->reps); 547289177Speter 548289177Speter /* serialize noderevs array */ 549289177Speter for (i = 0; i < container->noderevs->nelts; ++i) 550289177Speter { 551289177Speter const binary_noderev_t *noderev 552289177Speter = &APR_ARRAY_IDX(container->noderevs, i, binary_noderev_t); 553289177Speter 554289177Speter svn_packed__add_uint(noderevs_stream, noderev->flags); 555289177Speter 556289177Speter svn_packed__add_uint(noderevs_stream, noderev->id); 557289177Speter svn_packed__add_uint(noderevs_stream, noderev->node_id); 558289177Speter svn_packed__add_uint(noderevs_stream, noderev->copy_id); 559289177Speter svn_packed__add_uint(noderevs_stream, noderev->predecessor_id); 560289177Speter svn_packed__add_uint(noderevs_stream, noderev->predecessor_count); 561289177Speter 562289177Speter svn_packed__add_uint(noderevs_stream, noderev->copyfrom_path); 563289177Speter svn_packed__add_int(noderevs_stream, noderev->copyfrom_rev); 564289177Speter svn_packed__add_uint(noderevs_stream, noderev->copyroot_path); 565289177Speter svn_packed__add_int(noderevs_stream, noderev->copyroot_rev); 566289177Speter 567289177Speter svn_packed__add_uint(noderevs_stream, noderev->prop_rep); 568289177Speter svn_packed__add_uint(noderevs_stream, noderev->data_rep); 569289177Speter 570289177Speter svn_packed__add_uint(noderevs_stream, noderev->created_path); 571289177Speter svn_packed__add_uint(noderevs_stream, noderev->mergeinfo_count); 572289177Speter } 573289177Speter 574289177Speter /* write to disk */ 575289177Speter SVN_ERR(svn_fs_x__write_string_table(stream, paths, scratch_pool)); 576289177Speter SVN_ERR(svn_packed__data_write(stream, root, scratch_pool)); 577289177Speter 578289177Speter return SVN_NO_ERROR; 579289177Speter} 580289177Speter 581289177Speter/* Allocate a svn_fs_x__representation_t array in POOL and return it in 582289177Speter * REPS_P. Deserialize the data in REP_STREAM and DIGEST_STREAM and store 583289177Speter * the resulting representations into the *REPS_P. 584289177Speter */ 585289177Speterstatic svn_error_t * 586289177Speterread_reps(apr_array_header_t **reps_p, 587289177Speter svn_packed__int_stream_t *rep_stream, 588289177Speter svn_packed__byte_stream_t *digest_stream, 589289177Speter apr_pool_t *pool) 590289177Speter{ 591289177Speter apr_size_t i; 592289177Speter apr_size_t len; 593289177Speter const char *bytes; 594289177Speter 595289177Speter apr_size_t count 596289177Speter = svn_packed__int_count(svn_packed__first_int_substream(rep_stream)); 597289177Speter apr_array_header_t *reps 598289177Speter = apr_array_make(pool, (int)count, sizeof(svn_fs_x__representation_t)); 599289177Speter 600289177Speter for (i = 0; i < count; ++i) 601289177Speter { 602289177Speter svn_fs_x__representation_t rep; 603289177Speter 604289177Speter rep.has_sha1 = (svn_boolean_t)svn_packed__get_uint(rep_stream); 605289177Speter 606289177Speter rep.id.change_set = (svn_revnum_t)svn_packed__get_uint(rep_stream); 607289177Speter rep.id.number = svn_packed__get_uint(rep_stream); 608289177Speter rep.size = svn_packed__get_uint(rep_stream); 609289177Speter rep.expanded_size = svn_packed__get_uint(rep_stream); 610289177Speter 611289177Speter /* when extracting the checksums, beware of buffer under/overflows 612289177Speter caused by disk data corruption. */ 613289177Speter bytes = svn_packed__get_bytes(digest_stream, &len); 614289177Speter if (len != sizeof(rep.md5_digest)) 615289177Speter return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, 616289177Speter apr_psprintf(pool, 617289177Speter _("Unexpected MD5" 618289177Speter " digest size %%%s"), 619289177Speter APR_SIZE_T_FMT), 620289177Speter len); 621289177Speter 622289177Speter memcpy(rep.md5_digest, bytes, sizeof(rep.md5_digest)); 623289177Speter if (rep.has_sha1) 624289177Speter { 625289177Speter bytes = svn_packed__get_bytes(digest_stream, &len); 626289177Speter if (len != sizeof(rep.sha1_digest)) 627289177Speter return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, 628289177Speter apr_psprintf(pool, 629289177Speter _("Unexpected SHA1" 630289177Speter " digest size %%%s"), 631289177Speter APR_SIZE_T_FMT), 632289177Speter len); 633289177Speter 634289177Speter memcpy(rep.sha1_digest, bytes, sizeof(rep.sha1_digest)); 635289177Speter } 636289177Speter 637289177Speter APR_ARRAY_PUSH(reps, svn_fs_x__representation_t) = rep; 638289177Speter } 639289177Speter 640289177Speter *reps_p = reps; 641289177Speter 642289177Speter return SVN_NO_ERROR; 643289177Speter} 644289177Speter 645289177Spetersvn_error_t * 646289177Spetersvn_fs_x__read_noderevs_container(svn_fs_x__noderevs_t **container, 647289177Speter svn_stream_t *stream, 648289177Speter apr_pool_t *result_pool, 649289177Speter apr_pool_t *scratch_pool) 650289177Speter{ 651289177Speter apr_size_t i; 652289177Speter apr_size_t count; 653289177Speter 654289177Speter svn_fs_x__noderevs_t *noderevs 655289177Speter = apr_pcalloc(result_pool, sizeof(*noderevs)); 656289177Speter 657289177Speter svn_packed__data_root_t *root; 658289177Speter svn_packed__int_stream_t *structs_stream; 659289177Speter svn_packed__int_stream_t *ids_stream; 660289177Speter svn_packed__int_stream_t *reps_stream; 661289177Speter svn_packed__int_stream_t *noderevs_stream; 662289177Speter svn_packed__byte_stream_t *digests_stream; 663289177Speter 664289177Speter /* read everything from disk */ 665289177Speter SVN_ERR(svn_fs_x__read_string_table(&noderevs->paths, stream, 666289177Speter result_pool, scratch_pool)); 667289177Speter SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool)); 668289177Speter 669289177Speter /* get streams */ 670289177Speter structs_stream = svn_packed__first_int_stream(root); 671289177Speter ids_stream = svn_packed__first_int_substream(structs_stream); 672289177Speter reps_stream = svn_packed__next_int_stream(ids_stream); 673289177Speter noderevs_stream = svn_packed__next_int_stream(reps_stream); 674289177Speter digests_stream = svn_packed__first_byte_stream(root); 675289177Speter 676289177Speter /* read ids array */ 677289177Speter count 678289177Speter = svn_packed__int_count(svn_packed__first_int_substream(ids_stream)); 679289177Speter noderevs->ids 680289177Speter = apr_array_make(result_pool, (int)count, sizeof(svn_fs_x__id_t)); 681289177Speter for (i = 0; i < count; ++i) 682289177Speter { 683289177Speter svn_fs_x__id_t id; 684289177Speter 685289177Speter id.change_set = (svn_revnum_t)svn_packed__get_int(ids_stream); 686289177Speter id.number = svn_packed__get_uint(ids_stream); 687289177Speter 688289177Speter APR_ARRAY_PUSH(noderevs->ids, svn_fs_x__id_t) = id; 689289177Speter } 690289177Speter 691289177Speter /* read rep arrays */ 692289177Speter SVN_ERR(read_reps(&noderevs->reps, reps_stream, digests_stream, 693289177Speter result_pool)); 694289177Speter 695289177Speter /* read noderevs array */ 696289177Speter count 697289177Speter = svn_packed__int_count(svn_packed__first_int_substream(noderevs_stream)); 698289177Speter noderevs->noderevs 699289177Speter = apr_array_make(result_pool, (int)count, sizeof(binary_noderev_t)); 700289177Speter for (i = 0; i < count; ++i) 701289177Speter { 702289177Speter binary_noderev_t noderev; 703289177Speter 704289177Speter noderev.flags = (apr_uint32_t)svn_packed__get_uint(noderevs_stream); 705289177Speter 706289177Speter noderev.id = (int)svn_packed__get_uint(noderevs_stream); 707289177Speter noderev.node_id = (int)svn_packed__get_uint(noderevs_stream); 708289177Speter noderev.copy_id = (int)svn_packed__get_uint(noderevs_stream); 709289177Speter noderev.predecessor_id = (int)svn_packed__get_uint(noderevs_stream); 710289177Speter noderev.predecessor_count = (int)svn_packed__get_uint(noderevs_stream); 711289177Speter 712289177Speter noderev.copyfrom_path = (apr_size_t)svn_packed__get_uint(noderevs_stream); 713289177Speter noderev.copyfrom_rev = (svn_revnum_t)svn_packed__get_int(noderevs_stream); 714289177Speter noderev.copyroot_path = (apr_size_t)svn_packed__get_uint(noderevs_stream); 715289177Speter noderev.copyroot_rev = (svn_revnum_t)svn_packed__get_int(noderevs_stream); 716289177Speter 717289177Speter noderev.prop_rep = (int)svn_packed__get_uint(noderevs_stream); 718289177Speter noderev.data_rep = (int)svn_packed__get_uint(noderevs_stream); 719289177Speter 720289177Speter noderev.created_path = (apr_size_t)svn_packed__get_uint(noderevs_stream); 721289177Speter noderev.mergeinfo_count = svn_packed__get_uint(noderevs_stream); 722289177Speter 723289177Speter APR_ARRAY_PUSH(noderevs->noderevs, binary_noderev_t) = noderev; 724289177Speter } 725289177Speter 726289177Speter *container = noderevs; 727289177Speter 728289177Speter return SVN_NO_ERROR; 729289177Speter} 730289177Speter 731289177Spetersvn_error_t * 732289177Spetersvn_fs_x__serialize_noderevs_container(void **data, 733289177Speter apr_size_t *data_len, 734289177Speter void *in, 735289177Speter apr_pool_t *pool) 736289177Speter{ 737289177Speter svn_fs_x__noderevs_t *noderevs = in; 738289177Speter svn_stringbuf_t *serialized; 739289177Speter apr_size_t size 740289177Speter = noderevs->ids->elt_size * noderevs->ids->nelts 741289177Speter + noderevs->reps->elt_size * noderevs->reps->nelts 742289177Speter + noderevs->noderevs->elt_size * noderevs->noderevs->nelts 743289177Speter + 10 * noderevs->noderevs->elt_size 744289177Speter + 100; 745289177Speter 746289177Speter /* serialize array header and all its elements */ 747289177Speter svn_temp_serializer__context_t *context 748289177Speter = svn_temp_serializer__init(noderevs, sizeof(*noderevs), size, pool); 749289177Speter 750289177Speter /* serialize sub-structures */ 751289177Speter svn_fs_x__serialize_string_table(context, &noderevs->paths); 752289177Speter svn_fs_x__serialize_apr_array(context, &noderevs->ids); 753289177Speter svn_fs_x__serialize_apr_array(context, &noderevs->reps); 754289177Speter svn_fs_x__serialize_apr_array(context, &noderevs->noderevs); 755289177Speter 756289177Speter /* return the serialized result */ 757289177Speter serialized = svn_temp_serializer__get(context); 758289177Speter 759289177Speter *data = serialized->data; 760289177Speter *data_len = serialized->len; 761289177Speter 762289177Speter return SVN_NO_ERROR; 763289177Speter} 764289177Speter 765289177Spetersvn_error_t * 766289177Spetersvn_fs_x__deserialize_noderevs_container(void **out, 767289177Speter void *data, 768289177Speter apr_size_t data_len, 769289177Speter apr_pool_t *pool) 770289177Speter{ 771289177Speter svn_fs_x__noderevs_t *noderevs = (svn_fs_x__noderevs_t *)data; 772289177Speter 773289177Speter /* de-serialize sub-structures */ 774289177Speter svn_fs_x__deserialize_string_table(noderevs, &noderevs->paths); 775289177Speter svn_fs_x__deserialize_apr_array(noderevs, &noderevs->ids, pool); 776289177Speter svn_fs_x__deserialize_apr_array(noderevs, &noderevs->reps, pool); 777289177Speter svn_fs_x__deserialize_apr_array(noderevs, &noderevs->noderevs, pool); 778289177Speter 779289177Speter /* done */ 780289177Speter *out = noderevs; 781289177Speter 782289177Speter return SVN_NO_ERROR; 783289177Speter} 784289177Speter 785289177Speter/* Deserialize the cache serialized APR struct at *IN in BUFFER and write 786289177Speter * the result to OUT. Note that this will only resolve the pointers and 787289177Speter * not the array elements themselves. */ 788289177Speterstatic void 789289177Speterresolve_apr_array_header(apr_array_header_t *out, 790289177Speter const void *buffer, 791289177Speter apr_array_header_t * const *in) 792289177Speter{ 793289177Speter const apr_array_header_t *array 794289177Speter = svn_temp_deserializer__ptr(buffer, (const void *const *)in); 795289177Speter const char *elements 796289177Speter = svn_temp_deserializer__ptr(array, (const void *const *)&array->elts); 797289177Speter 798289177Speter *out = *array; 799289177Speter out->elts = (char *)elements; 800289177Speter out->pool = NULL; 801289177Speter} 802289177Speter 803289177Spetersvn_error_t * 804289177Spetersvn_fs_x__noderevs_get_func(void **out, 805289177Speter const void *data, 806289177Speter apr_size_t data_len, 807289177Speter void *baton, 808289177Speter apr_pool_t *pool) 809289177Speter{ 810289177Speter svn_fs_x__noderev_t *noderev; 811289177Speter binary_noderev_t *binary_noderev; 812289177Speter 813289177Speter apr_array_header_t ids; 814289177Speter apr_array_header_t reps; 815289177Speter apr_array_header_t noderevs; 816289177Speter 817289177Speter apr_uint32_t idx = *(apr_uint32_t *)baton; 818289177Speter const svn_fs_x__noderevs_t *container = data; 819289177Speter 820289177Speter /* Resolve all container pointers */ 821289177Speter const string_table_t *paths 822289177Speter = svn_temp_deserializer__ptr(container, 823289177Speter (const void *const *)&container->paths); 824289177Speter 825289177Speter resolve_apr_array_header(&ids, container, &container->ids); 826289177Speter resolve_apr_array_header(&reps, container, &container->reps); 827289177Speter resolve_apr_array_header(&noderevs, container, &container->noderevs); 828289177Speter 829289177Speter /* allocate result struct and fill it field by field */ 830289177Speter noderev = apr_pcalloc(pool, sizeof(*noderev)); 831289177Speter binary_noderev = &APR_ARRAY_IDX(&noderevs, idx, binary_noderev_t); 832289177Speter 833289177Speter noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK); 834289177Speter SVN_ERR(get_id(&noderev->noderev_id, &ids, binary_noderev->id)); 835289177Speter SVN_ERR(get_id(&noderev->node_id, &ids, binary_noderev->node_id)); 836289177Speter SVN_ERR(get_id(&noderev->copy_id, &ids, binary_noderev->copy_id)); 837289177Speter SVN_ERR(get_id(&noderev->predecessor_id, &ids, 838289177Speter binary_noderev->predecessor_id)); 839289177Speter 840289177Speter if (binary_noderev->flags & NODEREV_HAS_COPYFROM) 841289177Speter { 842289177Speter noderev->copyfrom_path 843289177Speter = svn_fs_x__string_table_get_func(paths, 844289177Speter binary_noderev->copyfrom_path, 845289177Speter NULL, 846289177Speter pool); 847289177Speter noderev->copyfrom_rev = binary_noderev->copyfrom_rev; 848289177Speter } 849289177Speter else 850289177Speter { 851289177Speter noderev->copyfrom_path = NULL; 852289177Speter noderev->copyfrom_rev = SVN_INVALID_REVNUM; 853289177Speter } 854289177Speter 855289177Speter if (binary_noderev->flags & NODEREV_HAS_COPYROOT) 856289177Speter { 857289177Speter noderev->copyroot_path 858289177Speter = svn_fs_x__string_table_get_func(paths, 859289177Speter binary_noderev->copyroot_path, 860289177Speter NULL, 861289177Speter pool); 862289177Speter noderev->copyroot_rev = binary_noderev->copyroot_rev; 863289177Speter } 864289177Speter else 865289177Speter { 866289177Speter noderev->copyroot_path = NULL; 867289177Speter noderev->copyroot_rev = 0; 868289177Speter } 869289177Speter 870289177Speter noderev->predecessor_count = binary_noderev->predecessor_count; 871289177Speter 872289177Speter SVN_ERR(get_representation(&noderev->prop_rep, &reps, 873289177Speter binary_noderev->prop_rep, pool)); 874289177Speter SVN_ERR(get_representation(&noderev->data_rep, &reps, 875289177Speter binary_noderev->data_rep, pool)); 876289177Speter 877289177Speter if (binary_noderev->flags & NODEREV_HAS_CPATH) 878289177Speter noderev->created_path 879289177Speter = svn_fs_x__string_table_get_func(paths, 880289177Speter binary_noderev->created_path, 881289177Speter NULL, 882289177Speter pool); 883289177Speter 884289177Speter noderev->mergeinfo_count = binary_noderev->mergeinfo_count; 885289177Speter 886289177Speter noderev->has_mergeinfo = (binary_noderev->flags & NODEREV_HAS_MINFO) ? 1 : 0; 887289177Speter *out = noderev; 888289177Speter 889289177Speter return SVN_NO_ERROR; 890289177Speter} 891289177Speter 892289177Spetersvn_error_t * 893289177Spetersvn_fs_x__mergeinfo_count_get_func(void **out, 894289177Speter const void *data, 895289177Speter apr_size_t data_len, 896289177Speter void *baton, 897289177Speter apr_pool_t *pool) 898289177Speter{ 899289177Speter binary_noderev_t *binary_noderev; 900289177Speter apr_array_header_t noderevs; 901289177Speter 902289177Speter apr_uint32_t idx = *(apr_uint32_t *)baton; 903289177Speter const svn_fs_x__noderevs_t *container = data; 904289177Speter 905289177Speter /* Resolve all container pointers */ 906289177Speter resolve_apr_array_header(&noderevs, container, &container->noderevs); 907289177Speter binary_noderev = &APR_ARRAY_IDX(&noderevs, idx, binary_noderev_t); 908289177Speter 909289177Speter *(apr_int64_t *)out = binary_noderev->mergeinfo_count; 910289177Speter 911289177Speter return SVN_NO_ERROR; 912289177Speter} 913