diff options
Diffstat (limited to 'subversion/libsvn_fs_fs/dag.h')
-rw-r--r-- | subversion/libsvn_fs_fs/dag.h | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/subversion/libsvn_fs_fs/dag.h b/subversion/libsvn_fs_fs/dag.h new file mode 100644 index 000000000000..867b025f1723 --- /dev/null +++ b/subversion/libsvn_fs_fs/dag.h @@ -0,0 +1,581 @@ +/* dag.h : DAG-like interface filesystem, private to libsvn_fs + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#ifndef SVN_LIBSVN_FS_DAG_H +#define SVN_LIBSVN_FS_DAG_H + +#include "svn_fs.h" +#include "svn_delta.h" +#include "private/svn_cache.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* The interface in this file provides all the essential filesystem + operations, but exposes the filesystem's DAG structure. This makes + it simpler to implement than the public interface, since a client + of this interface has to understand and cope with shared structure + directly as it appears in the database. However, it's still a + self-consistent set of invariants to maintain, making it + (hopefully) a useful interface boundary. + + In other words: + + - The dag_node_t interface exposes the internal DAG structure of + the filesystem, while the svn_fs.h interface does any cloning + necessary to make the filesystem look like a tree. + + - The dag_node_t interface exposes the existence of copy nodes, + whereas the svn_fs.h handles them transparently. + + - dag_node_t's must be explicitly cloned, whereas the svn_fs.h + operations make clones implicitly. + + - Callers of the dag_node_t interface use Berkeley DB transactions + to ensure consistency between operations, while callers of the + svn_fs.h interface use Subversion transactions. */ + + +/* Generic DAG node stuff. */ + +typedef struct dag_node_t dag_node_t; + +/* Fill *NODE with a dag_node_t representing node revision ID in FS, + allocating in POOL. */ +svn_error_t * +svn_fs_fs__dag_get_node(dag_node_t **node, + svn_fs_t *fs, + const svn_fs_id_t *id, + apr_pool_t *pool); + + +/* Return a new dag_node_t object referring to the same node as NODE, + allocated in POOL. If you're trying to build a structure in a + pool that wants to refer to dag nodes that may have been allocated + elsewhere, you can call this function and avoid inter-pool pointers. */ +dag_node_t * +svn_fs_fs__dag_dup(const dag_node_t *node, + apr_pool_t *pool); + +/* Serialize a DAG node, except don't try to preserve the 'fs' member. + Implements svn_cache__serialize_func_t */ +svn_error_t * +svn_fs_fs__dag_serialize(void **data, + apr_size_t *data_len, + void *in, + apr_pool_t *pool); + +/* Deserialize a DAG node, leaving the 'fs' member as NULL. + Implements svn_cache__deserialize_func_t */ +svn_error_t * +svn_fs_fs__dag_deserialize(void **out, + void *data, + apr_size_t data_len, + apr_pool_t *pool); + +/* Return the filesystem containing NODE. */ +svn_fs_t *svn_fs_fs__dag_get_fs(dag_node_t *node); + +/* Changes the filesystem containing NODE to FS. (Used when pulling + nodes out of a shared cache, say.) */ +void svn_fs_fs__dag_set_fs(dag_node_t *node, svn_fs_t *fs); + + +/* Set *REV to NODE's revision number, allocating in POOL. If NODE + has never been committed as part of a revision, set *REV to + SVN_INVALID_REVNUM. */ +svn_error_t *svn_fs_fs__dag_get_revision(svn_revnum_t *rev, + dag_node_t *node, + apr_pool_t *pool); + + +/* Return the node revision ID of NODE. The value returned is shared + with NODE, and will be deallocated when NODE is. */ +const svn_fs_id_t *svn_fs_fs__dag_get_id(const dag_node_t *node); + + +/* Return the created path of NODE. The value returned is shared + with NODE, and will be deallocated when NODE is. */ +const char *svn_fs_fs__dag_get_created_path(dag_node_t *node); + + +/* Set *ID_P to the node revision ID of NODE's immediate predecessor, + or NULL if NODE has no predecessor. + */ +svn_error_t *svn_fs_fs__dag_get_predecessor_id(const svn_fs_id_t **id_p, + dag_node_t *node); + + +/* Set *COUNT to the number of predecessors NODE has (recursively), or + -1 if not known. + */ +/* ### This function is currently only used by 'verify'. */ +svn_error_t *svn_fs_fs__dag_get_predecessor_count(int *count, + dag_node_t *node); + +/* Set *COUNT to the number of node under NODE (inclusive) with + svn:mergeinfo properties. + */ +svn_error_t *svn_fs_fs__dag_get_mergeinfo_count(apr_int64_t *count, + dag_node_t *node); + +/* Set *DO_THEY to a flag indicating whether or not NODE is a + directory with at least one descendant (not including itself) with + svn:mergeinfo. + */ +svn_error_t * +svn_fs_fs__dag_has_descendants_with_mergeinfo(svn_boolean_t *do_they, + dag_node_t *node); + +/* Set *HAS_MERGEINFO to a flag indicating whether or not NODE itself + has svn:mergeinfo set on it. + */ +svn_error_t * +svn_fs_fs__dag_has_mergeinfo(svn_boolean_t *has_mergeinfo, + dag_node_t *node); + +/* Return non-zero IFF NODE is currently mutable. */ +svn_boolean_t svn_fs_fs__dag_check_mutable(const dag_node_t *node); + +/* Return the node kind of NODE. */ +svn_node_kind_t svn_fs_fs__dag_node_kind(dag_node_t *node); + +/* Set *PROPLIST_P to a PROPLIST hash representing the entire property + list of NODE, allocating from POOL. The hash has const char * + names (the property names) and svn_string_t * values (the property + values). + + If properties do not exist on NODE, *PROPLIST_P will be set to + NULL. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_get_proplist(apr_hash_t **proplist_p, + dag_node_t *node, + apr_pool_t *pool); + +/* Set the property list of NODE to PROPLIST, allocating from POOL. + The node being changed must be mutable. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_set_proplist(dag_node_t *node, + apr_hash_t *proplist, + apr_pool_t *pool); + +/* Increment the mergeinfo_count field on NODE by INCREMENT. The node + being changed must be mutable. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_increment_mergeinfo_count(dag_node_t *node, + apr_int64_t increment, + apr_pool_t *pool); + +/* Set the has-mergeinfo flag on NODE to HAS_MERGEINFO. The node + being changed must be mutable. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_set_has_mergeinfo(dag_node_t *node, + svn_boolean_t has_mergeinfo, + apr_pool_t *pool); + + + +/* Revision and transaction roots. */ + + +/* Open the root of revision REV of filesystem FS, allocating from + POOL. Set *NODE_P to the new node. */ +svn_error_t *svn_fs_fs__dag_revision_root(dag_node_t **node_p, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *pool); + + +/* Set *NODE_P to the root of transaction TXN_ID in FS, allocating + from POOL. + + Note that the root node of TXN_ID is not necessarily mutable. If + no changes have been made in the transaction, then it may share its + root directory with its base revision. To get a mutable root node + for a transaction, call svn_fs_fs__dag_clone_root. */ +svn_error_t *svn_fs_fs__dag_txn_root(dag_node_t **node_p, + svn_fs_t *fs, + const char *txn_id, + apr_pool_t *pool); + + +/* Set *NODE_P to the base root of transaction TXN_ID in FS, + allocating from POOL. Allocate the node in TRAIL->pool. */ +svn_error_t *svn_fs_fs__dag_txn_base_root(dag_node_t **node_p, + svn_fs_t *fs, + const char *txn_id, + apr_pool_t *pool); + + +/* Clone the root directory of TXN_ID in FS, and update the + `transactions' table entry to point to it, unless this has been + done already. In either case, set *ROOT_P to a reference to the + root directory clone. Allocate *ROOT_P in POOL. */ +svn_error_t *svn_fs_fs__dag_clone_root(dag_node_t **root_p, + svn_fs_t *fs, + const char *txn_id, + apr_pool_t *pool); + + + +/* Directories. */ + + +/* Open the node named NAME in the directory PARENT. Set *CHILD_P to + the new node, allocated in RESULT_POOL. NAME must be a single path + component; it cannot be a slash-separated directory path. + */ +svn_error_t * +svn_fs_fs__dag_open(dag_node_t **child_p, + dag_node_t *parent, + const char *name, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/* Set *ENTRIES_P to a hash table of NODE's entries. The keys of the + table are entry names, and the values are svn_fs_dirent_t's. The + returned table (and its keys and values) is allocated in POOL, + which is also used for temporary allocations. */ +svn_error_t *svn_fs_fs__dag_dir_entries(apr_hash_t **entries_p, + dag_node_t *node, + apr_pool_t *pool); + +/* Fetches the NODE's entries and returns a copy of the entry selected + by the key value given in NAME and set *DIRENT to a copy of that + entry. If such entry was found, the copy will be allocated in POOL. + Otherwise, the *DIRENT will be set to NULL. + */ +/* ### This function is currently only called from dag.c. */ +svn_error_t * svn_fs_fs__dag_dir_entry(svn_fs_dirent_t **dirent, + dag_node_t *node, + const char* name, + apr_pool_t *pool); + +/* Set ENTRY_NAME in NODE to point to ID (with kind KIND), allocating + from POOL. NODE must be a mutable directory. ID can refer to a + mutable or immutable node. If ENTRY_NAME does not exist, it will + be created. TXN_ID is the Subversion transaction under which this + occurs. + + Use POOL for all allocations, including to cache the node_revision in + NODE. + */ +svn_error_t *svn_fs_fs__dag_set_entry(dag_node_t *node, + const char *entry_name, + const svn_fs_id_t *id, + svn_node_kind_t kind, + const char *txn_id, + apr_pool_t *pool); + + +/* Make a new mutable clone of the node named NAME in PARENT, and + adjust PARENT's directory entry to point to it, unless NAME in + PARENT already refers to a mutable node. In either case, set + *CHILD_P to a reference to the new node, allocated in POOL. PARENT + must be mutable. NAME must be a single path component; it cannot + be a slash-separated directory path. PARENT_PATH must be the + canonicalized absolute path of the parent directory. + + COPY_ID, if non-NULL, is a key into the `copies' table, and + indicates that this new node is being created as the result of a + copy operation, and specifically which operation that was. + + PATH is the canonicalized absolute path at which this node is being + created. + + TXN_ID is the Subversion transaction under which this occurs. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_clone_child(dag_node_t **child_p, + dag_node_t *parent, + const char *parent_path, + const char *name, + const char *copy_id, + const char *txn_id, + svn_boolean_t is_parent_copyroot, + apr_pool_t *pool); + + +/* Delete the directory entry named NAME from PARENT, allocating from + POOL. PARENT must be mutable. NAME must be a single path + component; it cannot be a slash-separated directory path. If the + node being deleted is a mutable directory, remove all mutable nodes + reachable from it. TXN_ID is the Subversion transaction under + which this occurs. + + If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in + PARENT. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_delete(dag_node_t *parent, + const char *name, + const char *txn_id, + apr_pool_t *pool); + + +/* Delete the node revision assigned to node ID from FS's `nodes' + table, allocating from POOL. Also delete any mutable + representations and strings associated with that node revision. ID + may refer to a file or directory, which must be mutable. + + NOTE: If ID represents a directory, and that directory has mutable + children, you risk orphaning those children by leaving them + dangling, disconnected from all DAG trees. It is assumed that + callers of this interface know what in the world they are doing. */ +svn_error_t *svn_fs_fs__dag_remove_node(svn_fs_t *fs, + const svn_fs_id_t *id, + apr_pool_t *pool); + + +/* Delete all mutable node revisions reachable from node ID, including + ID itself, from FS's `nodes' table, allocating from POOL. Also + delete any mutable representations and strings associated with that + node revision. ID may refer to a file or directory, which may be + mutable or immutable. */ +svn_error_t *svn_fs_fs__dag_delete_if_mutable(svn_fs_t *fs, + const svn_fs_id_t *id, + apr_pool_t *pool); + + +/* Create a new mutable directory named NAME in PARENT. Set *CHILD_P + to a reference to the new node, allocated in POOL. The new + directory has no contents, and no properties. PARENT must be + mutable. NAME must be a single path component; it cannot be a + slash-separated directory path. PARENT_PATH must be the + canonicalized absolute path of the parent directory. PARENT must + not currently have an entry named NAME. TXN_ID is the Subversion + transaction under which this occurs. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_make_dir(dag_node_t **child_p, + dag_node_t *parent, + const char *parent_path, + const char *name, + const char *txn_id, + apr_pool_t *pool); + + + +/* Files. */ + + +/* Set *CONTENTS to a readable generic stream which yields the + contents of FILE. Allocate the stream in POOL. + + If FILE is not a file, return SVN_ERR_FS_NOT_FILE. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_get_contents(svn_stream_t **contents, + dag_node_t *file, + apr_pool_t *pool); + +/* Attempt to fetch the contents of NODE and pass it along with the BATON + to the PROCESSOR. Set *SUCCESS only of the data could be provided + and the processor had been called. + + Use POOL for all allocations. + */ +svn_error_t * +svn_fs_fs__dag_try_process_file_contents(svn_boolean_t *success, + dag_node_t *node, + svn_fs_process_contents_func_t processor, + void* baton, + apr_pool_t *pool); + + +/* Set *STREAM_P to a delta stream that will turn the contents of SOURCE into + the contents of TARGET, allocated in POOL. If SOURCE is null, the empty + string will be used. + + Use POOL for all allocations. + */ +svn_error_t * +svn_fs_fs__dag_get_file_delta_stream(svn_txdelta_stream_t **stream_p, + dag_node_t *source, + dag_node_t *target, + apr_pool_t *pool); + +/* Return a generic writable stream in *CONTENTS with which to set the + contents of FILE. Allocate the stream in POOL. + + Any previous edits on the file will be deleted, and a new edit + stream will be constructed. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_get_edit_stream(svn_stream_t **contents, + dag_node_t *file, + apr_pool_t *pool); + + +/* Signify the completion of edits to FILE made using the stream + returned by svn_fs_fs__dag_get_edit_stream, allocating from POOL. + + If CHECKSUM is non-null, it must match the checksum for FILE's + contents (note: this is not recalculated, the recorded checksum is + used), else the error SVN_ERR_CHECKSUM_MISMATCH is returned. + + This operation is a no-op if no edits are present. + + Use POOL for all allocations, including to cache the node_revision in + FILE. + */ +svn_error_t *svn_fs_fs__dag_finalize_edits(dag_node_t *file, + const svn_checksum_t *checksum, + apr_pool_t *pool); + + +/* Set *LENGTH to the length of the contents of FILE. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_file_length(svn_filesize_t *length, + dag_node_t *file, + apr_pool_t *pool); + +/* Put the recorded checksum of type KIND for FILE into CHECKSUM, allocating + from POOL. + + If no stored checksum is available, do not calculate the checksum, + just put NULL into CHECKSUM. + + Use POOL for all allocations. + */ +svn_error_t * +svn_fs_fs__dag_file_checksum(svn_checksum_t **checksum, + dag_node_t *file, + svn_checksum_kind_t kind, + apr_pool_t *pool); + +/* Create a new mutable file named NAME in PARENT. Set *CHILD_P to a + reference to the new node, allocated in POOL. The new file's + contents are the empty string, and it has no properties. PARENT + must be mutable. NAME must be a single path component; it cannot + be a slash-separated directory path. PARENT_PATH must be the + canonicalized absolute path of the parent directory. TXN_ID is the + Subversion transaction under which this occurs. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_make_file(dag_node_t **child_p, + dag_node_t *parent, + const char *parent_path, + const char *name, + const char *txn_id, + apr_pool_t *pool); + + + +/* Copies */ + +/* Make ENTRY in TO_NODE be a copy of FROM_NODE, allocating from POOL. + TO_NODE must be mutable. TXN_ID is the Subversion transaction + under which this occurs. + + If PRESERVE_HISTORY is true, the new node will record that it was + copied from FROM_PATH in FROM_REV; therefore, FROM_NODE should be + the node found at FROM_PATH in FROM_REV, although this is not + checked. FROM_PATH should be canonicalized before being passed + here. + + If PRESERVE_HISTORY is false, FROM_PATH and FROM_REV are ignored. + + Use POOL for all allocations. + */ +svn_error_t *svn_fs_fs__dag_copy(dag_node_t *to_node, + const char *entry, + dag_node_t *from_node, + svn_boolean_t preserve_history, + svn_revnum_t from_rev, + const char *from_path, + const char *txn_id, + apr_pool_t *pool); + + +/* Comparison */ + +/* Find out what is the same between two nodes. + + If PROPS_CHANGED is non-null, set *PROPS_CHANGED to 1 if the two + nodes have different property lists, or to 0 if same. + + If CONTENTS_CHANGED is non-null, set *CONTENTS_CHANGED to 1 if the + two nodes have different contents, or to 0 if same. For files, + file contents are compared; for directories, the entries lists are + compared. If one is a file and the other is a directory, the one's + contents will be compared to the other's entries list. (Not + terribly useful, I suppose, but that's the caller's business.) + + ### todo: This function only compares rep keys at the moment. This + may leave us with a slight chance of a false positive, though I + don't really see how that would happen in practice. Nevertheless, + it should probably be fixed. + */ +svn_error_t *svn_fs_fs__dag_things_different(svn_boolean_t *props_changed, + svn_boolean_t *contents_changed, + dag_node_t *node1, + dag_node_t *node2); + + +/* Set *REV and *PATH to the copyroot revision and path of node NODE, or + to SVN_INVALID_REVNUM and NULL if no copyroot exists. + */ +svn_error_t *svn_fs_fs__dag_get_copyroot(svn_revnum_t *rev, + const char **path, + dag_node_t *node); + +/* Set *REV to the copyfrom revision associated with NODE. + */ +svn_error_t *svn_fs_fs__dag_get_copyfrom_rev(svn_revnum_t *rev, + dag_node_t *node); + +/* Set *PATH to the copyfrom path associated with NODE. + */ +svn_error_t *svn_fs_fs__dag_get_copyfrom_path(const char **path, + dag_node_t *node); + +/* Update *TARGET so that SOURCE is it's predecessor. + */ +svn_error_t * +svn_fs_fs__dag_update_ancestry(dag_node_t *target, + dag_node_t *source, + apr_pool_t *pool); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_LIBSVN_FS_DAG_H */ |