aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_fs/dag.h
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_fs/dag.h')
-rw-r--r--subversion/libsvn_fs_fs/dag.h581
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 */