📄 dag.c
字号:
(SVN_ERR_FS_NOT_FILE, NULL,
"Attempted to set textual contents of a *non*-file node");
/* Make sure our node is mutable. */
if (! svn_fs_base__dag_check_mutable (file, txn_id))
return svn_error_createf
(SVN_ERR_FS_NOT_MUTABLE, NULL,
"Attempted to set textual contents of an immutable node");
/* Get the node revision. */
SVN_ERR (get_node_revision (&noderev, file, trail));
/* If this node already has an EDIT-DATA-KEY, destroy the data
associated with that key. */
if (noderev->edit_key)
SVN_ERR (svn_fs_base__delete_rep_if_mutable (fs, noderev->edit_key,
txn_id, trail));
/* Now, let's ensure that we have a new EDIT-DATA-KEY available for
use. */
SVN_ERR (svn_fs_base__get_mutable_rep (&mutable_rep_key, NULL, fs,
txn_id, trail));
/* We made a new rep, so update the node revision. */
noderev->edit_key = mutable_rep_key;
SVN_ERR (svn_fs_bdb__put_node_revision (fs, file->id, noderev, trail));
/* Return a writable stream with which to set new contents. */
SVN_ERR (svn_fs_base__rep_contents_write_stream (&ws, fs, mutable_rep_key,
txn_id, FALSE, trail,
pool));
*contents = ws;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_finalize_edits (dag_node_t *file,
const char *checksum,
const char *txn_id,
trail_t *trail)
{
svn_fs_t *fs = file->fs; /* just for nicer indentation */
node_revision_t *noderev;
const char *old_data_key;
/* Make sure our node is a file. */
if (file->kind != svn_node_file)
return svn_error_createf
(SVN_ERR_FS_NOT_FILE, NULL,
"Attempted to set textual contents of a *non*-file node");
/* Make sure our node is mutable. */
if (! svn_fs_base__dag_check_mutable (file, txn_id))
return svn_error_createf
(SVN_ERR_FS_NOT_MUTABLE, NULL,
"Attempted to set textual contents of an immutable node");
/* Get the node revision. */
SVN_ERR (get_node_revision (&noderev, file, trail));
/* If this node has no EDIT-DATA-KEY, this is a no-op. */
if (! noderev->edit_key)
return SVN_NO_ERROR;
if (checksum)
{
unsigned char digest[APR_MD5_DIGESTSIZE];
const char *hex;
SVN_ERR (svn_fs_base__rep_contents_checksum
(digest, fs, noderev->edit_key, trail));
hex = svn_md5_digest_to_cstring (digest, trail->pool);
if (strcmp (checksum, hex) != 0)
return svn_error_createf
(SVN_ERR_CHECKSUM_MISMATCH,
NULL,
"Checksum mismatch, rep '%s':\n"
" expected: %s\n"
" actual: %s\n",
noderev->edit_key, checksum, hex);
}
/* Now, we want to delete the old representation and replace it with
the new. Of course, we don't actually delete anything until
everything is being properly referred to by the node-revision
skel. */
old_data_key = noderev->data_key;
noderev->data_key = noderev->edit_key;
noderev->edit_key = NULL;
SVN_ERR (svn_fs_bdb__put_node_revision (fs, file->id, noderev, trail));
/* Only *now* can we safely destroy the old representation (if it
even existed in the first place). */
if (old_data_key)
SVN_ERR (svn_fs_base__delete_rep_if_mutable (fs, old_data_key, txn_id,
trail));
return SVN_NO_ERROR;
}
dag_node_t *
svn_fs_base__dag_dup (dag_node_t *node,
apr_pool_t *pool)
{
/* Allocate our new node. */
dag_node_t *new_node = apr_pcalloc (pool, sizeof (*new_node));
new_node->fs = node->fs;
new_node->pool = pool;
new_node->id = svn_fs_base__id_copy (node->id, pool);
new_node->kind = node->kind;
new_node->created_path = apr_pstrdup (pool, node->created_path);
/* Leave new_node->node_revision zero for now, so it'll get read in.
We can get fancy and duplicate node's cache later. */
return new_node;
}
svn_error_t *
svn_fs_base__dag_open (dag_node_t **child_p,
dag_node_t *parent,
const char *name,
trail_t *trail)
{
const svn_fs_id_t *node_id;
/* Ensure that NAME exists in PARENT's entry list. */
SVN_ERR (dir_entry_id_from_node (&node_id, parent, name, trail));
if (! node_id)
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
"Attempted to open non-existent child node '%s'", name);
/* Make sure that NAME is a single path component. */
if (! svn_path_is_single_path_component (name))
return svn_error_createf
(SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL,
"Attempted to open node with an illegal name '%s'", name);
/* Now get the node that was requested. */
return svn_fs_base__dag_get_node (child_p, svn_fs_base__dag_get_fs (parent),
node_id, trail);
}
svn_error_t *
svn_fs_base__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,
trail_t *trail)
{
const svn_fs_id_t *id;
if (preserve_history)
{
node_revision_t *from_noderev, *to_noderev;
const char *copy_id;
svn_fs_t *fs = svn_fs_base__dag_get_fs (from_node);
const svn_fs_id_t *src_id = svn_fs_base__dag_get_id (from_node);
const char *from_txn_id = NULL;
/* Make a copy of the original node revision. */
SVN_ERR (get_node_revision (&from_noderev, from_node, trail));
to_noderev = copy_node_revision (from_noderev, trail->pool);
/* Reserve a copy ID for this new copy. */
SVN_ERR (svn_fs_bdb__reserve_copy_id (©_id, fs, trail));
/* Create a successor with its predecessor pointing at the copy
source. */
to_noderev->predecessor_id = svn_fs_base__id_copy (src_id, trail->pool);
if (to_noderev->predecessor_count != -1)
to_noderev->predecessor_count++;
to_noderev->created_path =
svn_path_join (svn_fs_base__dag_get_created_path (to_node), entry,
trail->pool);
SVN_ERR (svn_fs_base__create_successor (&id, fs, src_id, to_noderev,
copy_id, txn_id, trail));
/* Translate FROM_REV into a transaction ID. */
SVN_ERR (svn_fs_base__rev_get_txn_id (&from_txn_id, fs, from_rev,
trail));
/* Now that we've done the copy, we need to add the information
about the copy to the `copies' table, using the COPY_ID we
reserved above. */
SVN_ERR (svn_fs_bdb__create_copy
(fs, copy_id,
svn_fs_base__canonicalize_abspath (from_path, trail->pool),
from_txn_id, id, copy_kind_real, trail));
/* Finally, add the COPY_ID to the transaction's list of copies
so that, if this transaction is aborted, the `copies' table
entry we added above will be cleaned up. */
SVN_ERR (svn_fs_base__add_txn_copy (fs, txn_id, copy_id, trail));
}
else /* don't preserve history */
{
id = svn_fs_base__dag_get_id (from_node);
}
/* Set the entry in to_node to the new id. */
SVN_ERR (svn_fs_base__dag_set_entry (to_node, entry, id, txn_id, trail));
return SVN_NO_ERROR;
}
/*** Deltification ***/
svn_error_t *
svn_fs_base__dag_deltify (dag_node_t *target,
dag_node_t *source,
svn_boolean_t props_only,
trail_t *trail)
{
node_revision_t *source_nr, *target_nr;
svn_fs_t *fs = svn_fs_base__dag_get_fs (target);
/* Get node revisions for the two nodes. */
SVN_ERR (get_node_revision (&target_nr, target, trail));
SVN_ERR (get_node_revision (&source_nr, source, trail));
/* If TARGET and SOURCE both have properties, and are not sharing a
property key, deltify TARGET's properties. */
if (target_nr->prop_key
&& source_nr->prop_key
&& (strcmp (target_nr->prop_key, source_nr->prop_key)))
SVN_ERR (svn_fs_base__rep_deltify (fs, target_nr->prop_key,
source_nr->prop_key, trail));
/* If we are not only attending to properties, and if TARGET and
SOURCE both have data, and are not sharing a data key, deltify
TARGET's data. */
if ((! props_only)
&& target_nr->data_key
&& source_nr->data_key
&& (strcmp (target_nr->data_key, source_nr->data_key)))
SVN_ERR (svn_fs_base__rep_deltify (fs, target_nr->data_key,
source_nr->data_key, trail));
return SVN_NO_ERROR;
}
/*** Committing ***/
svn_error_t *
svn_fs_base__dag_commit_txn (svn_revnum_t *new_rev,
svn_fs_t *fs,
const char *txn_id,
trail_t *trail)
{
revision_t revision;
svn_string_t date;
/* Add new revision entry to `revisions' table. */
revision.txn_id = txn_id;
if (new_rev)
*new_rev = SVN_INVALID_REVNUM;
SVN_ERR (svn_fs_bdb__put_rev (new_rev, fs, &revision, trail));
/* Promote the unfinished transaction to a committed one. */
SVN_ERR (svn_fs_base__txn_make_committed (fs, txn_id, *new_rev, trail));
/* Set a date on the commit. We wait until now to fetch the date,
so it's definitely newer than any previous revision's date. */
date.data = svn_time_to_cstring (apr_time_now(), trail->pool);
date.len = strlen (date.data);
SVN_ERR (svn_fs_base__set_rev_prop (fs, *new_rev, SVN_PROP_REVISION_DATE,
&date, trail));
return SVN_NO_ERROR;
}
/*** Comparison. ***/
svn_error_t *
svn_fs_base__things_different (svn_boolean_t *props_changed,
svn_boolean_t *contents_changed,
dag_node_t *node1,
dag_node_t *node2,
trail_t *trail)
{
node_revision_t *noderev1, *noderev2;
/* If we have no place to store our results, don't bother doing
anything. */
if (! props_changed && ! contents_changed)
return SVN_NO_ERROR;
/* The the node revision skels for these two nodes. */
SVN_ERR (get_node_revision (&noderev1, node1, trail));
SVN_ERR (get_node_revision (&noderev2, node2, trail));
/* Compare property keys. */
if (props_changed != NULL)
*props_changed = (! svn_fs_base__same_keys (noderev1->prop_key,
noderev2->prop_key));
/* Compare contents keys. */
if (contents_changed != NULL)
*contents_changed = (! svn_fs_base__same_keys (noderev1->data_key,
noderev2->data_key));
return SVN_NO_ERROR;
}
struct is_ancestor_baton
{
const svn_fs_id_t *node1_id;
svn_boolean_t is_ancestor;
svn_boolean_t need_parent; /* TRUE if we only care about parenthood, not
full ancestry */
};
static svn_error_t *
is_ancestor_callback (void *baton,
dag_node_t *node,
svn_boolean_t *done,
trail_t *trail)
{
struct is_ancestor_baton *b = baton;
/* If there is no NODE, then this is the last call, and we didn't
find an ancestor. But if there is ... */
if (node)
{
/* ... compare NODE's ID with the ID we're looking for. */
if (svn_fs_base__id_eq (b->node1_id, svn_fs_base__dag_get_id (node)))
b->is_ancestor = TRUE;
/* Now, if we only are interested in parenthood, we don't care
to look any further than this. */
if (b->need_parent)
*done = TRUE;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_is_ancestor (svn_boolean_t *is_ancestor,
dag_node_t *node1,
dag_node_t *node2,
trail_t *trail)
{
struct is_ancestor_baton baton;
const svn_fs_id_t
*id1 = svn_fs_base__dag_get_id (node1),
*id2 = svn_fs_base__dag_get_id (node2);
/* Pessimism. */
*is_ancestor = FALSE;
/* Ancestry holds relatedness as a prerequisite. */
if (! svn_fs_base__id_check_related (id1, id2))
return SVN_NO_ERROR;
baton.is_ancestor = FALSE;
baton.need_parent = FALSE;
baton.node1_id = id1;
SVN_ERR (svn_fs_base__dag_walk_predecessors (node2, is_ancestor_callback,
&baton, trail));
if (baton.is_ancestor)
*is_ancestor = TRUE;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_is_parent (svn_boolean_t *is_parent,
dag_node_t *node1,
dag_node_t *node2,
trail_t *trail)
{
struct is_ancestor_baton baton;
const svn_fs_id_t
*id1 = svn_fs_base__dag_get_id (node1),
*id2 = svn_fs_base__dag_get_id (node2);
/* Pessimism. */
*is_parent = FALSE;
/* Parentry holds relatedness as a prerequisite. */
if (! svn_fs_base__id_check_related (id1, id2))
return SVN_NO_ERROR;
baton.is_ancestor = FALSE;
baton.need_parent = TRUE;
baton.node1_id = id1;
SVN_ERR (svn_fs_base__dag_walk_predecessors (node2, is_ancestor_callback,
&baton, trail));
if (baton.is_ancestor)
*is_parent = TRUE;
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -