blob: 23618db9e943edbdb1cd614b3fb69aaf7bd2ea40 [file] [log] [blame]
/* dag.h : DAG-like interface filesystem, private to libsvn_fs
*
* ====================================================================
* Copyright (c) 2000-2002 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
#ifndef SVN_LIBSVN_FS_DAG_H
#define SVN_LIBSVN_FS_DAG_H
#include "svn_fs.h"
#include "db.h"
#include "skel.h"
#include "trail.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. */
/* Initializing a filesystem. */
/* Given a filesystem FS, which contains all the necessary tables,
create the initial revision 0, and the initial root directory. */
svn_error_t *svn_fs__dag_init_fs (svn_fs_t *fs);
/* 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 TRAIL->pool. */
svn_error_t *
svn_fs__dag_get_node (dag_node_t **node,
svn_fs_t *fs,
svn_fs_id_t *id,
trail_t *trail);
/* Return a new dag_node_t object referring to the same node as NODE,
allocated in TRAIL->pool. If you're trying to build a structure in
TRAIL->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__dag_dup (dag_node_t *node,
trail_t *trail);
/* Return the filesystem containing NODE. */
svn_fs_t *svn_fs__dag_get_fs (dag_node_t *node);
/* Set *REV to NODE's revision number, as part of TRAIL. If NODE has
never been committed as part of a revision, set *REV to
SVN_INVALID_REVNUM. */
svn_error_t *svn_fs__dag_get_revision (svn_revnum_t *rev,
dag_node_t *node,
trail_t *trail);
/* 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__dag_get_id (dag_node_t *node);
/* Set IS_MUTABLE to a non-zero value if NODE is currently mutable in
TRAIL, or zero otherwise. */
svn_error_t *svn_fs__dag_check_mutable (svn_boolean_t *is_mutable,
dag_node_t *node,
trail_t *trail);
/* Return the node kind of NODE. */
svn_node_kind_t svn_fs__dag_node_kind (dag_node_t *node);
/* Return true iff NODE is a file/directory. */
int svn_fs__dag_is_file (dag_node_t *node);
int svn_fs__dag_is_directory (dag_node_t *node);
/* Set *PROPLIST_P to a PROPLIST skel representing the entire property
list of NODE, as part of TRAIL. This guarantees that *PROPLIST_P
is well-formed.
The caller must not change the returned skel --- it's shared with
dag.c's internal cache of node contents.
The returned skel is allocated in *either* TRAIL->pool or the pool
NODE was allocated in, at this function's discretion; the caller
must finish using it while both of those remain live. If the
caller needs the property list to live longer, it can use
svn_fs__copy_skel to make its own copy. */
svn_error_t *svn_fs__dag_get_proplist (skel_t **proplist_p,
dag_node_t *node,
trail_t *trail);
/* Set the property list of NODE to PROPLIST, as part of TRAIL. The
node being changed must be mutable. This verifies that PROPLIST is
well-formed. */
svn_error_t *svn_fs__dag_set_proplist (dag_node_t *node,
skel_t *proplist,
trail_t *trail);
/* Revision and transaction roots. */
/* Open the root of revision REV of filesystem FS, as part of TRAIL.
Set *NODE_P to the new node. Allocate the node in TRAIL->pool. */
svn_error_t *svn_fs__dag_revision_root (dag_node_t **node_p,
svn_fs_t *fs,
svn_revnum_t rev,
trail_t *trail);
/* Set *NODE_P to the root of transaction TXN in FS, as part
of TRAIL. Allocate the node in TRAIL->pool.
Note that the root node of TXN 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__dag_clone_root. */
svn_error_t *svn_fs__dag_txn_root (dag_node_t **node_p,
svn_fs_t *fs,
const char *txn,
trail_t *trail);
/* Set *NODE_P to the base root of transaction TXN in FS, as part
of TRAIL. Allocate the node in TRAIL->pool. */
svn_error_t *svn_fs__dag_txn_base_root (dag_node_t **node_p,
svn_fs_t *fs,
const char *txn,
trail_t *trail);
/* Clone the root directory of SVN_TXN 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. Do all this as part of TRAIL, and allocate
*ROOT_P in TRAIL->pool. */
svn_error_t *svn_fs__dag_clone_root (dag_node_t **root_p,
svn_fs_t *fs,
const char *svn_txn,
trail_t *trail);
/* Commit the transaction SVN_TXN in FS, as part of TRAIL. Store the
new revision number in *NEW_REV. This entails:
- marking the tree of mutable nodes at SVN_TXN's root as immutable,
and marking all their contents as stable
- creating a new revision, with SVN_TXN's root as its root directory
- deleting SVN_TXN from `transactions'
Beware! This does not make sure that SVN_TXN is based on the very
latest revision in FS. If the caller doesn't take care of this,
you may lose people's work!
Do any necessary temporary allocation in a subpool of TRAIL->pool.
Consume temporary space at most proportional to the maximum depth
of SVN_TXN's tree of mutable nodes. */
svn_error_t *svn_fs__dag_commit_txn (svn_revnum_t *new_rev,
svn_fs_t *fs,
const char *svn_txn,
trail_t *trail);
/* Directories. */
/* Open the node named NAME in the directory PARENT, as part of TRAIL.
Set *CHILD_P to the new node, allocated in TRAIL->pool. NAME must be a
single path component; it cannot be a slash-separated directory
path. */
svn_error_t *svn_fs__dag_open (dag_node_t **child_p,
dag_node_t *parent,
const char *name,
trail_t *trail);
/* Set *ENTRIES_P to the directory entry list skel of NODE, as part of
TRAIL. The returned skel has the form (ENTRY ...), as described in
`structure'; this function guarantees that *ENTRIES_P is well-formed.
The caller must not modify the returned skel --- it's shared with
dag.c's internal cache of node contents.
The returned skel is allocated in *either* TRAIL->pool or the pool
NODE was allocated in, at this function's discretion; the caller
must finish using it while both of those remain live. If the
caller needs the directory enttry list to live longer, it can use
svn_fs__copy_skel to make its own copy. */
svn_error_t *svn_fs__dag_dir_entries_skel (skel_t **entries_p,
dag_node_t *node,
trail_t *trail);
/* Set *ENTRIES_P to a hash table of NODE's entries, as part of
TRAIL. The keys of the table are entry names, and the values are
svn_fs_dirent_t's.
The returned table is allocated in *either* TRAIL->pool or the pool
NODE was allocated in, at this function's discretion; the caller
must finish using it while both of those remain live. If the
caller needs the table to live longer, it should copy the hash. */
svn_error_t *svn_fs__dag_dir_entries_hash (apr_hash_t **entries_p,
dag_node_t *node,
trail_t *trail);
/* Set ENTRY_NAME in NODE to point to ID, as part of TRAIL.
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. */
svn_error_t *svn_fs__dag_set_entry (dag_node_t *node,
const char *entry_name,
const svn_fs_id_t *id,
trail_t *trail);
/* Make a new mutable clone of the node named NAME in PARENT, and
adjust PARENT's directory entry to point to it, as part of TRAIL,
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
TRAIL->pool. PARENT must be mutable. NAME must be a single path
component; it cannot be a slash-separated directory path. */
svn_error_t *svn_fs__dag_clone_child (dag_node_t **child_p,
dag_node_t *parent,
const char *name,
trail_t *trail);
/* Why do we have both svn_fs__dag_link and svn_fs__dag_rename?
They each have different limitations and abilities (kind of like
superheroes!) that allow them to ensure the consistency of the
filesystem.
- svn_fs__dag_link can't rename mutable nodes. But since CHILD is
immutable, it knows that it's safe to create a new link to it:
mutable nodes must have exactly one parent, while immutable nodes
can be shared arbitrarily.
- svn_fs__dag_rename always deletes one link, and adds another, as
a single atomic operation. Since it preserves the total number
of links to the node being renamed, you can use it on both
mutable nodes (which must always have one parent) and immutable
nodes (which can have as many parents as they please). But by
the same token, you can't use it to create virtual copies, one of
the filesystem's defining features. */
/* Create a link to CHILD in PARENT named NAME, as part of TRAIL.
PARENT must be mutable. CHILD must be immutable. NAME must be a
single path component; it cannot be a slash-separated directory
path.
Note that it is impossible to use this function to create cyclic
directory structures. Since PARENT is mutable, and every parent of
a mutable node is mutable itself, and CHILD is immutable, we know
that CHILD can't be equal to, or a parent of, PARENT. */
svn_error_t *svn_fs__dag_link (dag_node_t *parent,
dag_node_t *child,
const char *name,
trail_t *trail);
/* Rename the node named FROM_NAME in FROM_DIR to TO_NAME in TO_DIR,
as part of TRAIL. FROM_DIR and TO_DIR must both be mutable; the
node being renamed may be either mutable or immutable. FROM_NAME
and TO_NAME must be single path components; they cannot be
slash-separated directory paths.
This function ensures that the rename does not create a cyclic
directory structure, by checking that TO_DIR is not a child of
FROM_DIR. */
svn_error_t *svn_fs__dag_rename (dag_node_t *from_dir, const char *from_name,
dag_node_t * to_dir, const char * to_name,
trail_t *trail);
/* Delete the directory entry named NAME from PARENT, as part of
TRAIL. 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 directory, it must be empty.
If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in
PARENT. */
svn_error_t *svn_fs__dag_delete (dag_node_t *parent,
const char *name,
trail_t *trail);
/* Delete the directory entry named NAME from PARENT, as part of
TRAIL. 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.
If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in
PARENT. */
svn_error_t *svn_fs__dag_delete_tree (dag_node_t *parent,
const char *name,
trail_t *trail);
/* Delete all mutable node revisions reachable from node ID, including
ID itself, from FS's `nodes' table, as part of TRAIL. ID may refer
to a file or directory, which may be mutable or immutable. */
svn_error_t *svn_fs__dag_delete_if_mutable (svn_fs_t *fs,
svn_fs_id_t *id,
trail_t *trail);
/* Create a new mutable directory named NAME in PARENT, as part of
TRAIL. Set *CHILD_P to a reference to the new node, allocated in
TRAIL->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 must not
currently have an entry named NAME. Do any temporary allocation in
TRAIL->pool. */
svn_error_t *svn_fs__dag_make_dir (dag_node_t **child_p,
dag_node_t *parent,
const char *name,
trail_t *trail);
/* Files. */
/* Set *CONTENTS to a readable generic stream which yields the
contents of FILE, as part of TRAIL. Allocate the stream in POOL,
which may or may not be TRAIL->pool.
If FILE is not a file, return SVN_ERR_FS_NOT_FILE. */
svn_error_t *svn_fs__dag_get_contents (svn_stream_t **contents,
dag_node_t *file,
apr_pool_t *pool,
trail_t *trail);
/* Return a generic writable stream in *CONTENTS with which to set the
contents of FILE as part of TRAIL. Allocate the stream in
POOL, which may or may not be TRAIL->pool. */
svn_error_t *svn_fs__dag_get_edit_stream (svn_stream_t **contents,
dag_node_t *file,
apr_pool_t *pool,
trail_t *trail);
/* Signify the completion of edits to FILE made using the stream
returned by svn_fs__dag_get_edit_stream, as part of TRAIL. */
svn_error_t *svn_fs__dag_finalize_edits (dag_node_t *file,
trail_t *trail);
/* Set *LENGTH to the length of the contents of FILE, as part of TRAIL. */
svn_error_t *svn_fs__dag_file_length (apr_size_t *length,
dag_node_t *file,
trail_t *trail);
/* Create a new mutable file named NAME in PARENT, as part of TRAIL.
Set *CHILD_P to a reference to the new node, allocated in
TRAIL->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. */
svn_error_t *svn_fs__dag_make_file (dag_node_t **child_p,
dag_node_t *parent,
const char *name,
trail_t *trail);
/* Copies */
/* Make ENTRY in TO_NODE be a copy of FROM_NODE, as part of TRAIL.
TO_NODE must be mutable.
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.
If PRESERVE_HISTORY is false, FROM_PATH and FROM_REV are ignored. */
svn_error_t *svn_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,
trail_t *trail);
/* If NODE was copied from some other node, set *REV_P and *PATH_P to
the revision and path of the other node, as part of TRAIL.
Allocate *PATH_P in TRAIL->pool.
Else if NODE is not a copy, set *REV_P to SVN_INVALID_REVNUM and
*PATH_P to null. */
svn_error_t *svn_fs__dag_copied_from (svn_revnum_t *rev_p,
const char **path_p,
dag_node_t *node,
trail_t *trail);
/* 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__things_different (int *props_changed,
int *contents_changed,
dag_node_t *node1,
dag_node_t *node2,
trail_t *trail);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_LIBSVN_FS_DAG_H */
/*
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end:
*/