You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by vm...@apache.org on 2012/05/29 03:39:49 UTC
svn commit: r1343447 [8/27] - in /subversion/branches/javahl-ra: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ contrib/server-side/ notes/
notes/api-errata/1.8/ notes/merge-tracking/ subv...
Modified: subversion/branches/javahl-ra/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_delta/path_driver.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_delta/path_driver.c Tue May 29 01:39:41 2012
@@ -44,15 +44,13 @@ typedef struct dir_stack_t
} dir_stack_t;
-/* Call EDITOR's open_directory() function with the PATH and REVISION
- * arguments, and then add the resulting dir baton to the dir baton
- * stack.
+/* Call EDITOR's open_directory() function with the PATH argument, then
+ * add the resulting dir baton to the dir baton stack.
*/
static svn_error_t *
open_dir(apr_array_header_t *db_stack,
const svn_delta_editor_t *editor,
const char *path,
- svn_revnum_t revision,
apr_pool_t *pool)
{
void *parent_db, *db;
@@ -69,7 +67,8 @@ open_dir(apr_array_header_t *db_stack,
/* Call the EDITOR's open_directory function to get a new directory
baton. */
subpool = svn_pool_create(pool);
- SVN_ERR(editor->open_directory(path, parent_db, revision, subpool, &db));
+ SVN_ERR(editor->open_directory(path, parent_db, SVN_INVALID_REVNUM, subpool,
+ &db));
/* Now add the dir baton to the stack. */
item = apr_pcalloc(subpool, sizeof(*item));
@@ -131,13 +130,12 @@ count_components(const char *path)
/*** Public interfaces ***/
svn_error_t *
-svn_delta_path_driver(const svn_delta_editor_t *editor,
- void *edit_baton,
- svn_revnum_t revision,
- const apr_array_header_t *paths,
- svn_delta_path_driver_cb_func_t callback_func,
- void *callback_baton,
- apr_pool_t *pool)
+svn_delta_path_driver2(const svn_delta_editor_t *editor,
+ void *edit_baton,
+ const apr_array_header_t *paths,
+ svn_delta_path_driver_cb_func_t callback_func,
+ void *callback_baton,
+ apr_pool_t *pool)
{
apr_array_header_t *db_stack = apr_array_make(pool, 4, sizeof(void *));
const char *last_path = NULL;
@@ -155,9 +153,6 @@ svn_delta_path_driver(const svn_delta_ed
iterpool = svn_pool_create(pool);
item = apr_pcalloc(subpool, sizeof(*item));
- /* Sort the paths in a depth-first directory-ish order. */
- qsort(paths->elts, paths->nelts, paths->elt_size, svn_sort_compare_paths);
-
/* If the root of the edit is also a target path, we want to call
the callback function to let the user open the root directory and
do what needs to be done. Otherwise, we'll do the open_root()
@@ -171,7 +166,7 @@ svn_delta_path_driver(const svn_delta_ed
}
else
{
- SVN_ERR(editor->open_root(edit_baton, revision, subpool, &db));
+ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, subpool, &db));
}
item->pool = subpool;
item->dir_baton = db;
@@ -238,7 +233,7 @@ svn_delta_path_driver(const svn_delta_ed
rel = apr_pstrmemdup(iterpool, pdir, piece - pdir);
/* Open the subdirectory. */
- SVN_ERR(open_dir(db_stack, editor, rel, revision, pool));
+ SVN_ERR(open_dir(db_stack, editor, rel, pool));
/* If we found a '/', advance our PIECE pointer to
character just after that '/'. Otherwise, we're
Modified: subversion/branches/javahl-ra/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_delta/text_delta.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_delta/text_delta.c Tue May 29 01:39:41 2012
@@ -904,29 +904,54 @@ svn_error_t *svn_txdelta_send_stream(svn
unsigned char *digest,
apr_pool_t *pool)
{
- svn_txdelta_stream_t *txstream;
- svn_error_t *err;
+ svn_txdelta_window_t delta_window = { 0 };
+ svn_txdelta_op_t delta_op;
+ svn_string_t window_data;
+ char read_buf[SVN__STREAM_CHUNK_SIZE + 1];
+ svn_checksum_ctx_t *md5_checksum_ctx;
- /* ### this is a hack. we should simply read from the stream, construct
- ### some windows, and pass those to the handler. there isn't any reason
- ### to crank up a full "diff" algorithm just to copy a stream.
- ###
- ### will fix RSN. */
-
- /* Create a delta stream which converts an *empty* bytestream into the
- target bytestream. */
- svn_txdelta(&txstream, svn_stream_empty(pool), stream, pool);
- err = svn_txdelta_send_txstream(txstream, handler, handler_baton, pool);
+ if (digest)
+ md5_checksum_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
- if (digest && (! err))
+ while (1)
{
- const unsigned char *result_md5;
- result_md5 = svn_txdelta_md5_digest(txstream);
- /* Since err is null, result_md5 "cannot" be null. */
- memcpy(digest, result_md5, APR_MD5_DIGESTSIZE);
+ apr_size_t read_len = SVN__STREAM_CHUNK_SIZE;
+
+ SVN_ERR(svn_stream_read(stream, read_buf, &read_len));
+ if (read_len == 0)
+ break;
+
+ window_data.data = read_buf;
+ window_data.len = read_len;
+
+ delta_op.action_code = svn_txdelta_new;
+ delta_op.offset = 0;
+ delta_op.length = read_len;
+
+ delta_window.tview_len = read_len;
+ delta_window.num_ops = 1;
+ delta_window.ops = &delta_op;
+ delta_window.new_data = &window_data;
+
+ SVN_ERR(handler(&delta_window, handler_baton));
+
+ if (digest)
+ SVN_ERR(svn_checksum_update(md5_checksum_ctx, read_buf, read_len));
+
+ if (read_len < SVN__STREAM_CHUNK_SIZE)
+ break;
}
+ SVN_ERR(handler(NULL, handler_baton));
- return err;
+ if (digest)
+ {
+ svn_checksum_t *md5_checksum;
+
+ SVN_ERR(svn_checksum_final(&md5_checksum, md5_checksum_ctx, pool));
+ memcpy(digest, md5_checksum->digest, APR_MD5_DIGESTSIZE);
+ }
+
+ return SVN_NO_ERROR;
}
svn_error_t *svn_txdelta_send_txstream(svn_txdelta_stream_t *txstream,
Modified: subversion/branches/javahl-ra/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_diff/diff_file.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_diff/diff_file.c Tue May 29 01:39:41 2012
@@ -2043,8 +2043,7 @@ output_line(svn_diff3__file_output_baton
static svn_error_t *
output_marker_eol(svn_diff3__file_output_baton_t *btn)
{
- apr_size_t len = strlen(btn->marker_eol);
- return svn_stream_write(btn->output_stream, btn->marker_eol, &len);
+ return svn_stream_puts(btn->output_stream, btn->marker_eol);
}
static svn_error_t *
@@ -2127,7 +2126,7 @@ output_conflict_with_context(svn_diff3__
if (btn->output_stream == btn->context_saver->stream)
{
if (btn->context_saver->total_written > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
- SVN_ERR(svn_stream_printf(btn->real_output_stream, btn->pool, "@@\n"));
+ SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
}
@@ -2179,7 +2178,6 @@ output_conflict(void *baton,
svn_diff_t *diff)
{
svn_diff3__file_output_baton_t *file_baton = baton;
- apr_size_t len;
svn_diff_conflict_display_style_t style = file_baton->conflict_style;
@@ -2201,33 +2199,28 @@ output_conflict(void *baton,
if (style == svn_diff_conflict_display_modified_latest ||
style == svn_diff_conflict_display_modified_original_latest)
{
- len = strlen(file_baton->conflict_modified);
- SVN_ERR(svn_stream_write(file_baton->output_stream,
- file_baton->conflict_modified,
- &len));
+ SVN_ERR(svn_stream_puts(file_baton->output_stream,
+ file_baton->conflict_modified));
SVN_ERR(output_marker_eol(file_baton));
SVN_ERR(output_hunk(baton, 1, modified_start, modified_length));
if (style == svn_diff_conflict_display_modified_original_latest)
{
- len = strlen(file_baton->conflict_original);
- SVN_ERR(svn_stream_write(file_baton->output_stream,
- file_baton->conflict_original, &len));
+ SVN_ERR(svn_stream_puts(file_baton->output_stream,
+ file_baton->conflict_original));
SVN_ERR(output_marker_eol(file_baton));
SVN_ERR(output_hunk(baton, 0, original_start, original_length));
}
- len = strlen(file_baton->conflict_separator);
- SVN_ERR(svn_stream_write(file_baton->output_stream,
- file_baton->conflict_separator, &len));
+ SVN_ERR(svn_stream_puts(file_baton->output_stream,
+ file_baton->conflict_separator));
SVN_ERR(output_marker_eol(file_baton));
SVN_ERR(output_hunk(baton, 2, latest_start, latest_length));
- len = strlen(file_baton->conflict_latest);
- SVN_ERR(svn_stream_write(file_baton->output_stream,
- file_baton->conflict_latest, &len));
+ SVN_ERR(svn_stream_puts(file_baton->output_stream,
+ file_baton->conflict_latest));
SVN_ERR(output_marker_eol(file_baton));
}
else if (style == svn_diff_conflict_display_modified)
Modified: subversion/branches/javahl-ra/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_diff/diff_memory.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_diff/diff_memory.c Tue May 29 01:39:41 2012
@@ -808,15 +808,13 @@ output_merge_token_range(apr_size_t *lin
static svn_error_t *
output_marker_eol(merge_output_baton_t *btn)
{
- apr_size_t len = strlen(btn->marker_eol);
- return svn_stream_write(btn->output_stream, btn->marker_eol, &len);
+ return svn_stream_puts(btn->output_stream, btn->marker_eol);
}
static svn_error_t *
output_merge_marker(merge_output_baton_t *btn, int idx)
{
- apr_size_t len = strlen(btn->markers[idx]);
- SVN_ERR(svn_stream_write(btn->output_stream, btn->markers[idx], &len));
+ SVN_ERR(svn_stream_puts(btn->output_stream, btn->markers[idx]));
return output_marker_eol(btn);
}
@@ -924,7 +922,7 @@ output_conflict_with_context(void *baton
if (btn->output_stream == btn->context_saver->stream)
{
if (btn->context_saver->total_written > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
- SVN_ERR(svn_stream_printf(btn->real_output_stream, btn->pool, "@@\n"));
+ SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs/editor.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs/editor.c Tue May 29 01:39:41 2012
@@ -28,44 +28,699 @@
#include "svn_pools.h"
#include "svn_editor.h"
#include "svn_fs.h"
+#include "svn_props.h"
+
+#include "svn_private_config.h"
#include "fs-loader.h"
+#include "private/svn_fspath.h"
+
struct edit_baton {
+ /* The transaction associated with this editor. */
svn_fs_txn_t *txn;
- svn_boolean_t no_autocommit;
+
+ /* Has this editor been completed? */
+ svn_boolean_t completed;
+
+ /* We sometimes need the cancellation beyond what svn_editor_t provides */
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
+
+ /* The pool that the txn lives within. When we create a ROOT, it will
+ be allocated within a subpool of this. The root will be closed in
+ complete/abort and that subpool will be destroyed.
+
+ This pool SHOULD NOT be used for any allocations. */
+ apr_pool_t *txn_pool;
+
+ /* This is the root from the txn. Use get_root() to fetch/create this
+ member as appropriate. */
+ svn_fs_root_t *root;
};
+#define FSPATH(relpath, pool) apr_pstrcat(pool, "/", relpath, NULL)
+#define UNUSED(x) ((void)(x))
+
+
+static svn_error_t *
+get_root(svn_fs_root_t **root,
+ struct edit_baton *eb)
+{
+ if (eb->root == NULL)
+ SVN_ERR(svn_fs_txn_root(&eb->root, eb->txn, eb->txn_pool));
+ *root = eb->root;
+ return SVN_NO_ERROR;
+}
+
+
+/* Apply each property in PROPS to the node at FSPATH in ROOT. */
+static svn_error_t *
+add_new_props(svn_fs_root_t *root,
+ const char *fspath,
+ apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_index_t *hi;
+
+ /* ### it would be nice to have svn_fs_set_node_props(). but since we
+ ### don't... add each property to the node. this is a new node, so
+ ### we don't need to worry about deleting props. just adding. */
+
+ for (hi = apr_hash_first(scratch_pool, props); hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *name = svn__apr_hash_index_key(hi);
+ const svn_string_t *value = svn__apr_hash_index_val(hi);
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_fs_change_node_prop(root, fspath, name, value, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+alter_props(svn_fs_root_t *root,
+ const char *fspath,
+ apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_t *old_props;
+ apr_array_header_t *propdiffs;
+ int i;
+
+ SVN_ERR(svn_fs_node_proplist(&old_props, root, fspath, scratch_pool));
+
+ SVN_ERR(svn_prop_diffs(&propdiffs, props, old_props, scratch_pool));
+
+ for (i = 0; i < propdiffs->nelts; ++i)
+ {
+ const svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
+
+ svn_pool_clear(iterpool);
+
+ /* Add, change, or delete properties. */
+ SVN_ERR(svn_fs_change_node_prop(root, fspath, prop->name, prop->value,
+ iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+set_text(svn_fs_root_t *root,
+ const char *fspath,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_stream_t *fs_contents;
+
+ /* ### We probably don't have an MD5 checksum, so no digest is available
+ ### for svn_fs_apply_text() to validate. It would be nice to have an
+ ### FS API that takes our CHECKSUM/CONTENTS pair (and PROPS!). */
+ SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath,
+ NULL /* result_checksum */,
+ scratch_pool));
+ SVN_ERR(svn_stream_copy3(contents, fs_contents,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* The caller wants to modify REVISION of FSPATH. Is that allowed? */
+static svn_error_t *
+can_modify(svn_fs_root_t *txn_root,
+ const char *fspath,
+ svn_revnum_t revision,
+ apr_pool_t *scratch_pool)
+{
+ svn_revnum_t created_rev;
+
+ /* Out-of-dateness check: compare the created-rev of the node
+ in the txn against the created-rev of FSPATH. */
+ SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
+ scratch_pool));
+
+ /* Uncommitted nodes (eg. a descendent of a copy/move/rotate destination)
+ have no (committed) revision number. Let the caller go ahead and
+ modify these nodes.
+
+ Note: strictly speaking, they might be performing an "illegal" edit
+ in certain cases, but let's just assume they're Good Little Boys.
+
+ If CREATED_REV is invalid, that means it's already mutable in the
+ txn, which means it has already passed this out-of-dateness check.
+ (Usually, this happens when looking at a parent directory of an
+ already-modified node) */
+ if (!SVN_IS_VALID_REVNUM(created_rev))
+ return SVN_NO_ERROR;
+
+ /* If the node is immutable (has a revision), then the caller should
+ have supplied a valid revision number [that they expect to change].
+ The checks further below will determine the out-of-dateness of the
+ specified revision. */
+ /* ### ugh. descendents of copy/move/rotate destinations carry along
+ ### their original immutable state and (thus) a valid CREATED_REV.
+ ### but they are logically uncommitted, so the caller will pass
+ ### SVN_INVALID_REVNUM. (technically, the caller could provide
+ ### ORIGINAL_REV, but that is semantically incorrect for the Ev2
+ ### API).
+ ###
+ ### for now, we will assume the caller knows what they are doing
+ ### and an invalid revision implies such a descendent. in the
+ ### future, we could examine the ancestor chain looking for a
+ ### copy/move/rotate-here node and allow the modification (and the
+ ### converse: if no such ancestor, the caller must specify the
+ ### correct/intended revision to modify).
+ */
+#if 1
+ if (!SVN_IS_VALID_REVNUM(revision))
+ return SVN_NO_ERROR;
+#else
+ if (!SVN_IS_VALID_REVNUM(revision))
+ /* ### use a custom error code? */
+ return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+ N_("Revision for modifying '%s' is required"),
+ fspath);
+#endif
+
+ if (revision < created_rev)
+ {
+ /* We asked to change a node that is *older* than what we found
+ in the transaction. The client is out of date. */
+ return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
+ _("'%s' is out of date; try updating"),
+ fspath);
+ }
+
+ if (revision > created_rev)
+ {
+ /* We asked to change a node that is *newer* than what we found
+ in the transaction. Given that the transaction was based off
+ of 'youngest', then either:
+ - the caller asked to modify a future node
+ - the caller has committed more revisions since this txn
+ was constructed, and is asking to modify a node in one
+ of those new revisions.
+ In either case, the node may not have changed in those new
+ revisions; use the node's ID to determine this case. */
+ const svn_fs_id_t *txn_noderev_id;
+ svn_fs_root_t *rev_root;
+ const svn_fs_id_t *new_noderev_id;
+
+ /* The ID of the node that we would be modifying in the txn */
+ SVN_ERR(svn_fs_node_id(&txn_noderev_id, txn_root, fspath,
+ scratch_pool));
+
+ /* Get the ID from the future/new revision. */
+ SVN_ERR(svn_fs_revision_root(&rev_root, svn_fs_root_fs(txn_root),
+ revision, scratch_pool));
+ SVN_ERR(svn_fs_node_id(&new_noderev_id, rev_root, fspath,
+ scratch_pool));
+ svn_fs_close_root(rev_root);
+
+ /* Has the target node changed in the future? */
+ if (svn_fs_compare_ids(txn_noderev_id, new_noderev_id) != 0)
+ {
+ /* Restarting the commit will base the txn on the future/new
+ revision, allowing the modification at REVISION. */
+ /* ### use a custom error code */
+ return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
+ _("'%s' has been modified since the "
+ "commit began (restart the commit)"),
+ fspath);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Can we create a node at FSPATH in TXN_ROOT? If something already exists
+ at that path, then the client MAY be out of date. We then have to see if
+ the path was created/modified in this transaction. IOW, it is new and
+ can be replaced without problem.
+
+ Note: the editor protocol disallows double-modifications. This is to
+ ensure somebody does not accidentally overwrite another file due to
+ being out-of-date. */
+static svn_error_t *
+can_create(svn_fs_root_t *txn_root,
+ const char *fspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t kind;
+ const char *cur_fspath;
+
+ SVN_ERR(svn_fs_check_path(&kind, txn_root, fspath, scratch_pool));
+ if (kind == svn_node_none)
+ return SVN_NO_ERROR;
+
+ /* ### I'm not sure if this works perfectly. We might have an ancestor
+ ### that was modified as a result of a change on a cousin. We might
+ ### misinterpret that as a *-here node which brought along this
+ ### child. Need to write a test to verify. We may also be able to
+ ### test the ancestor to determine if it has been *-here in this
+ ### txn, or just a simple modification. */
+
+ /* Are any of the parents copied/moved/rotated-here? */
+ for (cur_fspath = fspath;
+ strlen(cur_fspath) > 1; /* not the root */
+ cur_fspath = svn_fspath__dirname(cur_fspath, scratch_pool))
+ {
+ svn_revnum_t created_rev;
+
+ SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, cur_fspath,
+ scratch_pool));
+ if (!SVN_IS_VALID_REVNUM(created_rev))
+ {
+ /* The node has no created revision, meaning it is uncommitted.
+ Thus, it was created in this transaction, or it has already
+ been modified in some way (implying it has already passed a
+ modification check. */
+ /* ### verify the node has been *-here ?? */
+ return SVN_NO_ERROR;
+ }
+ }
+
+ return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
+ _("'%s' already exists, so may be out"
+ " of date; try updating"),
+ fspath);
+}
+
+
+/* This implements svn_editor_cb_add_directory_t */
+static svn_error_t *
+add_directory_cb(void *baton,
+ const char *relpath,
+ const apr_array_header_t *children,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about,
+ so we don't need to be aware of what children will be created. */
+
+ SVN_ERR(get_root(&root, eb));
+
+ if (SVN_IS_VALID_REVNUM(replaces_rev))
+ {
+ SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool));
+ SVN_ERR(svn_fs_delete(root, fspath, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(can_create(root, fspath, scratch_pool));
+ }
+
+ SVN_ERR(svn_fs_make_dir(root, fspath, scratch_pool));
+ SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_file_t */
+static svn_error_t *
+add_file_cb(void *baton,
+ const char *relpath,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ SVN_ERR(get_root(&root, eb));
+
+ if (SVN_IS_VALID_REVNUM(replaces_rev))
+ {
+ SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool));
+ SVN_ERR(svn_fs_delete(root, fspath, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(can_create(root, fspath, scratch_pool));
+ }
+
+ SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool));
+
+ SVN_ERR(set_text(root, fspath, checksum, contents,
+ eb->cancel_func, eb->cancel_baton, scratch_pool));
+ SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_symlink_t */
+static svn_error_t *
+add_symlink_cb(void *baton,
+ const char *relpath,
+ const char *target,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ SVN_ERR(get_root(&root, eb));
+
+ if (SVN_IS_VALID_REVNUM(replaces_rev))
+ {
+ SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool));
+ SVN_ERR(svn_fs_delete(root, fspath, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(can_create(root, fspath, scratch_pool));
+ }
+
+ /* ### we probably need to construct a file with specific contents
+ ### (until the FS grows some symlink APIs) */
+#if 0
+ SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool));
+ SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath,
+ NULL /* result_checksum */,
+ scratch_pool));
+ /* ### SVN_ERR(svn_stream_printf(fs_contents, ..., scratch_pool)); */
+ apr_hash_set(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING,
+ SVN_PROP_SPECIAL_VALUE);
+
+ SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+#endif
+
+ SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_add_absent_t */
+static svn_error_t *
+add_absent_cb(void *baton,
+ const char *relpath,
+ svn_kind_t kind,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ /* This is a programming error. Code should not attempt to create these
+ kinds of nodes within the FS. */
+ /* ### use a custom error code */
+ return svn_error_create(
+ SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ N_("The filesystem does not support 'absent' nodes"));
+}
+
+
+/* This implements svn_editor_cb_alter_directory_t */
+static svn_error_t *
+alter_directory_cb(void *baton,
+ const char *relpath,
+ svn_revnum_t revision,
+ const apr_array_header_t *children,
+ apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about,
+ so we don't need to be aware of what children will be created. */
+
+ SVN_ERR(get_root(&root, eb));
+ SVN_ERR(can_modify(root, fspath, revision, scratch_pool));
+
+ SVN_ERR(alter_props(root, fspath, props, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_file_t */
+static svn_error_t *
+alter_file_cb(void *baton,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_hash_t *props,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ SVN_ERR(get_root(&root, eb));
+ SVN_ERR(can_modify(root, fspath, revision, scratch_pool));
+
+ if (contents != NULL)
+ {
+ SVN_ERR_ASSERT(checksum != NULL);
+ SVN_ERR(set_text(root, fspath, checksum, contents,
+ eb->cancel_func, eb->cancel_baton, scratch_pool));
+ }
+
+ if (props != NULL)
+ {
+ SVN_ERR(alter_props(root, fspath, props, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_symlink_t */
+static svn_error_t *
+alter_symlink_cb(void *baton,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_hash_t *props,
+ const char *target,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+
+ UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_delete_t */
+static svn_error_t *
+delete_cb(void *baton,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *fspath = FSPATH(relpath, scratch_pool);
+ svn_fs_root_t *root;
+
+ SVN_ERR(get_root(&root, eb));
+ SVN_ERR(can_modify(root, fspath, revision, scratch_pool));
+
+ SVN_ERR(svn_fs_delete(root, fspath, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_copy_t */
+static svn_error_t *
+copy_cb(void *baton,
+ const char *src_relpath,
+ svn_revnum_t src_revision,
+ const char *dst_relpath,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *src_fspath = FSPATH(src_relpath, scratch_pool);
+ const char *dst_fspath = FSPATH(dst_relpath, scratch_pool);
+ svn_fs_root_t *root;
+ svn_fs_root_t *src_root;
+
+ SVN_ERR(get_root(&root, eb));
+
+ /* Check if we can we replace the maybe-specified destination (revision). */
+ if (SVN_IS_VALID_REVNUM(replaces_rev))
+ {
+ SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool));
+ SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(can_create(root, dst_fspath, scratch_pool));
+ }
+
+ SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision,
+ scratch_pool));
+ SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool));
+ svn_fs_close_root(src_root);
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_move_t */
+static svn_error_t *
+move_cb(void *baton,
+ const char *src_relpath,
+ svn_revnum_t src_revision,
+ const char *dst_relpath,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *src_fspath = FSPATH(src_relpath, scratch_pool);
+ const char *dst_fspath = FSPATH(dst_relpath, scratch_pool);
+ svn_fs_root_t *root;
+ svn_fs_root_t *src_root;
+
+ SVN_ERR(get_root(&root, eb));
+
+ /* Check if we delete the specified source (revision), and can we replace
+ the maybe-specified destination (revision). */
+ SVN_ERR(can_modify(root, src_fspath, src_revision, scratch_pool));
+ if (SVN_IS_VALID_REVNUM(replaces_rev))
+ {
+ SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool));
+ SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(can_create(root, dst_fspath, scratch_pool));
+ }
+
+ /* ### would be nice to have svn_fs_move() */
+
+ /* Copy the src to the dst. */
+ SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision,
+ scratch_pool));
+ SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool));
+ svn_fs_close_root(src_root);
+
+ /* Notice: we're deleting the src repos path from the dst root. */
+ SVN_ERR(svn_fs_delete(root, src_fspath, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_rotate_t */
+static svn_error_t *
+rotate_cb(void *baton,
+ const apr_array_header_t *relpaths,
+ const apr_array_header_t *revisions,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+
+ UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_complete_t */
+static svn_error_t *
+complete_cb(void *baton,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+
+ /* Watch out for a following call to svn_fs_editor_commit(). Note that
+ we are likely here because svn_fs_editor_commit() was called, and it
+ invoked svn_editor_complete(). */
+ eb->completed = TRUE;
+
+ if (eb->root != NULL)
+ {
+ svn_fs_close_root(eb->root);
+ eb->root = NULL;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_error_t *err;
+
+ /* Don't allow a following call to svn_fs_editor_commit(). */
+ eb->completed = TRUE;
+
+ if (eb->root != NULL)
+ {
+ svn_fs_close_root(eb->root);
+ eb->root = NULL;
+ }
+
+ /* ### should we examine the error and attempt svn_fs_purge_txn() ? */
+ err = svn_fs_abort_txn(eb->txn, scratch_pool);
+
+ /* For safety, clear the now-useless txn. */
+ eb->txn = NULL;
+
+ return svn_error_trace(err);
+}
+
static svn_error_t *
make_editor(svn_editor_t **editor,
svn_fs_txn_t *txn,
- svn_boolean_t no_autocommit,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
static const svn_editor_cb_many_t editor_cbs = {
- NULL /* add_directory_cb */,
- NULL /* add_file_cb */,
- NULL /* add_symlink_cb */,
- NULL /* add_absent_cb */,
- NULL /* alter_directory_cb */,
- NULL /* alter_file_cb */,
- NULL /* alter_symlink_cb */,
- NULL /* delete_cb */,
- NULL /* copy_cb */,
- NULL /* move_cb */,
- NULL /* rotate_cb */,
- NULL /* complete_cb */,
- NULL /* abort_cb */
+ add_directory_cb,
+ add_file_cb,
+ add_symlink_cb,
+ add_absent_cb,
+ alter_directory_cb,
+ alter_file_cb,
+ alter_symlink_cb,
+ delete_cb,
+ copy_cb,
+ move_cb,
+ rotate_cb,
+ complete_cb,
+ abort_cb
};
- struct edit_baton *eb = apr_palloc(result_pool, sizeof(*eb));
+ struct edit_baton *eb = apr_pcalloc(result_pool, sizeof(*eb));
eb->txn = txn;
- eb->no_autocommit = no_autocommit;
+ eb->cancel_func = cancel_func;
+ eb->cancel_baton = cancel_baton;
+ eb->txn_pool = result_pool;
SVN_ERR(svn_editor_create(editor, eb, cancel_func, cancel_baton,
result_pool, scratch_pool));
@@ -79,19 +734,19 @@ svn_error_t *
svn_fs_editor_create(svn_editor_t **editor,
const char **txn_name,
svn_fs_t *fs,
- svn_revnum_t revision,
apr_uint32_t flags,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ svn_revnum_t revision;
svn_fs_txn_t *txn;
- svn_boolean_t no_autocommit = (flags & SVN_FS_TXN_NO_AUTOCOMMIT) != 0;
+ SVN_ERR(svn_fs_youngest_rev(&revision, fs, scratch_pool));
SVN_ERR(svn_fs_begin_txn2(&txn, fs, revision, flags, result_pool));
SVN_ERR(svn_fs_txn_name(txn_name, txn, result_pool));
- return svn_error_trace(make_editor(editor, txn, no_autocommit,
+ return svn_error_trace(make_editor(editor, txn,
cancel_func, cancel_baton,
result_pool, scratch_pool));
}
@@ -109,8 +764,84 @@ svn_fs_editor_create_for(svn_editor_t **
svn_fs_txn_t *txn;
SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, result_pool));
- return svn_error_trace(make_editor(editor, txn, TRUE /* no_autocommit */,
+ return svn_error_trace(make_editor(editor, txn,
cancel_func, cancel_baton,
result_pool, scratch_pool));
}
+
+svn_error_t *
+svn_fs_editor_commit(svn_revnum_t *revision,
+ svn_error_t **post_commit_err,
+ const char **conflict_path,
+ svn_editor_t *editor,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = svn_editor_get_baton(editor);
+ const char *inner_conflict_path;
+ svn_error_t *err = NULL;
+
+ /* make sure people are using the correct sequencing. */
+ if (eb->completed)
+ return svn_error_create(SVN_ERR_FS_INCORRECT_EDITOR_COMPLETION,
+ NULL, NULL);
+
+ *revision = SVN_INVALID_REVNUM;
+ *post_commit_err = NULL;
+ *conflict_path = NULL;
+
+ /* Clean up internal resources (eg. eb->root). This also allows the
+ editor infrastructure to know this editor is "complete". */
+ err = svn_editor_complete(editor);
+
+ /* Note: docco for svn_fs_commit_txn() states that CONFLICT_PATH will
+ be allocated in the txn's pool. But it lies. Regardless, we want
+ it placed into RESULT_POOL. */
+
+ if (!err)
+ err = svn_fs_commit_txn(&inner_conflict_path,
+ revision,
+ eb->txn,
+ scratch_pool);
+ if (SVN_IS_VALID_REVNUM(*revision))
+ {
+ if (err)
+ {
+ /* Case 3. ERR is a post-commit (cleanup) error. */
+
+ /* Pass responsibility via POST_COMMIT_ERR. */
+ *post_commit_err = err;
+ err = SVN_NO_ERROR;
+ }
+ /* else: Case 1. */
+ }
+ else
+ {
+ SVN_ERR_ASSERT(err != NULL);
+ if (err->apr_err == SVN_ERR_FS_CONFLICT)
+ {
+ /* Case 2. */
+
+ /* Copy this into the correct pool (see note above). */
+ *conflict_path = apr_pstrdup(result_pool, inner_conflict_path);
+
+ /* Return sucess. The caller should inspect CONFLICT_PATH to
+ determine this particular case. */
+ svn_error_clear(err);
+ err = SVN_NO_ERROR;
+ }
+ /* else: Case 4. */
+
+ /* Abort the TXN. Nobody wants to use it. */
+ /* ### should we examine the error and attempt svn_fs_purge_txn() ? */
+ err = svn_error_compose_create(
+ err,
+ svn_fs_abort_txn(eb->txn, scratch_pool));
+ }
+
+ /* For safety, clear the now-useless txn. */
+ eb->txn = NULL;
+
+ return svn_error_trace(err);
+}
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.c Tue May 29 01:39:41 2012
@@ -44,6 +44,7 @@
#include "private/svn_fs_util.h"
#include "private/svn_utf_private.h"
#include "private/svn_mutex.h"
+#include "private/svn_subr_private.h"
#include "fs-loader.h"
#include "svn_hash.h"
@@ -336,6 +337,7 @@ fs_new(apr_hash_t *fs_config, apr_pool_t
fs->access_ctx = NULL;
fs->vtable = NULL;
fs->fsap_data = NULL;
+ fs->uuid = NULL;
return fs;
}
@@ -645,6 +647,7 @@ svn_error_t *
svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
svn_fs_txn_t *txn, apr_pool_t *pool)
{
+ svn_error_t *err;
#ifdef PACK_AFTER_EVERY_COMMIT
svn_fs_root_t *txn_root;
svn_fs_t *fs;
@@ -656,11 +659,25 @@ svn_fs_commit_txn(const char **conflict_
fs_path = svn_fs_path(fs, pool);
#endif
- SVN_ERR(txn->vtable->commit(conflict_p, new_rev, txn, pool));
+ err = txn->vtable->commit(conflict_p, new_rev, txn, pool);
+
+#ifdef SVN_DEBUG
+ /* Check postconditions. */
+ if (conflict_p)
+ {
+ SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL),
+ err);
+ SVN_ERR_ASSERT_E((*conflict_p != NULL)
+ == (err && err->apr_err == SVN_ERR_FS_CONFLICT),
+ err);
+ }
+#endif
+
+ SVN_ERR(err);
#ifdef PACK_AFTER_EVERY_COMMIT
{
- svn_error_t *err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
+ err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
/* Pre-1.6 filesystem. */
svn_error_clear(err);
@@ -1218,7 +1235,9 @@ svn_fs_get_file_delta_stream(svn_txdelta
svn_error_t *
svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
{
- return svn_error_trace(fs->vtable->get_uuid(fs, uuid, pool));
+ /* If you change this, consider changing svn_fs__identifier(). */
+ *uuid = apr_pstrdup(pool, fs->uuid);
+ return SVN_NO_ERROR;
}
svn_error_t *
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.h?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.h Tue May 29 01:39:41 2012
@@ -172,7 +172,7 @@ typedef struct fs_vtable_t
const svn_string_t *const *old_value_p,
const svn_string_t *value,
apr_pool_t *pool);
- svn_error_t *(*get_uuid)(svn_fs_t *fs, const char **uuid, apr_pool_t *pool);
+ /* There is no get_uuid(); see svn_fs_t.uuid docstring. */
svn_error_t *(*set_uuid)(svn_fs_t *fs, const char *uuid, apr_pool_t *pool);
svn_error_t *(*revision_root)(svn_fs_root_t **root_p, svn_fs_t *fs,
svn_revnum_t rev, apr_pool_t *pool);
@@ -391,6 +391,9 @@ struct svn_fs_t
/* FSAP-specific vtable and private data */
fs_vtable_t *vtable;
void *fsap_data;
+
+ /* UUID, stored by open(), create(), and set_uuid(). */
+ const char *uuid;
};
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/lock-tokens-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/lock-tokens-table.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/lock-tokens-table.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/lock-tokens-table.c Tue May 29 01:39:41 2012
@@ -104,7 +104,7 @@ svn_fs_bdb__lock_token_delete(svn_fs_t *
svn_fs_base__trail_debug(trail, "lock-tokens", "del");
db_err = bfd->lock_tokens->del(bfd->lock_tokens, trail->db_txn, &key, 0);
if (db_err == DB_NOTFOUND)
- return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
+ return SVN_FS__ERR_NO_SUCH_LOCK(fs, path);
return BDB_WRAP(fs, "deleting entry from 'lock-tokens' table", db_err);
}
@@ -131,7 +131,7 @@ svn_fs_bdb__lock_token_get(const char **
svn_fs_base__track_dbt(&value, pool);
if (db_err == DB_NOTFOUND)
- return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
+ return SVN_FS__ERR_NO_SUCH_LOCK(fs, path);
SVN_ERR(BDB_WRAP(fs, "reading lock token", db_err));
lock_token = apr_pstrmemdup(pool, value.data, value.size);
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/locks-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/locks-table.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/locks-table.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/locks-table.c Tue May 29 01:39:41 2012
@@ -153,7 +153,7 @@ svn_fs_bdb__lock_get(svn_lock_t **lock_p
if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
{
SVN_ERR(svn_fs_bdb__lock_delete(fs, lock_token, trail, pool));
- return SVN_FS__ERR_LOCK_EXPIRED(fs, lock_token, pool);
+ return SVN_FS__ERR_LOCK_EXPIRED(fs, lock_token);
}
*lock_p = lock;
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/err.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/err.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/err.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/err.c Tue May 29 01:39:41 2012
@@ -62,10 +62,11 @@ svn_fs_base__err_dangling_id(svn_fs_t *f
svn_error_t *
svn_fs_base__err_dangling_rev(svn_fs_t *fs, svn_revnum_t rev)
{
+ /* Log the UUID as this error may be reported to the client. */
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_REVISION, 0,
_("No such revision %ld in filesystem '%s'"),
- rev, fs->path);
+ rev, fs->uuid);
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.c Tue May 29 01:39:41 2012
@@ -473,15 +473,6 @@ bdb_write_config(svn_fs_t *fs)
-static svn_error_t *
-base_serialized_init(svn_fs_t *fs, apr_pool_t *common_pool, apr_pool_t *pool)
-{
- /* Nothing to do here. */
- return SVN_NO_ERROR;
-}
-
-
-
/* Creating a new filesystem */
static fs_vtable_t fs_vtable = {
@@ -489,7 +480,6 @@ static fs_vtable_t fs_vtable = {
svn_fs_base__revision_prop,
svn_fs_base__revision_proplist,
svn_fs_base__change_rev_prop,
- svn_fs_base__get_uuid,
svn_fs_base__set_uuid,
svn_fs_base__revision_root,
svn_fs_base__begin_txn,
@@ -656,6 +646,15 @@ open_databases(svn_fs_t *fs,
}
+/* Called by functions that initialize an svn_fs_t struct, after that
+ initialization is done, to populate svn_fs_t->uuid. */
+static svn_error_t *
+populate_opened_fs(svn_fs_t *fs, apr_pool_t *scratch_pool)
+{
+ SVN_ERR(svn_fs_base__populate_uuid(fs, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
base_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
apr_pool_t *common_pool)
@@ -691,7 +690,9 @@ base_create(svn_fs_t *fs, const char *pa
if (svn_err) goto error;
((base_fs_data_t *) fs->fsap_data)->format = format;
- return base_serialized_init(fs, common_pool, pool);
+
+ SVN_ERR(populate_opened_fs(fs, pool));
+ return SVN_NO_ERROR;;
error:
svn_error_clear(cleanup_fs(fs));
@@ -775,7 +776,8 @@ base_open(svn_fs_t *fs, const char *path
if (svn_err) goto error;
}
- return base_serialized_init(fs, common_pool, pool);
+ SVN_ERR(populate_opened_fs(fs, pool));
+ return SVN_NO_ERROR;
error:
svn_error_clear(cleanup_fs(fs));
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.h?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.h Tue May 29 01:39:41 2012
@@ -108,9 +108,6 @@ typedef struct base_fs_data_t
transaction trail alive. */
svn_boolean_t in_txn_trail;
- /* The filesystem UUID (or NULL if not-yet-known; see svn_fs_get_uuid). */
- const char *uuid;
-
/* The format number of this FS. */
int format;
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/lock.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/lock.c Tue May 29 01:39:41 2012
@@ -93,7 +93,7 @@ txn_body_lock(void *baton, trail_t *trai
/* Until we implement directory locks someday, we only allow locks
on files or non-existent paths. */
if (kind == svn_node_dir)
- return SVN_FS__ERR_NOT_FILE(trail->fs, args->path, trail->pool);
+ return SVN_FS__ERR_NOT_FILE(trail->fs, args->path);
/* While our locking implementation easily supports the locking of
nonexistent paths, we deliberately choose not to allow such madness. */
@@ -113,7 +113,7 @@ txn_body_lock(void *baton, trail_t *trai
/* There better be a username attached to the fs. */
if (!trail->fs->access_ctx || !trail->fs->access_ctx->username)
- return SVN_FS__ERR_NO_USER(trail->fs, trail->pool);
+ return SVN_FS__ERR_NO_USER(trail->fs);
/* Is the caller attempting to lock an out-of-date working file? */
if (SVN_IS_VALID_REVNUM(args->current_rev))
@@ -179,8 +179,7 @@ txn_body_lock(void *baton, trail_t *trai
{
/* Sorry, the path is already locked. */
return SVN_FS__ERR_PATH_ALREADY_LOCKED(trail->fs,
- existing_lock,
- trail->pool);
+ existing_lock);
}
else
{
@@ -282,22 +281,21 @@ txn_body_unlock(void *baton, trail_t *tr
if (args->token == NULL)
return svn_fs_base__err_no_lock_token(trail->fs, args->path);
else if (strcmp(lock_token, args->token) != 0)
- return SVN_FS__ERR_NO_SUCH_LOCK(trail->fs, args->path, trail->pool);
+ return SVN_FS__ERR_NO_SUCH_LOCK(trail->fs, args->path);
SVN_ERR(svn_fs_bdb__lock_get(&lock, trail->fs, lock_token,
trail, trail->pool));
/* There better be a username attached to the fs. */
if (!trail->fs->access_ctx || !trail->fs->access_ctx->username)
- return SVN_FS__ERR_NO_USER(trail->fs, trail->pool);
+ return SVN_FS__ERR_NO_USER(trail->fs);
/* And that username better be the same as the lock's owner. */
if (strcmp(trail->fs->access_ctx->username, lock->owner) != 0)
return SVN_FS__ERR_LOCK_OWNER_MISMATCH(
trail->fs,
trail->fs->access_ctx->username,
- lock->owner,
- trail->pool);
+ lock->owner);
}
/* Remove a row from each of the locking tables. */
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/tree.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/tree.c Tue May 29 01:39:41 2012
@@ -431,7 +431,7 @@ mutable_root_node(dag_node_t **node_p,
trail, pool);
else
/* If it's not a transaction root, we can't change its contents. */
- return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path, pool);
+ return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path);
}
@@ -769,7 +769,7 @@ open_path(parent_path_t **parent_path_p,
/* The path isn't finished yet; we'd better be in a directory. */
if (svn_fs_base__dag_node_kind(child) != svn_node_dir)
- SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far, pool),
+ SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far),
apr_psprintf(pool, _("Failure opening '%s'"), path));
rest = next;
@@ -2926,7 +2926,7 @@ txn_body_make_dir(void *baton,
/* If there's already a sub-directory by that name, complain. This
also catches the case of trying to make a subdirectory named `/'. */
if (parent_path->node)
- return SVN_FS__ALREADY_EXISTS(root, path, trail->pool);
+ return SVN_FS__ALREADY_EXISTS(root, path);
/* Check to see if some lock is 'reserving' a file-path or dir-path
at that location, or even some child-path; if so, check that we
@@ -3192,17 +3192,7 @@ fs_same_p(svn_boolean_t *same_p,
svn_fs_t *fs2,
apr_pool_t *pool)
{
- const char *uuid1;
- const char *uuid2;
-
- /* Random thought: if fetching UUIDs to compare filesystems is too
- expensive, one solution would be to cache the UUID in each fs
- object (copying the UUID into fs->pool, of course). */
-
- SVN_ERR(fs1->vtable->get_uuid(fs1, &uuid1, pool));
- SVN_ERR(fs2->vtable->get_uuid(fs2, &uuid2, pool));
-
- *same_p = ! strcmp(uuid1, uuid2);
+ *same_p = ! strcmp(fs1->uuid, fs2->uuid);
return SVN_NO_ERROR;
}
@@ -3379,7 +3369,7 @@ txn_body_make_file(void *baton,
/* If there's already a file by that name, complain.
This also catches the case of trying to make a file named `/'. */
if (parent_path->node)
- return SVN_FS__ALREADY_EXISTS(root, path, trail->pool);
+ return SVN_FS__ALREADY_EXISTS(root, path);
/* Check to see if some lock is 'reserving' a file-path or dir-path
at that location, or even some child-path; if so, check that we
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.c Tue May 29 01:39:41 2012
@@ -48,39 +48,27 @@ txn_body_get_uuid(void *baton, trail_t *
svn_error_t *
-svn_fs_base__get_uuid(svn_fs_t *fs,
- const char **uuid,
- apr_pool_t *pool)
+svn_fs_base__populate_uuid(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
{
- base_fs_data_t *bfd = fs->fsap_data;
SVN_ERR(svn_fs__check_fs(fs, TRUE));
- /* Check for a cached UUID first. Failing that, we hit the
- database. */
- if (bfd->uuid)
- {
- *uuid = apr_pstrdup(pool, bfd->uuid);
- }
- else
+ /* We hit the database. */
{
+ const char *uuid;
struct get_uuid_args args;
- apr_pool_t *scratch_pool = svn_pool_create(pool);
args.idx = 1;
- args.uuid = uuid;
+ args.uuid = &uuid;
SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_get_uuid, &args,
FALSE, scratch_pool));
- if (*uuid)
+ if (uuid)
{
- *uuid = apr_pstrdup(pool, *uuid);
-
/* Toss what we find into the cache. */
- bfd->uuid = apr_pstrdup(fs->pool, *uuid);
+ fs->uuid = apr_pstrdup(fs->pool, uuid);
}
-
- svn_pool_destroy(scratch_pool);
}
return SVN_NO_ERROR;
@@ -109,7 +97,6 @@ svn_fs_base__set_uuid(svn_fs_t *fs,
apr_pool_t *pool)
{
struct set_uuid_args args;
- base_fs_data_t *bfd = fs->fsap_data;
SVN_ERR(svn_fs__check_fs(fs, TRUE));
@@ -122,7 +109,7 @@ svn_fs_base__set_uuid(svn_fs_t *fs,
/* Toss our value into the cache. */
if (uuid)
- bfd->uuid = apr_pstrdup(fs->pool, uuid);
+ fs->uuid = apr_pstrdup(fs->pool, uuid);
return SVN_NO_ERROR;
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.h?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_base/uuid.h Tue May 29 01:39:41 2012
@@ -29,12 +29,15 @@ extern "C" {
+/* Set FS->UUID to the the value read from the database, allocated
+ in FS->POOL. Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *svn_fs_base__populate_uuid(svn_fs_t *fs,
+ apr_pool_t *scratch_pool);
+
+
/* These functions implement some of the calls in the FS loader
library's fs vtable. */
-svn_error_t *svn_fs_base__get_uuid(svn_fs_t *fs, const char **uuid,
- apr_pool_t *pool);
-
svn_error_t *svn_fs_base__set_uuid(svn_fs_t *fs, const char *uuid,
apr_pool_t *pool);
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/caching.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/caching.c Tue May 29 01:39:41 2012
@@ -33,6 +33,7 @@
#include "svn_private_config.h"
#include "svn_hash.h"
#include "private/svn_debug.h"
+#include "private/svn_subr_private.h"
/* Return a memcache in *MEMCACHE_P for FS if it's configured to use
memcached, or NULL otherwise. Also, sets *FAIL_STOP to a boolean
@@ -252,7 +253,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
{
fs_fs_data_t *ffd = fs->fsap_data;
const char *prefix = apr_pstrcat(pool,
- "fsfs:", ffd->uuid,
+ "fsfs:", fs->uuid,
"/", fs->path, ":",
(char *)NULL);
svn_memcache_t *memcache;
@@ -495,7 +496,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
to start a new transaction later that receives the same id.
Therefore, throw in a uuid as well - just to be sure. */
const char *prefix = apr_pstrcat(pool,
- "fsfs:", ffd->uuid,
+ "fsfs:", fs->uuid,
"/", fs->path,
":", txn_id,
":", svn_uuid_generate(pool), ":",
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/dag.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/dag.c Tue May 29 01:39:41 2012
@@ -778,11 +778,9 @@ svn_fs_fs__dag_delete(dag_node_t *parent
subpool = svn_pool_create(pool);
- /* Get a dirent hash for this directory. */
- SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, parent_noderev, subpool));
-
- /* Find name in the ENTRIES hash. */
- dirent = apr_hash_get(entries, name, APR_HASH_KEY_STRING);
+ /* Search this directory for a dirent with that NAME. */
+ SVN_ERR(svn_fs_fs__rep_contents_dir_entry(&dirent, fs, parent_noderev,
+ name, subpool, subpool));
/* If we never found ID in ENTRIES (perhaps because there are no
ENTRIES, perhaps because ID just isn't in the existing ENTRIES
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.c Tue May 29 01:39:41 2012
@@ -73,7 +73,8 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
know of a better way of associating such data with the
repository. */
- key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, ffd->uuid,
+ SVN_ERR_ASSERT(fs->uuid);
+ key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, fs->uuid,
(char *) NULL);
status = apr_pool_userdata_get(&val, key, common_pool);
if (status)
@@ -130,7 +131,6 @@ static fs_vtable_t fs_vtable = {
svn_fs_fs__revision_prop,
svn_fs_fs__revision_proplist,
svn_fs_fs__change_rev_prop,
- svn_fs_fs__get_uuid,
svn_fs_fs__set_uuid,
svn_fs_fs__revision_root,
svn_fs_fs__begin_txn,
@@ -294,10 +294,18 @@ fs_hotcopy(svn_fs_t *src_fs,
void *cancel_baton,
apr_pool_t *pool)
{
+ SVN_ERR(svn_fs__check_fs(src_fs, FALSE));
SVN_ERR(initialize_fs_struct(src_fs));
+ SVN_ERR(svn_fs_fs__open(src_fs, src_path, pool));
+ SVN_ERR(svn_fs_fs__initialize_caches(src_fs, pool));
SVN_ERR(fs_serialized_init(src_fs, pool, pool));
+
+ SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
SVN_ERR(initialize_fs_struct(dst_fs));
- SVN_ERR(fs_serialized_init(dst_fs, pool, pool));
+ /* In INCREMENTAL mode, svn_fs_fs__hotcopy() will open DST_FS.
+ Otherwise, it's not an FS yet --- possibly just an empty dir --- so
+ can't be opened.
+ */
return svn_fs_fs__hotcopy(src_fs, dst_fs, src_path, dst_path,
incremental, cancel_func, cancel_baton, pool);
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.h?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.h Tue May 29 01:39:41 2012
@@ -61,6 +61,8 @@ extern "C" {
#define PATH_LOCKS_DIR "locks" /* Directory of locks */
#define PATH_MIN_UNPACKED_REV "min-unpacked-rev" /* Oldest revision which
has not been packed. */
+#define PATH_REVPROP_GENERATION "revprop-generation"
+ /* Current revprop generation*/
/* If you change this, look at tests/svn_test_fs.c(maybe_install_fsfs_conf) */
#define PATH_CONFIG "fsfs.conf" /* Configuration */
@@ -218,9 +220,6 @@ typedef struct fs_fs_data_t
layouts) or zero (for linear layouts). */
int max_files_per_dir;
- /* The uuid of this FS. */
- const char *uuid;
-
/* The revision that was youngest, last time we checked. */
svn_revnum_t youngest_rev_cache;
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c Tue May 29 01:39:41 2012
@@ -59,7 +59,9 @@
#include "rep-cache.h"
#include "temp_serializer.h"
+#include "private/svn_string_private.h"
#include "private/svn_fs_util.h"
+#include "private/svn_subr_private.h"
#include "../libsvn_fs/fs-loader.h"
#include "svn_private_config.h"
@@ -236,6 +238,12 @@ path_lock(svn_fs_t *fs, apr_pool_t *pool
}
static const char *
+path_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
+{
+ return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool);
+}
+
+static const char *
path_rev_packed(svn_fs_t *fs, svn_revnum_t rev, const char *kind,
apr_pool_t *pool)
{
@@ -1307,7 +1315,7 @@ svn_fs_fs__open(svn_fs_t *fs, const char
limit = sizeof(buf);
SVN_ERR(svn_io_read_length_line(uuid_file, buf, &limit, pool));
- ffd->uuid = apr_pstrdup(fs->pool, buf);
+ fs->uuid = apr_pstrdup(fs->pool, buf);
SVN_ERR(svn_io_file_close(uuid_file, pool));
@@ -2384,7 +2392,7 @@ svn_fs_fs__write_noderev(svn_stream_t *o
noderev->copyroot_path));
if (noderev->is_fresh_txn_root)
- SVN_ERR(svn_stream_printf(outfile, pool, HEADER_FRESHTXNRT ": y\n"));
+ SVN_ERR(svn_stream_puts(outfile, HEADER_FRESHTXNRT ": y\n"));
if (include_mergeinfo)
{
@@ -2394,10 +2402,10 @@ svn_fs_fs__write_noderev(svn_stream_t *o
noderev->mergeinfo_count));
if (noderev->has_mergeinfo)
- SVN_ERR(svn_stream_printf(outfile, pool, HEADER_MINFO_HERE ": y\n"));
+ SVN_ERR(svn_stream_puts(outfile, HEADER_MINFO_HERE ": y\n"));
}
- return svn_stream_printf(outfile, pool, "\n");
+ return svn_stream_puts(outfile, "\n");
}
svn_error_t *
@@ -2800,6 +2808,95 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
return SVN_NO_ERROR;
}
+/* Revprop caching management.
+ *
+ * Revprop caching needs to be activated and will be deactivated for the
+ * respective FS instance if the necessary infrastructure could not be
+ * initialized. In deactivated mode, there is almost no runtime overhead
+ * associated with revprop caching. As long as no revprops are being read
+ * or changed, revprop caching imposes no overhead.
+ *
+ * When activated, we cache revprops using (revision, generation) pairs
+ * as keys with the generation being incremented upon every revprop change.
+ * Since the cache is process-local, the generation needs to be tracked
+ * for at least as long as the process lives but may be reset afterwards.
+ *
+ * To track the revprop generation, we use two-layer approach. On the lower
+ * level, we use named atomics to have a system-wide consistent value for
+ * the current revprop generation. However, those named atomics will only
+ * remain valid for as long as at least one process / thread in the system
+ * accesses revprops in the respective repository. The underlying shared
+ * memory gets cleaned up afterwards.
+ *
+ * On the second level, we will use a persistent file to track the latest
+ * revprop generation. It will be written upon each revprop change but
+ * only be read if we are the first process to initialize the named atomics
+ * with that value.
+ *
+ * The overhead for the second and following accesses to revprops is
+ * almost zero on most systems.
+ */
+
+/* Read revprop generation as stored on disk for repository FS. The result
+ * is returned in *CURRENT. Default to 2 if no such file is available.
+ */
+static svn_error_t *
+read_revprop_generation_file(apr_int64_t *current,
+ svn_fs_t *fs,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+ apr_file_t *file;
+ char buf[80];
+ apr_size_t len;
+ const char *path = path_revprop_generation(fs, pool);
+
+ err = svn_io_file_open(&file, path,
+ APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, pool);
+ if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+ {
+ svn_error_clear(err);
+ *current = 2;
+
+ return SVN_NO_ERROR;
+ }
+ SVN_ERR(err);
+
+ len = sizeof(buf);
+ SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
+
+ /* Check that the first line contains only digits. */
+ SVN_ERR(check_file_buffer_numeric(buf, 0, path,
+ "Revprop Generation", pool));
+ SVN_ERR(svn_cstring_atoi64(current, buf));
+
+ return svn_io_file_close(file, pool);
+}
+
+/* Write the CURRENT revprop generation to disk for repository FS.
+ */
+static svn_error_t *
+write_revprop_generation_file(svn_fs_t *fs,
+ apr_int64_t current,
+ apr_pool_t *pool)
+{
+ apr_file_t *file;
+ const char *tmp_path;
+
+ char buf[SVN_INT64_BUFFER_SIZE];
+ apr_size_t len = svn__i64toa(buf, current);
+ buf[len] = '\n';
+
+ SVN_ERR(svn_io_open_unique_file3(&file, &tmp_path, fs->path,
+ svn_io_file_del_none, pool, pool));
+ SVN_ERR(svn_io_file_write_full(file, buf, len + 1, NULL, pool));
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ return move_into_place(tmp_path, path_revprop_generation(fs, pool),
+ tmp_path, pool);
+}
+
/* Make sure the revprop_namespace member in FS is set. */
static svn_error_t *
ensure_revprop_namespace(svn_fs_t *fs)
@@ -2815,19 +2912,39 @@ ensure_revprop_namespace(svn_fs_t *fs)
: SVN_NO_ERROR;
}
-/* Make sure the revprop_generation member in FS is set. */
+/* Make sure the revprop_generation member in FS is set and, if necessary,
+ * initialized with the latest value stored on disk.
+ */
static svn_error_t *
-ensure_revprop_generation(svn_fs_t *fs)
+ensure_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
SVN_ERR(ensure_revprop_namespace(fs));
- return ffd->revprop_generation == NULL
- ? svn_named_atomic__get(&ffd->revprop_generation,
- ffd->revprop_namespace,
- ATOMIC_REVPROP_GENERATION,
- TRUE)
- : SVN_NO_ERROR;
+ if (ffd->revprop_generation == NULL)
+ {
+ apr_int64_t current = 0;
+
+ SVN_ERR(svn_named_atomic__get(&ffd->revprop_generation,
+ ffd->revprop_namespace,
+ ATOMIC_REVPROP_GENERATION,
+ TRUE));
+
+ /* If the generation is at 0, we just created a new namespace
+ * (it would be at least 2 otherwise). Read the lastest generation
+ * from disk and if we are the first one to initialize the atomic
+ * (i.e. is still 0), set it to the value just gotten.
+ */
+ SVN_ERR(svn_named_atomic__read(¤t, ffd->revprop_generation));
+ if (current == 0)
+ {
+ SVN_ERR(read_revprop_generation_file(¤t, fs, pool));
+ SVN_ERR(svn_named_atomic__cmpxchg(NULL, current, 0,
+ ffd->revprop_generation));
+ }
+ }
+
+ return SVN_NO_ERROR;
}
/* Make sure the revprop_timeout member in FS is set. */
@@ -2848,7 +2965,7 @@ ensure_revprop_timeout(svn_fs_t *fs)
/* Test whether revprop cache and necessary infrastructure are
available in FS. */
static svn_boolean_t
-has_revprop_cache(svn_fs_t *fs)
+has_revprop_cache(svn_fs_t *fs, apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
svn_error_t *error;
@@ -2868,7 +2985,7 @@ has_revprop_cache(svn_fs_t *fs)
}
/* try to access our SHM-backed infrastructure */
- error = ensure_revprop_generation(fs);
+ error = ensure_revprop_generation(fs, pool);
if (error)
{
/* failure -> disable revprop cache for good */
@@ -2887,13 +3004,14 @@ has_revprop_cache(svn_fs_t *fs)
Use the access object in FS to set the shared mem values. */
static svn_error_t *
read_revprop_generation(apr_int64_t *generation,
- svn_fs_t *fs)
+ svn_fs_t *fs,
+ apr_pool_t *pool)
{
apr_int64_t current = 0;
fs_fs_data_t *ffd = fs->fsap_data;
/* read the current revprop generation number */
- SVN_ERR(ensure_revprop_generation(fs));
+ SVN_ERR(ensure_revprop_generation(fs, pool));
SVN_ERR(svn_named_atomic__read(¤t, ffd->revprop_generation));
/* is an unfinished revprop write under the way? */
@@ -2930,7 +3048,7 @@ read_revprop_generation(apr_int64_t *gen
readers shall recover from that state & re-read revprops.
Use the access object in FS to set the shared mem value. */
static svn_error_t *
-begin_revprop_change(svn_fs_t *fs)
+begin_revprop_change(svn_fs_t *fs, apr_pool_t *pool)
{
apr_int64_t current;
fs_fs_data_t *ffd = fs->fsap_data;
@@ -2944,7 +3062,7 @@ begin_revprop_change(svn_fs_t *fs)
/* set the revprop generation to an odd value to indicate
* that a write is in progress
*/
- SVN_ERR(ensure_revprop_generation(fs));
+ SVN_ERR(ensure_revprop_generation(fs, pool));
do
{
SVN_ERR(svn_named_atomic__add(¤t,
@@ -2961,7 +3079,7 @@ begin_revprop_change(svn_fs_t *fs)
b) the write process has been completed (no recovery required)
Use the access object in FS to set the shared mem value. */
static svn_error_t *
-end_revprop_change(svn_fs_t *fs)
+end_revprop_change(svn_fs_t *fs, apr_pool_t *pool)
{
apr_int64_t current = 1;
fs_fs_data_t *ffd = fs->fsap_data;
@@ -2969,7 +3087,7 @@ end_revprop_change(svn_fs_t *fs)
/* set the revprop generation to an even value to indicate
* that a write has been completed
*/
- SVN_ERR(ensure_revprop_generation(fs));
+ SVN_ERR(ensure_revprop_generation(fs, pool));
do
{
SVN_ERR(svn_named_atomic__add(¤t,
@@ -2978,7 +3096,11 @@ end_revprop_change(svn_fs_t *fs)
}
while (current % 2);
- return SVN_NO_ERROR;
+ /* Save the latest generation to disk. FS is currently in a "locked"
+ * state such that we can be sure the be the only ones to write that
+ * file.
+ */
+ return write_revprop_generation_file(fs, current, pool);
}
/* Set the revision property list of revision REV in filesystem FS to
@@ -3000,7 +3122,7 @@ set_revision_proplist(svn_fs_t *fs,
svn_node_kind_t kind = svn_node_none;
/* test whether revprops already exist for this revision */
- if (has_revprop_cache(fs))
+ if (has_revprop_cache(fs, pool))
SVN_ERR(svn_io_check_path(final_path, &kind, pool));
/* ### do we have a directory sitting around already? we really shouldn't
@@ -3020,13 +3142,13 @@ set_revision_proplist(svn_fs_t *fs,
/* Now, we may actually be replacing revprops. Make sure that all other
threads and processes will know about this. */
if (kind != svn_node_none)
- SVN_ERR(begin_revprop_change(fs));
+ SVN_ERR(begin_revprop_change(fs, pool));
SVN_ERR(move_into_place(tmp_path, final_path, perms_reference, pool));
/* Indicate that the update (if relevant) has been completed. */
if (kind != svn_node_none)
- SVN_ERR(end_revprop_change(fs));
+ SVN_ERR(end_revprop_change(fs, pool));
}
return SVN_NO_ERROR;
@@ -3045,12 +3167,12 @@ revision_proplist(apr_hash_t **proplist_
SVN_ERR(ensure_revision_exists(fs, rev, pool));
/* Try cache lookup first. */
- if (has_revprop_cache(fs))
+ if (has_revprop_cache(fs, pool))
{
apr_int64_t generation;
svn_boolean_t is_cached;
- SVN_ERR(read_revprop_generation(&generation, fs));
+ SVN_ERR(read_revprop_generation(&generation, fs, pool));
key = svn_fs_fs__combine_two_numbers(rev, generation, pool);
SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
@@ -3114,7 +3236,7 @@ revision_proplist(apr_hash_t **proplist_
}
/* Cache the result, if caching has been activated. */
- if (has_revprop_cache(fs))
+ if (has_revprop_cache(fs, pool))
SVN_ERR(svn_cache__set(ffd->revprop_cache, key, proplist, pool));
*proplist_p = proplist;
@@ -4729,20 +4851,37 @@ fetch_all_changes(apr_hash_t *changed_pa
{
apr_hash_index_t *hi;
+ /* a potential child path must contain at least 2 more chars
+ (the path separator plus at least one char for the name).
+ Also, we should not assume that all paths have been normalized
+ i.e. some might have trailing path separators.
+ */
+ apr_ssize_t change_path_len = strlen(change->path);
+ apr_ssize_t min_child_len = change_path_len == 0
+ ? 1
+ : change->path[change_path_len-1] == '/'
+ ? change_path_len + 1
+ : change_path_len + 2;
+
+ /* CAUTION: This is the inner loop of an O(n^2) algorithm.
+ The number of changes to process may be >> 1000.
+ Therefore, keep the inner loop as tight as possible.
+ */
for (hi = apr_hash_first(iterpool, changed_paths);
hi;
hi = apr_hash_next(hi))
{
/* KEY is the path. */
- const char *path = svn__apr_hash_index_key(hi);
- apr_ssize_t klen = svn__apr_hash_index_klen(hi);
-
- /* If we come across our own path, ignore it. */
- if (strcmp(change->path, path) == 0)
- continue;
-
- /* If we come across a child of our path, remove it. */
- if (svn_dirent_is_child(change->path, path, iterpool))
+ const void *path;
+ apr_ssize_t klen;
+ apr_hash_this(hi, &path, &klen, NULL);
+
+ /* If we come across a child of our path, remove it.
+ Call svn_dirent_is_child only if there is a chance that
+ this is actually a sub-path.
+ */
+ if ( klen >= min_child_len
+ && svn_dirent_is_child(change->path, path, iterpool))
apr_hash_set(changed_paths, path, klen, NULL);
}
}
@@ -5849,7 +5988,7 @@ rep_write_contents_close(void *baton)
else
{
/* Write out our cosmetic end marker. */
- SVN_ERR(svn_stream_printf(b->rep_stream, b->pool, "ENDREP\n"));
+ SVN_ERR(svn_stream_puts(b->rep_stream, "ENDREP\n"));
b->noderev->data_rep = rep;
}
@@ -6064,7 +6203,7 @@ write_hash_rep(representation_t *rep,
stream = svn_stream_create(whb, pool);
svn_stream_set_write(stream, write_hash_handler);
- SVN_ERR(svn_stream_printf(whb->stream, pool, "PLAIN\n"));
+ SVN_ERR(svn_stream_puts(whb->stream, "PLAIN\n"));
SVN_ERR(svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool));
@@ -6087,7 +6226,7 @@ write_hash_rep(representation_t *rep,
else
{
/* Write out our cosmetic end marker. */
- SVN_ERR(svn_stream_printf(whb->stream, pool, "ENDREP\n"));
+ SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n"));
/* update the representation */
rep->size = whb->size;
@@ -6195,7 +6334,7 @@ write_hash_delta_rep(representation_t *r
{
/* Write out our cosmetic end marker. */
SVN_ERR(get_file_offset(&rep_end, file, pool));
- SVN_ERR(svn_stream_printf(file_stream, pool, "ENDREP\n"));
+ SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
/* update the representation */
rep->expanded_size = whb->size;
@@ -7500,17 +7639,6 @@ svn_fs_fs__recover(svn_fs_t *fs,
}
svn_error_t *
-svn_fs_fs__get_uuid(svn_fs_t *fs,
- const char **uuid_p,
- apr_pool_t *pool)
-{
- fs_fs_data_t *ffd = fs->fsap_data;
-
- *uuid_p = apr_pstrdup(pool, ffd->uuid);
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_fs_fs__set_uuid(svn_fs_t *fs,
const char *uuid,
apr_pool_t *pool)
@@ -7519,7 +7647,6 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
apr_size_t my_uuid_len;
const char *tmp_path;
const char *uuid_path = path_uuid(fs, pool);
- fs_fs_data_t *ffd = fs->fsap_data;
if (! uuid)
uuid = svn_uuid_generate(pool);
@@ -7540,7 +7667,7 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
/* Remove the newline we added, and stash the UUID. */
my_uuid[my_uuid_len - 1] = '\0';
- ffd->uuid = my_uuid;
+ fs->uuid = my_uuid;
return SVN_NO_ERROR;
}
@@ -8709,7 +8836,7 @@ hotcopy_incremental_check_preconditions(
/* Make sure the UUID of source and destination match up.
* We don't want to copy over a different repository. */
- if (strcmp(src_ffd->uuid, dst_ffd->uuid) != 0)
+ if (strcmp(src_fs->uuid, dst_fs->uuid) != 0)
return svn_error_create(SVN_ERR_RA_UUID_MISMATCH, NULL,
_("The UUID of the hotcopy source does "
"not match the UUID of the hotcopy "
@@ -9089,6 +9216,15 @@ hotcopy_body(void *baton, apr_pool_t *po
SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
PATH_TXN_CURRENT, pool));
+ /* If a revprop generation file exists in the source filesystem,
+ * force a fresh revprop caching namespace for the destination by
+ * setting the generation to zero. We have no idea if the revprops
+ * we copied above really belong to the currently cached generation. */
+ SVN_ERR(svn_io_check_path(path_revprop_generation(src_fs, pool),
+ &kind, pool));
+ if (kind == svn_node_file)
+ SVN_ERR(write_revprop_generation_file(dst_fs, 0, pool));
+
/* Hotcopied FS is complete. Stamp it with a format file. */
SVN_ERR(write_format(svn_dirent_join(dst_fs->path, PATH_FORMAT, pool),
dst_ffd->format, max_files_per_dir, TRUE, pool));
@@ -9097,6 +9233,20 @@ hotcopy_body(void *baton, apr_pool_t *po
}
+/* Set up shared data between SRC_FS and DST_FS. */
+static void
+hotcopy_setup_shared_fs_data(svn_fs_t *src_fs, svn_fs_t *dst_fs)
+{
+ fs_fs_data_t *src_ffd = src_fs->fsap_data;
+ fs_fs_data_t *dst_ffd = dst_fs->fsap_data;
+
+ /* The common pool and mutexes are shared between src and dst filesystems.
+ * During hotcopy we only grab the mutexes for the destination, so there
+ * is no risk of dead-lock. We don't write to the src filesystem. Shared
+ * data for the src_fs has already been initialised in fs_hotcopy(). */
+ dst_ffd->shared = src_ffd->shared;
+}
+
/* Create an empty filesystem at DST_FS at DST_PATH with the same
* configuration as SRC_FS (uuid, format, and other parameters).
* After creation DST_FS has no revisions, not even revision zero. */
@@ -9155,7 +9305,7 @@ hotcopy_create_empty_dest(svn_fs_t *src_
/* Create lock file and UUID. */
SVN_ERR(svn_io_file_create(path_lock(dst_fs, pool), "", pool));
- SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_ffd->uuid, pool));
+ SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, pool));
/* Create the min unpacked rev file. */
if (dst_ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
@@ -9172,6 +9322,10 @@ hotcopy_create_empty_dest(svn_fs_t *src_
}
dst_ffd->youngest_rev_cache = 0;
+
+ hotcopy_setup_shared_fs_data(src_fs, dst_fs);
+ SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool));
+
return SVN_NO_ERROR;
}
@@ -9213,6 +9367,8 @@ svn_fs_fs__hotcopy(svn_fs_t *src_fs,
SVN_ERR(svn_fs_fs__open(dst_fs, dst_path, pool));
SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs,
pool));
+ hotcopy_setup_shared_fs_data(src_fs, dst_fs);
+ SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool));
}
}
else
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.h?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.h Tue May 29 01:39:41 2012
@@ -131,8 +131,9 @@ svn_error_t *svn_fs_fs__rep_contents_dir
apr_pool_t *pool);
/* Set *DIRENT to the entry identified by NAME in the directory given
- by NODEREV in filesystem FS. The returned object is allocated in
- RESULT_POOL; SCRATCH_POOL used for temporary allocations. */
+ by NODEREV in filesystem FS. If no such entry exits, *DIRENT will
+ be NULL. The returned object is allocated in RESULT_POOL; SCRATCH_POOL
+ used for temporary allocations. */
svn_error_t *
svn_fs_fs__rep_contents_dir_entry(svn_fs_dirent_t **dirent,
svn_fs_t *fs,
@@ -355,12 +356,6 @@ svn_error_t *svn_fs_fs__create(svn_fs_t
const char *path,
apr_pool_t *pool);
-/* Store the uuid of the repository FS in *UUID. Allocate space in
- POOL. */
-svn_error_t *svn_fs_fs__get_uuid(svn_fs_t *fs,
- const char **uuid,
- apr_pool_t *pool);
-
/* Set the uuid of repository FS to UUID, if UUID is not NULL;
otherwise, set the uuid of FS to a newly generated UUID. Perform
temporary allocations in POOL. */
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/lock.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/lock.c Tue May 29 01:39:41 2012
@@ -493,7 +493,7 @@ get_lock(svn_lock_t **lock_p,
SVN_ERR(read_digest_file(NULL, &lock, fs->path, digest_path, pool));
if (! lock)
- return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
+ return SVN_FS__ERR_NO_SUCH_LOCK(fs, path);
/* Don't return an expired lock. */
if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
@@ -503,7 +503,7 @@ get_lock(svn_lock_t **lock_p,
if (have_write_lock)
SVN_ERR(delete_lock(fs, lock, pool));
*lock_p = NULL;
- return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token, pool);
+ return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token);
}
*lock_p = lock;
@@ -766,7 +766,7 @@ lock_body(void *baton, apr_pool_t *pool)
SVN_ERR(lb->fs->vtable->revision_root(&root, lb->fs, youngest, pool));
SVN_ERR(svn_fs_fs__check_path(&kind, root, lb->path, pool));
if (kind == svn_node_dir)
- return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path, pool);
+ return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path);
/* While our locking implementation easily supports the locking of
nonexistent paths, we deliberately choose not to allow such madness. */
@@ -786,7 +786,7 @@ lock_body(void *baton, apr_pool_t *pool)
/* We need to have a username attached to the fs. */
if (!lb->fs->access_ctx || !lb->fs->access_ctx->username)
- return SVN_FS__ERR_NO_USER(lb->fs, pool);
+ return SVN_FS__ERR_NO_USER(lb->fs);
/* Is the caller attempting to lock an out-of-date working file? */
if (SVN_IS_VALID_REVNUM(lb->current_rev))
@@ -832,7 +832,7 @@ lock_body(void *baton, apr_pool_t *pool)
if (! lb->steal_lock)
{
/* Sorry, the path is already locked. */
- return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock, pool);
+ return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock);
}
else
{
@@ -888,16 +888,16 @@ unlock_body(void *baton, apr_pool_t *poo
{
/* Sanity check: the incoming token should match lock->token. */
if (strcmp(ub->token, lock->token) != 0)
- return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path, pool);
+ return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path);
/* There better be a username attached to the fs. */
if (! (ub->fs->access_ctx && ub->fs->access_ctx->username))
- return SVN_FS__ERR_NO_USER(ub->fs, pool);
+ return SVN_FS__ERR_NO_USER(ub->fs);
/* And that username better be the same as the lock's owner. */
if (strcmp(ub->fs->access_ctx->username, lock->owner) != 0)
return SVN_FS__ERR_LOCK_OWNER_MISMATCH(
- ub->fs, ub->fs->access_ctx->username, lock->owner, pool);
+ ub->fs, ub->fs->access_ctx->username, lock->owner);
}
/* Remove lock and lock token files. */