1 /* dag.h : DAG-like interface filesystem, private to libsvn_fs 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 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 */ 22 23 #ifndef SVN_LIBSVN_FS_DAG_H 24 #define SVN_LIBSVN_FS_DAG_H 25 26 #include "svn_fs.h" 27 #include "svn_delta.h" 28 #include "private/svn_cache.h" 29 30 #include "id.h" 31 32 #ifdef __cplusplus 33 extern "C" { 34 #endif /* __cplusplus */ 35 36 37 /* The interface in this file provides all the essential filesystem 38 operations, but exposes the filesystem's DAG structure. This makes 39 it simpler to implement than the public interface, since a client 40 of this interface has to understand and cope with shared structure 41 directly as it appears in the database. However, it's still a 42 self-consistent set of invariants to maintain, making it 43 (hopefully) a useful interface boundary. 44 45 In other words: 46 47 - The dag_node_t interface exposes the internal DAG structure of 48 the filesystem, while the svn_fs.h interface does any cloning 49 necessary to make the filesystem look like a tree. 50 51 - The dag_node_t interface exposes the existence of copy nodes, 52 whereas the svn_fs.h handles them transparently. 53 54 - dag_node_t's must be explicitly cloned, whereas the svn_fs.h 55 operations make clones implicitly. 56 57 - Callers of the dag_node_t interface use Berkeley DB transactions 58 to ensure consistency between operations, while callers of the 59 svn_fs.h interface use Subversion transactions. */ 60 61 62 /* Generic DAG node stuff. */ 63 64 typedef struct dag_node_t dag_node_t; 65 66 /* Fill *NODE with a dag_node_t representing node revision ID in FS, 67 allocating in POOL. */ 68 svn_error_t * 69 svn_fs_fs__dag_get_node(dag_node_t **node, 70 svn_fs_t *fs, 71 const svn_fs_id_t *id, 72 apr_pool_t *pool); 73 74 75 /* Return a new dag_node_t object referring to the same node as NODE, 76 allocated in POOL. If you're trying to build a structure in a 77 pool that wants to refer to dag nodes that may have been allocated 78 elsewhere, you can call this function and avoid inter-pool pointers. */ 79 dag_node_t * 80 svn_fs_fs__dag_dup(const dag_node_t *node, 81 apr_pool_t *pool); 82 83 /* Serialize a DAG node, except don't try to preserve the 'fs' member. 84 Implements svn_cache__serialize_func_t */ 85 svn_error_t * 86 svn_fs_fs__dag_serialize(void **data, 87 apr_size_t *data_len, 88 void *in, 89 apr_pool_t *pool); 90 91 /* Deserialize a DAG node, leaving the 'fs' member as NULL. 92 Implements svn_cache__deserialize_func_t */ 93 svn_error_t * 94 svn_fs_fs__dag_deserialize(void **out, 95 void *data, 96 apr_size_t data_len, 97 apr_pool_t *pool); 98 99 /* Return the filesystem containing NODE. */ 100 svn_fs_t *svn_fs_fs__dag_get_fs(dag_node_t *node); 101 102 /* Changes the filesystem containing NODE to FS. (Used when pulling 103 nodes out of a shared cache, say.) */ 104 void svn_fs_fs__dag_set_fs(dag_node_t *node, svn_fs_t *fs); 105 106 107 /* Set *REV to NODE's revision number, allocating in POOL. If NODE 108 has never been committed as part of a revision, set *REV to 109 SVN_INVALID_REVNUM. */ 110 svn_error_t *svn_fs_fs__dag_get_revision(svn_revnum_t *rev, 111 dag_node_t *node, 112 apr_pool_t *pool); 113 114 115 /* Return the node revision ID of NODE. The value returned is shared 116 with NODE, and will be deallocated when NODE is. */ 117 const svn_fs_id_t *svn_fs_fs__dag_get_id(const dag_node_t *node); 118 119 120 /* Return the created path of NODE. The value returned is shared 121 with NODE, and will be deallocated when NODE is. */ 122 const char *svn_fs_fs__dag_get_created_path(dag_node_t *node); 123 124 125 /* Set *ID_P to the node revision ID of NODE's immediate predecessor, 126 or NULL if NODE has no predecessor. 127 */ 128 svn_error_t *svn_fs_fs__dag_get_predecessor_id(const svn_fs_id_t **id_p, 129 dag_node_t *node); 130 131 132 /* Set *COUNT to the number of predecessors NODE has (recursively), or 133 -1 if not known. 134 */ 135 /* ### This function is currently only used by 'verify'. */ 136 svn_error_t *svn_fs_fs__dag_get_predecessor_count(int *count, 137 dag_node_t *node); 138 139 /* Set *COUNT to the number of node under NODE (inclusive) with 140 svn:mergeinfo properties. 141 */ 142 svn_error_t *svn_fs_fs__dag_get_mergeinfo_count(apr_int64_t *count, 143 dag_node_t *node); 144 145 /* Set *DO_THEY to a flag indicating whether or not NODE is a 146 directory with at least one descendant (not including itself) with 147 svn:mergeinfo. 148 */ 149 svn_error_t * 150 svn_fs_fs__dag_has_descendants_with_mergeinfo(svn_boolean_t *do_they, 151 dag_node_t *node); 152 153 /* Set *HAS_MERGEINFO to a flag indicating whether or not NODE itself 154 has svn:mergeinfo set on it. 155 */ 156 svn_error_t * 157 svn_fs_fs__dag_has_mergeinfo(svn_boolean_t *has_mergeinfo, 158 dag_node_t *node); 159 160 /* Return non-zero IFF NODE is currently mutable. */ 161 svn_boolean_t svn_fs_fs__dag_check_mutable(const dag_node_t *node); 162 163 /* Return the node kind of NODE. */ 164 svn_node_kind_t svn_fs_fs__dag_node_kind(dag_node_t *node); 165 166 /* Set *PROPLIST_P to a PROPLIST hash representing the entire property 167 list of NODE, allocating from POOL. The hash has const char * 168 names (the property names) and svn_string_t * values (the property 169 values). 170 171 If properties do not exist on NODE, *PROPLIST_P will be set to 172 NULL. 173 174 Use POOL for all allocations. 175 */ 176 svn_error_t *svn_fs_fs__dag_get_proplist(apr_hash_t **proplist_p, 177 dag_node_t *node, 178 apr_pool_t *pool); 179 180 /* Set *HAS_PROPS to TRUE if NODE has properties. Use SCRATCH_POOL 181 for temporary allocations */ 182 svn_error_t *svn_fs_fs__dag_has_props(svn_boolean_t *has_props, 183 dag_node_t *node, 184 apr_pool_t *scratch_pool); 185 186 /* Set the property list of NODE to PROPLIST, allocating from POOL. 187 The node being changed must be mutable. 188 189 Use POOL for all allocations. 190 */ 191 svn_error_t *svn_fs_fs__dag_set_proplist(dag_node_t *node, 192 apr_hash_t *proplist, 193 apr_pool_t *pool); 194 195 /* Increment the mergeinfo_count field on NODE by INCREMENT. The node 196 being changed must be mutable. 197 198 Use POOL for all allocations. 199 */ 200 svn_error_t *svn_fs_fs__dag_increment_mergeinfo_count(dag_node_t *node, 201 apr_int64_t increment, 202 apr_pool_t *pool); 203 204 /* Set the has-mergeinfo flag on NODE to HAS_MERGEINFO. The node 205 being changed must be mutable. 206 207 Use POOL for all allocations. 208 */ 209 svn_error_t *svn_fs_fs__dag_set_has_mergeinfo(dag_node_t *node, 210 svn_boolean_t has_mergeinfo, 211 apr_pool_t *pool); 212 213 214 215 /* Revision and transaction roots. */ 216 217 218 /* Open the root of revision REV of filesystem FS, allocating from 219 POOL. Set *NODE_P to the new node. */ 220 svn_error_t *svn_fs_fs__dag_revision_root(dag_node_t **node_p, 221 svn_fs_t *fs, 222 svn_revnum_t rev, 223 apr_pool_t *pool); 224 225 226 /* Set *NODE_P to the root of transaction TXN_ID in FS, allocating 227 from POOL. 228 229 Note that the root node of TXN_ID is not necessarily mutable. If 230 no changes have been made in the transaction, then it may share its 231 root directory with its base revision. To get a mutable root node 232 for a transaction, call svn_fs_fs__dag_clone_root. */ 233 svn_error_t *svn_fs_fs__dag_txn_root(dag_node_t **node_p, 234 svn_fs_t *fs, 235 const svn_fs_fs__id_part_t *txn_id, 236 apr_pool_t *pool); 237 238 239 /* Set *NODE_P to the base root of transaction TXN_ID in FS, 240 allocating from POOL. Allocate the node in TRAIL->pool. */ 241 svn_error_t *svn_fs_fs__dag_txn_base_root(dag_node_t **node_p, 242 svn_fs_t *fs, 243 const svn_fs_fs__id_part_t *txn_id, 244 apr_pool_t *pool); 245 246 247 /* Clone the root directory of TXN_ID in FS, and update the 248 `transactions' table entry to point to it, unless this has been 249 done already. In either case, set *ROOT_P to a reference to the 250 root directory clone. Allocate *ROOT_P in POOL. */ 251 svn_error_t *svn_fs_fs__dag_clone_root(dag_node_t **root_p, 252 svn_fs_t *fs, 253 const svn_fs_fs__id_part_t *txn_id, 254 apr_pool_t *pool); 255 256 257 258 /* Directories. */ 259 260 261 /* Open the node named NAME in the directory PARENT. Set *CHILD_P to 262 the new node, allocated in RESULT_POOL. NAME must be a single path 263 component; it cannot be a slash-separated directory path. If NAME does 264 not exist within PARENT, set *CHILD_P to NULL. 265 */ 266 svn_error_t * 267 svn_fs_fs__dag_open(dag_node_t **child_p, 268 dag_node_t *parent, 269 const char *name, 270 apr_pool_t *result_pool, 271 apr_pool_t *scratch_pool); 272 273 274 /* Set *ENTRIES_P to an array of NODE's entries, sorted by entry names, 275 and the values are svn_fs_dirent_t's. The returned table (and elements) 276 is allocated in POOL, which is also used for temporary allocations. */ 277 svn_error_t *svn_fs_fs__dag_dir_entries(apr_array_header_t **entries_p, 278 dag_node_t *node, 279 apr_pool_t *pool); 280 281 /* Fetches the NODE's entries and returns a copy of the entry selected 282 by the key value given in NAME and set *DIRENT to a copy of that 283 entry. If such entry was found, the copy will be allocated in 284 RESULT_POOL. Temporary data will be used in SCRATCH_POOL. 285 Otherwise, the *DIRENT will be set to NULL. 286 */ 287 /* ### This function is currently only called from dag.c. */ 288 svn_error_t * svn_fs_fs__dag_dir_entry(svn_fs_dirent_t **dirent, 289 dag_node_t *node, 290 const char* name, 291 apr_pool_t *result_pool, 292 apr_pool_t *scratch_pool); 293 294 /* Set ENTRY_NAME in NODE to point to ID (with kind KIND), allocating 295 from POOL. NODE must be a mutable directory. ID can refer to a 296 mutable or immutable node. If ENTRY_NAME does not exist, it will 297 be created. TXN_ID is the Subversion transaction under which this 298 occurs. 299 300 Use POOL for all allocations, including to cache the node_revision in 301 NODE. 302 */ 303 svn_error_t *svn_fs_fs__dag_set_entry(dag_node_t *node, 304 const char *entry_name, 305 const svn_fs_id_t *id, 306 svn_node_kind_t kind, 307 const svn_fs_fs__id_part_t *txn_id, 308 apr_pool_t *pool); 309 310 311 /* Make a new mutable clone of the node named NAME in PARENT, and 312 adjust PARENT's directory entry to point to it, unless NAME in 313 PARENT already refers to a mutable node. In either case, set 314 *CHILD_P to a reference to the new node, allocated in POOL. PARENT 315 must be mutable. NAME must be a single path component; it cannot 316 be a slash-separated directory path. PARENT_PATH must be the 317 canonicalized absolute path of the parent directory. 318 319 COPY_ID, if non-NULL, is a key into the `copies' table, and 320 indicates that this new node is being created as the result of a 321 copy operation, and specifically which operation that was. 322 323 PATH is the canonicalized absolute path at which this node is being 324 created. 325 326 TXN_ID is the Subversion transaction under which this occurs. 327 328 Use POOL for all allocations. 329 */ 330 svn_error_t *svn_fs_fs__dag_clone_child(dag_node_t **child_p, 331 dag_node_t *parent, 332 const char *parent_path, 333 const char *name, 334 const svn_fs_fs__id_part_t *copy_id, 335 const svn_fs_fs__id_part_t *txn_id, 336 svn_boolean_t is_parent_copyroot, 337 apr_pool_t *pool); 338 339 340 /* Delete the directory entry named NAME from PARENT, allocating from 341 POOL. PARENT must be mutable. NAME must be a single path 342 component; it cannot be a slash-separated directory path. If the 343 node being deleted is a mutable directory, remove all mutable nodes 344 reachable from it. TXN_ID is the Subversion transaction under 345 which this occurs. 346 347 If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in 348 PARENT. 349 350 Use POOL for all allocations. 351 */ 352 svn_error_t *svn_fs_fs__dag_delete(dag_node_t *parent, 353 const char *name, 354 const svn_fs_fs__id_part_t *txn_id, 355 apr_pool_t *pool); 356 357 358 /* Delete the node revision assigned to node ID from FS's `nodes' 359 table, allocating from POOL. Also delete any mutable 360 representations and strings associated with that node revision. ID 361 may refer to a file or directory, which must be mutable. 362 363 NOTE: If ID represents a directory, and that directory has mutable 364 children, you risk orphaning those children by leaving them 365 dangling, disconnected from all DAG trees. It is assumed that 366 callers of this interface know what in the world they are doing. */ 367 svn_error_t *svn_fs_fs__dag_remove_node(svn_fs_t *fs, 368 const svn_fs_id_t *id, 369 apr_pool_t *pool); 370 371 372 /* Delete all mutable node revisions reachable from node ID, including 373 ID itself, from FS's `nodes' table, allocating from POOL. Also 374 delete any mutable representations and strings associated with that 375 node revision. ID may refer to a file or directory, which may be 376 mutable or immutable. */ 377 svn_error_t *svn_fs_fs__dag_delete_if_mutable(svn_fs_t *fs, 378 const svn_fs_id_t *id, 379 apr_pool_t *pool); 380 381 382 /* Create a new mutable directory named NAME in PARENT. Set *CHILD_P 383 to a reference to the new node, allocated in POOL. The new 384 directory has no contents, and no properties. PARENT must be 385 mutable. NAME must be a single path component; it cannot be a 386 slash-separated directory path. PARENT_PATH must be the 387 canonicalized absolute path of the parent directory. PARENT must 388 not currently have an entry named NAME. TXN_ID is the Subversion 389 transaction under which this occurs. 390 391 Use POOL for all allocations. 392 */ 393 svn_error_t *svn_fs_fs__dag_make_dir(dag_node_t **child_p, 394 dag_node_t *parent, 395 const char *parent_path, 396 const char *name, 397 const svn_fs_fs__id_part_t *txn_id, 398 apr_pool_t *pool); 399 400 401 402 /* Files. */ 403 404 405 /* Set *CONTENTS to a readable generic stream which yields the 406 contents of FILE. Allocate the stream in POOL. 407 408 If FILE is not a file, return SVN_ERR_FS_NOT_FILE. 409 410 Use POOL for all allocations. 411 */ 412 svn_error_t *svn_fs_fs__dag_get_contents(svn_stream_t **contents, 413 dag_node_t *file, 414 apr_pool_t *pool); 415 416 /* Attempt to fetch the contents of NODE and pass it along with the BATON 417 to the PROCESSOR. Set *SUCCESS only of the data could be provided 418 and the processor had been called. 419 420 Use POOL for all allocations. 421 */ 422 svn_error_t * 423 svn_fs_fs__dag_try_process_file_contents(svn_boolean_t *success, 424 dag_node_t *node, 425 svn_fs_process_contents_func_t processor, 426 void* baton, 427 apr_pool_t *pool); 428 429 430 /* Set *STREAM_P to a delta stream that will turn the contents of SOURCE into 431 the contents of TARGET, allocated in POOL. If SOURCE is null, the empty 432 string will be used. 433 434 Use POOL for all allocations. 435 */ 436 svn_error_t * 437 svn_fs_fs__dag_get_file_delta_stream(svn_txdelta_stream_t **stream_p, 438 dag_node_t *source, 439 dag_node_t *target, 440 apr_pool_t *pool); 441 442 /* Return a generic writable stream in *CONTENTS with which to set the 443 contents of FILE. Allocate the stream in POOL. 444 445 Any previous edits on the file will be deleted, and a new edit 446 stream will be constructed. 447 448 Use POOL for all allocations. 449 */ 450 svn_error_t *svn_fs_fs__dag_get_edit_stream(svn_stream_t **contents, 451 dag_node_t *file, 452 apr_pool_t *pool); 453 454 455 /* Signify the completion of edits to FILE made using the stream 456 returned by svn_fs_fs__dag_get_edit_stream, allocating from POOL. 457 458 If CHECKSUM is non-null, it must match the checksum for FILE's 459 contents (note: this is not recalculated, the recorded checksum is 460 used), else the error SVN_ERR_CHECKSUM_MISMATCH is returned. 461 462 This operation is a no-op if no edits are present. 463 464 Use POOL for all allocations, including to cache the node_revision in 465 FILE. 466 */ 467 svn_error_t *svn_fs_fs__dag_finalize_edits(dag_node_t *file, 468 const svn_checksum_t *checksum, 469 apr_pool_t *pool); 470 471 472 /* Set *LENGTH to the length of the contents of FILE. 473 474 Use POOL for all allocations. 475 */ 476 svn_error_t *svn_fs_fs__dag_file_length(svn_filesize_t *length, 477 dag_node_t *file, 478 apr_pool_t *pool); 479 480 /* Put the recorded checksum of type KIND for FILE into CHECKSUM, allocating 481 from POOL. 482 483 If no stored checksum is available, do not calculate the checksum, 484 just put NULL into CHECKSUM. 485 486 Use POOL for all allocations. 487 */ 488 svn_error_t * 489 svn_fs_fs__dag_file_checksum(svn_checksum_t **checksum, 490 dag_node_t *file, 491 svn_checksum_kind_t kind, 492 apr_pool_t *pool); 493 494 /* Create a new mutable file named NAME in PARENT. Set *CHILD_P to a 495 reference to the new node, allocated in POOL. The new file's 496 contents are the empty string, and it has no properties. PARENT 497 must be mutable. NAME must be a single path component; it cannot 498 be a slash-separated directory path. PARENT_PATH must be the 499 canonicalized absolute path of the parent directory. TXN_ID is the 500 Subversion transaction under which this occurs. 501 502 Use POOL for all allocations. 503 */ 504 svn_error_t *svn_fs_fs__dag_make_file(dag_node_t **child_p, 505 dag_node_t *parent, 506 const char *parent_path, 507 const char *name, 508 const svn_fs_fs__id_part_t *txn_id, 509 apr_pool_t *pool); 510 511 512 513 /* Copies */ 514 515 /* Make ENTRY in TO_NODE be a copy of FROM_NODE, allocating from POOL. 516 TO_NODE must be mutable. TXN_ID is the Subversion transaction 517 under which this occurs. 518 519 If PRESERVE_HISTORY is true, the new node will record that it was 520 copied from FROM_PATH in FROM_REV; therefore, FROM_NODE should be 521 the node found at FROM_PATH in FROM_REV, although this is not 522 checked. FROM_PATH should be canonicalized before being passed 523 here. 524 525 If PRESERVE_HISTORY is false, FROM_PATH and FROM_REV are ignored. 526 527 Use POOL for all allocations. 528 */ 529 svn_error_t *svn_fs_fs__dag_copy(dag_node_t *to_node, 530 const char *entry, 531 dag_node_t *from_node, 532 svn_boolean_t preserve_history, 533 svn_revnum_t from_rev, 534 const char *from_path, 535 const svn_fs_fs__id_part_t *txn_id, 536 apr_pool_t *pool); 537 538 539 /* Comparison */ 540 541 /* Find out what is the same between two nodes. If STRICT is FALSE, 542 this function may report false positives, i.e. report changes even 543 if the resulting contents / props are equal. 544 545 If PROPS_CHANGED is non-null, set *PROPS_CHANGED to 1 if the two 546 nodes have different property lists, or to 0 if same. 547 548 If CONTENTS_CHANGED is non-null, set *CONTENTS_CHANGED to 1 if the 549 two nodes have different contents, or to 0 if same. NODE1 and NODE2 550 must refer to files from the same filesystem. 551 552 Use POOL for temporary allocations. 553 */ 554 svn_error_t *svn_fs_fs__dag_things_different(svn_boolean_t *props_changed, 555 svn_boolean_t *contents_changed, 556 dag_node_t *node1, 557 dag_node_t *node2, 558 svn_boolean_t strict, 559 apr_pool_t *pool); 560 561 562 /* Set *REV and *PATH to the copyroot revision and path of node NODE, or 563 to SVN_INVALID_REVNUM and NULL if no copyroot exists. 564 */ 565 svn_error_t *svn_fs_fs__dag_get_copyroot(svn_revnum_t *rev, 566 const char **path, 567 dag_node_t *node); 568 569 /* Set *REV to the copyfrom revision associated with NODE. 570 */ 571 svn_error_t *svn_fs_fs__dag_get_copyfrom_rev(svn_revnum_t *rev, 572 dag_node_t *node); 573 574 /* Set *PATH to the copyfrom path associated with NODE. 575 */ 576 svn_error_t *svn_fs_fs__dag_get_copyfrom_path(const char **path, 577 dag_node_t *node); 578 579 /* Update *TARGET so that SOURCE is it's predecessor. 580 */ 581 svn_error_t * 582 svn_fs_fs__dag_update_ancestry(dag_node_t *target, 583 dag_node_t *source, 584 apr_pool_t *pool); 585 #ifdef __cplusplus 586 } 587 #endif /* __cplusplus */ 588 589 #endif /* SVN_LIBSVN_FS_DAG_H */ 590