Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.c?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.c Sun Feb 22 16:52:05 2015 @@ -278,10 +278,9 @@ add_work_items(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool); static svn_error_t * -set_actual_props(apr_int64_t wc_id, +set_actual_props(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, apr_hash_t *props, - svn_sqlite__db_t *db, apr_pool_t *scratch_pool); static svn_error_t * @@ -487,35 +486,6 @@ repos_location_from_columns(apr_int64_t } } - -/* Get the statement given by STMT_IDX, and bind the appropriate wc_id and - local_relpath based upon LOCAL_ABSPATH. Store it in *STMT, and use - SCRATCH_POOL for temporary allocations. - - Note: WC_ID and LOCAL_RELPATH must be arguments 1 and 2 in the statement. */ -static svn_error_t * -get_statement_for_path(svn_sqlite__stmt_t **stmt, - svn_wc__db_t *db, - const char *local_abspath, - int stmt_idx, - apr_pool_t *scratch_pool) -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, - local_abspath, scratch_pool, scratch_pool)); - VERIFY_USABLE_WCROOT(wcroot); - - SVN_ERR(svn_sqlite__get_statement(stmt, wcroot->sdb, stmt_idx)); - SVN_ERR(svn_sqlite__bindf(*stmt, "is", wcroot->wc_id, local_relpath)); - - return SVN_NO_ERROR; -} - - /* For a given REPOS_ROOT_URL/REPOS_UUID pair, return the existing REPOS_ID value. If one does not exist, then create a new one. */ static svn_error_t * @@ -743,6 +713,7 @@ insert_base_node(const insert_base_baton svn_sqlite__stmt_t *stmt; svn_filesize_t recorded_size = SVN_INVALID_FILESIZE; apr_int64_t recorded_time; + svn_boolean_t present; /* The directory at the WCROOT has a NULL parent_relpath. Otherwise, bind the appropriate parent_relpath. */ @@ -773,6 +744,9 @@ insert_base_node(const insert_base_baton SVN_ERR(svn_sqlite__reset(stmt)); } + present = (pibb->status == svn_wc__db_status_normal + || pibb->status == svn_wc__db_status_incomplete); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isdsisr" "tstr" /* 8 - 11 */ @@ -785,15 +759,16 @@ insert_base_node(const insert_base_baton pibb->repos_relpath, pibb->revision, presence_map, pibb->status, /* 8 */ - (pibb->kind == svn_node_dir) ? /* 9 */ - svn_token__to_word(depth_map, pibb->depth) : NULL, + (pibb->kind == svn_node_dir && present) /* 9 */ + ? svn_token__to_word(depth_map, pibb->depth) + : NULL, kind_map, pibb->kind, /* 10 */ pibb->changed_rev, /* 11 */ pibb->changed_date, /* 12 */ pibb->changed_author, /* 13 */ - (pibb->kind == svn_node_symlink) ? + (pibb->kind == svn_node_symlink && present) ? pibb->target : NULL)); /* 19 */ - if (pibb->kind == svn_node_file) + if (pibb->kind == svn_node_file && present) { if (!pibb->checksum && pibb->status != svn_wc__db_status_not_present @@ -818,11 +793,14 @@ insert_base_node(const insert_base_baton assert(pibb->status == svn_wc__db_status_normal || pibb->status == svn_wc__db_status_incomplete || pibb->props == NULL); - SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props, - scratch_pool)); + if (present) + { + SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props, + scratch_pool)); - SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops, + SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops, scratch_pool)); + } if (pibb->dav_cache) SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache, @@ -852,8 +830,8 @@ insert_base_node(const insert_base_baton new_actual_props = NULL; } - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props, - wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props, + scratch_pool)); } if (pibb->kind == svn_node_dir && pibb->children) @@ -1027,6 +1005,7 @@ insert_working_node(const insert_working const char *moved_to_relpath = NULL; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + svn_boolean_t present; SVN_ERR_ASSERT(piwb->op_depth > 0); @@ -1045,6 +1024,9 @@ insert_working_node(const insert_working moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool); SVN_ERR(svn_sqlite__reset(stmt)); + present = (piwb->presence == svn_wc__db_status_normal + || piwb->presence == svn_wc__db_status_incomplete); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn" "nnnn" /* properties translated_size last_mod_time dav_cache */ @@ -1053,14 +1035,14 @@ insert_working_node(const insert_working piwb->op_depth, parent_relpath, presence_map, piwb->presence, - (piwb->kind == svn_node_dir) + (piwb->kind == svn_node_dir && present) ? svn_token__to_word(depth_map, piwb->depth) : NULL, kind_map, piwb->kind, piwb->changed_rev, piwb->changed_date, piwb->changed_author, /* Note: incomplete nodes may have a NULL target. */ - (piwb->kind == svn_node_symlink) + (piwb->kind == svn_node_symlink && present) ? piwb->target : NULL, moved_to_relpath)); @@ -1069,7 +1051,7 @@ insert_working_node(const insert_working SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE)); } - if (piwb->kind == svn_node_file) + if (piwb->kind == svn_node_file && present) { SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum, scratch_pool)); @@ -1086,7 +1068,8 @@ insert_working_node(const insert_working assert(piwb->presence == svn_wc__db_status_normal || piwb->presence == svn_wc__db_status_incomplete || piwb->props == NULL); - SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool)); + if (present && piwb->original_repos_relpath) + SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool)); SVN_ERR(svn_sqlite__insert(NULL, stmt)); @@ -1123,8 +1106,8 @@ insert_working_node(const insert_working new_actual_props = NULL; } - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props, - wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props, + scratch_pool)); } if (piwb->kind == svn_node_dir) @@ -1170,119 +1153,40 @@ insert_working_node(const insert_working } -/* Each name is allocated in RESULT_POOL and stored into CHILDREN as a key - pointed to the same name. */ -static svn_error_t * -add_children_to_hash(apr_hash_t *children, - int stmt_idx, - svn_sqlite__db_t *sdb, - apr_int64_t wc_id, - const char *parent_relpath, - apr_pool_t *result_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - while (have_row) - { - const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); - const char *name = svn_relpath_basename(child_relpath, result_pool); - - svn_hash_sets(children, name, name); - - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - } - - return svn_sqlite__reset(stmt); -} - - -/* Set *CHILDREN to a new array of the (const char *) basenames of the - immediate children, whatever their status, of the working node at - LOCAL_RELPATH. */ -static svn_error_t * -gather_children2(const apr_array_header_t **children, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_hash_t *names_hash = apr_hash_make(scratch_pool); - apr_array_header_t *names_array; - - /* All of the names get allocated in RESULT_POOL. It - appears to be faster to use the hash to remove duplicates than to - use DISTINCT in the SQL query. */ - SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_WORKING_CHILDREN, - wcroot->sdb, wcroot->wc_id, - local_relpath, result_pool)); - - SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool)); - *children = names_array; - return SVN_NO_ERROR; -} - /* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH, of any status, in all op-depths in the NODES table. */ static svn_error_t * gather_children(const apr_array_header_t **children, svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, + const char *parent_relpath, + int stmt_idx, + int op_depth, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_hash_t *names_hash = apr_hash_make(scratch_pool); - apr_array_header_t *names_array; - - /* All of the names get allocated in RESULT_POOL. It - appears to be faster to use the hash to remove duplicates than to - use DISTINCT in the SQL query. */ - SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN, - wcroot->sdb, wcroot->wc_id, - local_relpath, result_pool)); - - SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool)); - *children = names_array; - return SVN_NO_ERROR; -} - - -/* Set *CHILDREN to a new array of (const char *) names of the children of - the repository directory corresponding to WCROOT:LOCAL_RELPATH:OP_DEPTH - - that is, only the children that are at the same op-depth as their parent. */ -static svn_error_t * -gather_repo_children(const apr_array_header_t **children, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - int op_depth, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_array_header_t *result - = apr_array_make(result_pool, 0, sizeof(const char *)); + apr_array_header_t *result; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_OP_DEPTH_CHILDREN)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, - op_depth)); + result = apr_array_make(result_pool, 16, sizeof(const char*)); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath)); + if (op_depth >= 0) + SVN_ERR(svn_sqlite__bind_int(stmt, 3, op_depth)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); + const char *name = svn_relpath_basename(child_relpath, result_pool); - /* Allocate the name in RESULT_POOL so we won't have to copy it. */ - APR_ARRAY_PUSH(result, const char *) - = svn_relpath_basename(child_relpath, result_pool); + APR_ARRAY_PUSH(result, const char *) = name; SVN_ERR(svn_sqlite__step(&have_row, stmt)); } - SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__reset(stmt)); *children = result; return SVN_NO_ERROR; } @@ -1577,7 +1481,7 @@ svn_wc__db_init(svn_wc__db_t *db, /* ### REPOS_ROOT_URL and REPOS_UUID may be NULL. ... more doc: tbd */ - SVN_ERR(svn_config_get_bool((svn_config_t *)db->config, &sqlite_exclusive, + SVN_ERR(svn_config_get_bool(db->config, &sqlite_exclusive, SVN_CONFIG_SECTION_WORKING_COPY, SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE, FALSE)); @@ -2238,12 +2142,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro if (status == svn_wc__db_status_normal && keep_as_working) { - SVN_ERR(svn_wc__db_op_make_copy(db, - svn_dirent_join(wcroot->abspath, - local_relpath, - scratch_pool), - NULL, NULL, - scratch_pool)); + SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, + NULL, NULL, + scratch_pool)); keep_working = TRUE; } else @@ -2397,8 +2298,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro } if (keep_working) { - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_DELETE_WORKING_BASE_DELETE)); + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0)); SVN_ERR(svn_sqlite__step_done(stmt)); } @@ -2835,8 +2737,10 @@ svn_wc__db_base_get_children(const apr_a scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - return gather_repo_children(children, wcroot, local_relpath, 0, - result_pool, scratch_pool); + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, 0, + result_pool, scratch_pool)); } @@ -2846,12 +2750,20 @@ svn_wc__db_base_set_dav_cache(svn_wc__db const apr_hash_t *props, apr_pool_t *scratch_pool) { + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; svn_sqlite__stmt_t *stmt; int affected_rows; - SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, - STMT_UPDATE_BASE_NODE_DAV_CACHE, - scratch_pool)); + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_BASE_NODE_DAV_CACHE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); @@ -2873,11 +2785,20 @@ svn_wc__db_base_get_dav_cache(apr_hash_t apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, - STMT_SELECT_BASE_DAV_CACHE, scratch_pool)); + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_BASE_DAV_CACHE)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); if (!have_row) return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, @@ -4030,9 +3951,7 @@ scan_deletion_txn(const char **base_del_ scan = (moved_to_op_root_relpath || moved_to_relpath); SVN_ERR(svn_sqlite__get_statement( - &stmt, wcroot->sdb, - scan ? STMT_SELECT_DELETION_INFO_SCAN - : STMT_SELECT_DELETION_INFO)); + &stmt, wcroot->sdb, STMT_SELECT_DELETION_INFO)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); @@ -4606,8 +4525,9 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro int src_op_depth; SVN_ERR(op_depth_of(&src_op_depth, src_wcroot, src_relpath)); - SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath, - src_op_depth, scratch_pool, scratch_pool)); + SVN_ERR(gather_children(&children, src_wcroot, src_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth, + scratch_pool, scratch_pool)); } else children = NULL; @@ -4831,6 +4751,72 @@ svn_wc__db_op_copy(svn_wc__db_t *db, return SVN_NO_ERROR; } +/* Remove unneeded actual nodes for svn_wc__db_op_copy_layer_internal */ +static svn_error_t * +clear_or_remove_actual(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + int op_depth, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row, shadowed; + svn_boolean_t keep_conflict = FALSE; + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_NODE_INFO)); + + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + if (have_row) + { + svn_wc__db_status_t presence; + + shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth); + presence = svn_sqlite__column_token(stmt, 3, presence_map); + + if (shadowed && presence == svn_wc__db_status_base_deleted) + { + keep_conflict = TRUE; + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + if (have_row) + shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth); + else + shadowed = FALSE; + } + } + else + shadowed = FALSE; + + SVN_ERR(svn_sqlite__reset(stmt)); + if (shadowed) + return SVN_NO_ERROR; + + if (keep_conflict) + { + /* We don't want to accidentally remove delete-delete conflicts */ + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_CLEAR_ACTUAL_NODE_LEAVING_CONFLICT)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_EMPTY)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + else + { + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + + return SVN_NO_ERROR; +} + svn_error_t * svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot, const char *src_op_relpath, @@ -4962,6 +4948,12 @@ svn_wc__db_op_copy_layer_internal(svn_wc err = svn_sqlite__step_done(stmt2); /* stmt2 is reset (never modified or by step_done) */ + if (err) + break; + + /* Delete ACTUAL information about this node that we just deleted */ + err = clear_or_remove_actual(wcroot, dst_relpath, dst_op_depth, + scratch_pool); if (err) break; @@ -4979,8 +4971,6 @@ svn_wc__db_op_copy_layer_internal(svn_wc SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); - /* ### TODO: Did we handle ACTUAL as intended? */ - SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); if (conflict) @@ -5397,8 +5387,9 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr return SVN_NO_ERROR; } - SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath, - src_op_depth, scratch_pool, iterpool)); + SVN_ERR(gather_children(&children, src_wcroot, src_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth, + scratch_pool, iterpool)); for (i = 0; i < children->nelts; i++) { @@ -5585,8 +5576,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, const char *original_uuid, svn_revnum_t original_revision, const apr_array_header_t *children, - svn_boolean_t is_move, svn_depth_t depth, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -5613,11 +5604,6 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_dir; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - if (original_root_url != NULL) { SVN_ERR(create_repos_id(&iwb.original_repos_id, @@ -5625,6 +5611,11 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5693,11 +5684,6 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_file; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - if (original_root_url != NULL) { SVN_ERR(create_repos_id(&iwb.original_repos_id, @@ -5705,6 +5691,11 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5747,6 +5738,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t const char *original_uuid, svn_revnum_t original_revision, const char *target, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -5771,11 +5763,6 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_symlink; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - iwb.moved_here = FALSE; if (original_root_url != NULL) { @@ -5784,6 +5771,11 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5793,6 +5785,8 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t wcroot, local_relpath, scratch_pool)); iwb.target = target; + iwb.moved_here = is_move && (parent_op_depth == 0 || + iwb.op_depth == parent_op_depth); iwb.work_items = work_items; iwb.conflict = conflict; @@ -6002,27 +5996,39 @@ svn_wc__db_global_record_fileinfo(svn_wc * props; to indicate no properties when the pristine has some props, * PROPS must be an empty hash. */ static svn_error_t * -set_actual_props(apr_int64_t wc_id, +set_actual_props(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, apr_hash_t *props, - svn_sqlite__db_t *db, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; int affected_rows; - SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_ACTUAL_PROPS)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); if (affected_rows == 1 || !props) - return SVN_NO_ERROR; /* We are done */ + { + /* Perhaps the entire ACTUAL record is unneeded now? */ + if (!props && affected_rows) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_EMPTY)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + + return SVN_NO_ERROR; /* We are done */ + } /* We have to insert a row in ACTUAL */ - SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_INSERT_ACTUAL_PROPS)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); if (*local_relpath != '\0') SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_relpath_dirname(local_relpath, @@ -6038,8 +6044,7 @@ svn_wc__db_op_set_props_internal(svn_wc_ svn_boolean_t clear_recorded_info, apr_pool_t *scratch_pool) { - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, - props, wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, props, scratch_pool)); if (clear_recorded_info) { @@ -6318,7 +6323,7 @@ set_changelist_txn(void *baton, if (scb->new_changelist) { SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_INSERT_ACTUAL_EMPTIES)); + STMT_INSERT_ACTUAL_EMPTIES_FILES)); SVN_ERR(svn_sqlite__step_done(stmt)); } @@ -9913,35 +9918,34 @@ svn_wc__db_read_node_install_info(const -/* The body of svn_wc__db_read_url(). +/* The body of svn_wc__db_read_repos_info(). */ static svn_error_t * -read_url_txn(const char **url, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +db_read_repos_info(svn_revnum_t *revision, + const char **repos_relpath, + apr_int64_t *repos_id, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_wc__db_status_t status; - const char *repos_relpath; - const char *repos_root_url; - apr_int64_t repos_id; - svn_boolean_t have_base; - SVN_ERR(read_info(&status, NULL, NULL, &repos_relpath, &repos_id, NULL, + SVN_ERR(read_info(&status, NULL, revision, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &have_base, NULL, NULL, - wcroot, local_relpath, scratch_pool, scratch_pool)); + NULL, NULL, NULL, + wcroot, local_relpath, result_pool, scratch_pool)); - if (repos_relpath == NULL) + if ((repos_relpath && !*repos_relpath) + || (repos_id && *repos_id == INVALID_REPOS_ID)) { if (status == svn_wc__db_status_added) { - SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, NULL, + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, wcroot, local_relpath, - scratch_pool, scratch_pool)); + result_pool, scratch_pool)); } else if (status == svn_wc__db_status_deleted) { @@ -9955,26 +9959,7 @@ read_url_txn(const char **url, scratch_pool, scratch_pool)); - if (base_del_relpath) - { - SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, - &repos_relpath, - &repos_id, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - wcroot, - base_del_relpath, - scratch_pool, - scratch_pool)); - - repos_relpath = svn_relpath_join( - repos_relpath, - svn_dirent_skip_ancestor(base_del_relpath, - local_relpath), - scratch_pool); - } - else + if (work_del_relpath) { /* The parent of the WORKING delete, must be an addition */ const char *work_relpath = NULL; @@ -9987,34 +9972,57 @@ read_url_txn(const char **url, work_relpath = svn_relpath_dirname(work_del_relpath, scratch_pool); - SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, wcroot, work_relpath, scratch_pool, scratch_pool)); - repos_relpath = svn_relpath_join( - repos_relpath, + if (repos_relpath) + *repos_relpath = svn_relpath_join( + *repos_relpath, svn_dirent_skip_ancestor(work_relpath, local_relpath), - scratch_pool); + result_pool); + } + else + { + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision, + repos_relpath, + repos_id, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + wcroot, + base_del_relpath, + scratch_pool, + scratch_pool)); + + if (repos_relpath) + *repos_relpath = svn_relpath_join( + *repos_relpath, + svn_dirent_skip_ancestor(base_del_relpath, + local_relpath), + result_pool); } } else if (status == svn_wc__db_status_excluded) { const char *parent_relpath; const char *name; - const char *url2; - /* Set 'url' to the *full URL* of the parent WC dir, - * and 'name' to the *single path component* that is the - * basename of this WC directory, so that joining them will result - * in the correct full URL. */ + /* A BASE excluded would have had repository information, so + we have a working exclude, which must be below an addition */ + svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool); - SVN_ERR(read_url_txn(&url2, wcroot, parent_relpath, - scratch_pool, scratch_pool)); + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, parent_relpath, + scratch_pool, scratch_pool)); - *url = svn_path_url_add_component2(url2, name, result_pool); + if (repos_relpath) + *repos_relpath = svn_relpath_join(*repos_relpath, name, + result_pool); return SVN_NO_ERROR; } @@ -10026,26 +10034,23 @@ read_url_txn(const char **url, } } - SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot, - repos_id, scratch_pool)); - - SVN_ERR_ASSERT(repos_root_url != NULL && repos_relpath != NULL); - *url = svn_path_url_add_component2(repos_root_url, repos_relpath, - result_pool); - return SVN_NO_ERROR; } svn_error_t * -svn_wc__db_read_url(const char **url, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_wc__db_read_repos_info(svn_revnum_t *revision, + const char **repos_relpath, + const char **repos_root_url, + const char **repos_uuid, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; + apr_int64_t repos_id = INVALID_REPOS_ID; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); @@ -10054,9 +10059,17 @@ svn_wc__db_read_url(const char **url, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - SVN_WC__DB_WITH_TXN(read_url_txn(url, wcroot, local_relpath, - result_pool, scratch_pool), - wcroot); + SVN_WC__DB_WITH_TXN4(db_read_repos_info(revision, repos_relpath, + (repos_root_url || repos_uuid) + ? &repos_id : NULL, + wcroot, local_relpath, + result_pool, scratch_pool), + svn_wc__db_fetch_repos_info(repos_root_url, + repos_uuid, + wcroot, repos_id, + result_pool), + SVN_NO_ERROR, SVN_NO_ERROR, + wcroot); return SVN_NO_ERROR; } @@ -10898,8 +10911,34 @@ svn_wc__db_read_children_of_working_node scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - return gather_children2(children, wcroot, local_relpath, - result_pool, scratch_pool); + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_WORKING_CHILDREN, -1, + result_pool, scratch_pool)); +} + +svn_error_t * +svn_wc__db_base_read_not_present_children( + const apr_array_header_t **children, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_BASE_NOT_PRESENT_CHILDREN, -1, + result_pool, scratch_pool)); } /* Helper for svn_wc__db_node_check_replace(). @@ -11086,6 +11125,7 @@ svn_wc__db_read_children(const apr_array VERIFY_USABLE_WCROOT(wcroot); return gather_children(children, wcroot, local_relpath, + STMT_SELECT_NODE_CHILDREN, -1, result_pool, scratch_pool); } @@ -11291,35 +11331,18 @@ determine_repos_info(apr_int64_t *repos_ return SVN_NO_ERROR; } -/* Helper for svn_wc__db_global_commit() - - Makes local_relpath and all its descendants at the same op-depth represent - the copy origin repos_id:repos_relpath@revision. - - This code is only valid to fix-up a move from an old location, to a new - location during a commit. - - Assumptions: - * local_relpath is not the working copy root (can't be moved) - * repos_relpath is not the repository root (can't be moved) - */ static svn_error_t * -moved_descendant_commit(svn_wc__db_wcroot_t *wcroot, +moved_descendant_collect(apr_hash_t **map, + svn_wc__db_wcroot_t *wcroot, const char *local_relpath, int op_depth, - apr_int64_t repos_id, - const char *repos_relpath, - svn_revnum_t revision, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_hash_t *children; - apr_pool_t *iterpool; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - apr_hash_index_t *hi; - SVN_ERR_ASSERT(*local_relpath != '\0' - && *repos_relpath != '\0'); + *map = NULL; SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_DESCENDANTS_SRC)); @@ -11331,21 +11354,56 @@ moved_descendant_commit(svn_wc__db_wcroo if (! have_row) return svn_error_trace(svn_sqlite__reset(stmt)); - children = apr_hash_make(scratch_pool); - - /* First, obtain all moved descendants */ - /* To keep error handling simple, first cache them in a hashtable */ + /* Find all moved descendants. Key them on target, because that is + always unique */ while (have_row) { - const char *src_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool); - const char *to_relpath = svn_sqlite__column_text(stmt, 4, scratch_pool); + const char *src_relpath = svn_sqlite__column_text(stmt, 1, result_pool); + const char *to_relpath = svn_sqlite__column_text(stmt, 4, result_pool); + + if (!*map) + *map = apr_hash_make(result_pool); - svn_hash_sets(children, src_relpath, to_relpath); + svn_hash_sets(*map, to_relpath, src_relpath); SVN_ERR(svn_sqlite__step(&have_row, stmt)); } SVN_ERR(svn_sqlite__reset(stmt)); + return SVN_NO_ERROR; +} + +/* Helper for svn_wc__db_global_commit() + + Makes local_relpath and all its descendants at the same op-depth represent + the copy origin repos_id:repos_relpath@revision. + + This code is only valid to fix-up a move from an old location, to a new + location during a commit. + + Assumptions: + * local_relpath is not the working copy root (can't be moved) + * repos_relpath is not the repository root (can't be moved) + */ +static svn_error_t * +moved_descendant_commit(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_int64_t repos_id, + const char *repos_relpath, + svn_revnum_t revision, + apr_hash_t *children, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool; + svn_sqlite__stmt_t *stmt; + apr_hash_index_t *hi; + + SVN_ERR_ASSERT(*local_relpath != '\0' + && *repos_relpath != '\0'); + + if (!children) + return SVN_NO_ERROR; + /* Then update them */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_COMMIT_UPDATE_ORIGIN)); @@ -11353,11 +11411,12 @@ moved_descendant_commit(svn_wc__db_wcroo iterpool = svn_pool_create(scratch_pool); for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi)) { - const char *src_relpath = apr_hash_this_key(hi); - const char *to_relpath = apr_hash_this_val(hi); + const char *src_relpath = apr_hash_this_val(hi); + const char *to_relpath = apr_hash_this_key(hi); const char *new_repos_relpath; int to_op_depth = relpath_depth(to_relpath); int affected; + apr_hash_t *map; svn_pool_clear(iterpool); @@ -11384,9 +11443,11 @@ moved_descendant_commit(svn_wc__db_wcroo SVN_ERR_ASSERT(affected >= 1); /* If this fails there is no move dest */ #endif - SVN_ERR(moved_descendant_commit(wcroot, to_relpath, to_op_depth, + SVN_ERR(moved_descendant_collect(&map, wcroot, to_relpath, to_op_depth, + iterpool, iterpool)); + SVN_ERR(moved_descendant_commit(wcroot, to_relpath, repos_id, new_repos_relpath, revision, - iterpool)); + map, iterpool)); } svn_pool_destroy(iterpool); @@ -11467,6 +11528,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot, const char *repos_relpath; int op_depth; svn_wc__db_status_t old_presence; + svn_boolean_t moved_here; /* If we are adding a file or directory, then we need to get repository information from the parent node since "this node" does @@ -11535,6 +11597,8 @@ commit_node(svn_wc__db_wcroot_t *wcroot, old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map); + moved_here = svn_sqlite__column_int(stmt_info, 15); + /* ### other stuff? */ SVN_ERR(svn_sqlite__reset(stmt_info)); @@ -11543,6 +11607,13 @@ commit_node(svn_wc__db_wcroot_t *wcroot, if (op_depth > 0) { int affected_rows; + apr_hash_t *map_pre = NULL; + apr_hash_t *map_post = NULL; + svn_boolean_t op_root = (relpath_depth(local_relpath) == op_depth); + + /* First collect the moves that we might delete in a bit */ + SVN_ERR(moved_descendant_collect(&map_pre, wcroot, local_relpath, 0, + scratch_pool, scratch_pool)); /* This removes all layers of this node and at the same time determines if we need to remove shadowed layers below our descendants. */ @@ -11576,26 +11647,61 @@ commit_node(svn_wc__db_wcroot_t *wcroot, be integrated, they really affect a different op-depth and completely different nodes (via a different recursion pattern). */ - /* Collapse descendants of the current op_depth in layer 0 */ - SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth, - repos_id, repos_relpath, new_revision, - scratch_pool)); + if (op_root) + { + /* Collapse descendants of the current op_depth to layer 0, + this includes moved-from/to clearing */ + SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth, + repos_id, repos_relpath, new_revision, + scratch_pool)); + } + + SVN_ERR(moved_descendant_collect(&map_post, wcroot, local_relpath, 0, + scratch_pool, scratch_pool)); + /* And make the recorded local moves represent moves of the node we just committed. */ - SVN_ERR(moved_descendant_commit(wcroot, local_relpath, 0, + SVN_ERR(moved_descendant_commit(wcroot, local_relpath, repos_id, repos_relpath, new_revision, - scratch_pool)); + map_post, scratch_pool)); - /* This node is no longer modified, so no node was moved here */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_CLEAR_MOVED_TO_FROM_DEST)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, - local_relpath)); + if (map_pre && map_post != map_pre) + { + apr_hash_index_t *hi; - SVN_ERR(svn_sqlite__step_done(stmt)); - } + for (hi = apr_hash_first(scratch_pool, map_pre); + hi; hi = apr_hash_next(hi)) + { + const char *to_relpath = apr_hash_this_key(hi); + svn_error_t *err; + + if (map_post && svn_hash_gets(map_post, to_relpath)) + continue; + + err = clear_moved_here(wcroot, to_relpath, scratch_pool); + + if (err) + { + if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) + return svn_error_trace(err); + + svn_error_clear(err); /* Node already committed? */ + } + } + } + + if (op_root && moved_here) + { + /* This node is no longer modified, so no node was moved here */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_CLEAR_MOVED_TO_FROM_DEST)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, + local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + } /* Update or add the BASE_NODE row with all the new information. */ if (*local_relpath == '\0') @@ -11677,9 +11783,18 @@ commit_node(svn_wc__db_wcroot_t *wcroot, if (!no_unlock) { svn_sqlite__stmt_t *lock_stmt; + svn_boolean_t op_root = (op_depth > 0 + && (relpath_depth(local_relpath) == op_depth)); + /* If we are committing an add of a delete, we can assume we own + all locks at or below REPOS_RELPATH (or the server would have + denied the commit). As we must have passed these to the server + we can now safely remove them. + */ SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb, - STMT_DELETE_LOCK_RECURSIVELY)); + op_root + ? STMT_DELETE_LOCK_RECURSIVELY + : STMT_DELETE_LOCK)); SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath)); SVN_ERR(svn_sqlite__step_done(lock_stmt)); } @@ -13055,191 +13170,6 @@ svn_wc__db_upgrade_begin(svn_sqlite__db_ return SVN_NO_ERROR; } - -svn_error_t * -svn_wc__db_upgrade_apply_dav_cache(svn_sqlite__db_t *sdb, - const char *dir_relpath, - apr_hash_t *cache_values, - apr_pool_t *scratch_pool) -{ - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - apr_int64_t wc_id; - apr_hash_index_t *hi; - svn_sqlite__stmt_t *stmt; - - SVN_ERR(svn_wc__db_util_fetch_wc_id(&wc_id, sdb, iterpool)); - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_BASE_NODE_DAV_CACHE)); - - /* Iterate over all the wcprops, writing each one to the wc_db. */ - for (hi = apr_hash_first(scratch_pool, cache_values); - hi; - hi = apr_hash_next(hi)) - { - const char *name = apr_hash_this_key(hi); - apr_hash_t *props = apr_hash_this_val(hi); - const char *local_relpath; - - svn_pool_clear(iterpool); - - local_relpath = svn_relpath_join(dir_relpath, name, iterpool); - - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool)); - SVN_ERR(svn_sqlite__step_done(stmt)); - } - - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_wc__db_upgrade_apply_props(svn_sqlite__db_t *sdb, - const char *dir_abspath, - const char *local_relpath, - apr_hash_t *base_props, - apr_hash_t *revert_props, - apr_hash_t *working_props, - int original_format, - apr_int64_t wc_id, - apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - int top_op_depth = -1; - int below_op_depth = -1; - svn_wc__db_status_t top_presence; - svn_wc__db_status_t below_presence; - int affected_rows; - - /* ### working_props: use set_props_txn. - ### if working_props == NULL, then skip. what if they equal the - ### pristine props? we should probably do the compare here. - ### - ### base props go into WORKING_NODE if avail, otherwise BASE. - ### - ### revert only goes into BASE. (and WORKING better be there!) - - Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a - file was deleted, then a copy (potentially with props) was disallowed - and could not replace the deletion. An addition *could* be performed, - but that would never bring its own props. - - 1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a - bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT - construct a REVERT_PROPS if the target had no props. Thus, reverting - the delete/copy would see no REVERT_PROPS to restore, leaving the - props from the copy source intact, and appearing as if they are (now) - the base props for the previously-deleted file. (wc corruption) - - 1.4.6 ensured that an empty REVERT_PROPS would be established at all - times. See issue 2530, and r861670 as starting points. - - We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine - the handling of our inputs, relative to the state of this node. - */ - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) - { - top_op_depth = svn_sqlite__column_int(stmt, 0); - top_presence = svn_sqlite__column_token(stmt, 3, presence_map); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) - { - below_op_depth = svn_sqlite__column_int(stmt, 0); - below_presence = svn_sqlite__column_token(stmt, 3, presence_map); - } - } - SVN_ERR(svn_sqlite__reset(stmt)); - - /* Detect the buggy scenario described above. We cannot upgrade this - working copy if we have no idea where BASE_PROPS should go. */ - if (original_format > SVN_WC__NO_REVERT_FILES - && revert_props == NULL - && top_op_depth != -1 - && top_presence == svn_wc__db_status_normal - && below_op_depth != -1 - && below_presence != svn_wc__db_status_not_present) - { - /* There should be REVERT_PROPS, so it appears that we just ran into - the described bug. Sigh. */ - return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, - _("The properties of '%s' are in an " - "indeterminate state and cannot be " - "upgraded. See issue #2530."), - svn_dirent_local_style( - svn_dirent_join(dir_abspath, local_relpath, - scratch_pool), scratch_pool)); - } - - /* Need at least one row, or two rows if there are revert props */ - if (top_op_depth == -1 - || (below_op_depth == -1 && revert_props)) - return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, - _("Insufficient NODES rows for '%s'"), - svn_dirent_local_style( - svn_dirent_join(dir_abspath, local_relpath, - scratch_pool), scratch_pool)); - - /* one row, base props only: upper row gets base props - two rows, base props only: lower row gets base props - two rows, revert props only: lower row gets revert props - two rows, base and revert props: upper row gets base, lower gets revert */ - - - if (revert_props || below_op_depth == -1) - { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_NODE_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", - wc_id, local_relpath, top_op_depth)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool)); - SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); - - SVN_ERR_ASSERT(affected_rows == 1); - } - - if (below_op_depth != -1) - { - apr_hash_t *props = revert_props ? revert_props : base_props; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_NODE_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", - wc_id, local_relpath, below_op_depth)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool)); - SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); - - SVN_ERR_ASSERT(affected_rows == 1); - } - - /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE. */ - if (working_props != NULL - && base_props != NULL) - { - apr_array_header_t *diffs; - - SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool)); - - if (diffs->nelts == 0) - working_props = NULL; /* No differences */ - } - - if (working_props != NULL) - { - SVN_ERR(set_actual_props(wc_id, local_relpath, working_props, - sdb, scratch_pool)); - } - - return SVN_NO_ERROR; -} - svn_error_t * svn_wc__db_upgrade_insert_external(svn_wc__db_t *db, const char *local_abspath, @@ -13315,28 +13245,6 @@ svn_wc__db_upgrade_insert_external(svn_w } svn_error_t * -svn_wc__db_upgrade_get_repos_id(apr_int64_t *repos_id, - svn_sqlite__db_t *sdb, - const char *repos_root_url, - apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_REPOSITORY)); - SVN_ERR(svn_sqlite__bindf(stmt, "s", repos_root_url)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - - if (!have_row) - return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt), - _("Repository '%s' not found in the database"), - repos_root_url); - - *repos_id = svn_sqlite__column_int64(stmt, 0); - return svn_error_trace(svn_sqlite__reset(stmt)); -} - -svn_error_t * svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot, const svn_skel_t *work_item, apr_pool_t *scratch_pool) @@ -13991,6 +13899,7 @@ svn_wc__db_read_kind(svn_node_kind_t *ki const char *local_relpath; svn_sqlite__stmt_t *stmt_info; svn_boolean_t have_info; + svn_wc__db_status_t status; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); @@ -14022,12 +13931,27 @@ svn_wc__db_read_kind(svn_node_kind_t *ki } } + status = svn_sqlite__column_token(stmt_info, 3, presence_map); + + if (show_deleted && status == svn_wc__db_status_base_deleted) + { + /* Let's return the kind of what is really deleted insead of what + we have cached in the base-deleted record */ + + SVN_ERR(svn_sqlite__step(&have_info, stmt_info)); + + if (!have_info) + { + /* No lower layer deleted? Database inconsistency! */ + *kind = svn_node_none; + return svn_error_trace(svn_sqlite__reset(stmt_info)); + } + } + if (!(show_deleted && show_hidden)) { int op_depth = svn_sqlite__column_int(stmt_info, 0); svn_boolean_t report_none = FALSE; - svn_wc__db_status_t status = svn_sqlite__column_token(stmt_info, 3, - presence_map); if (op_depth > 0) SVN_ERR(convert_to_working_status(&status, status)); @@ -14063,38 +13987,6 @@ svn_wc__db_read_kind(svn_node_kind_t *ki return svn_error_trace(svn_sqlite__reset(stmt_info)); } - -svn_error_t * -svn_wc__db_node_hidden(svn_boolean_t *hidden, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *scratch_pool) -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - svn_wc__db_status_t status; - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, - local_abspath, scratch_pool, scratch_pool)); - VERIFY_USABLE_WCROOT(wcroot); - - SVN_ERR(read_info(&status, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, - wcroot, local_relpath, - scratch_pool, scratch_pool)); - - *hidden = (status == svn_wc__db_status_server_excluded - || status == svn_wc__db_status_not_present - || status == svn_wc__db_status_excluded); - - return SVN_NO_ERROR; -} - - svn_error_t * svn_wc__db_is_wcroot(svn_boolean_t *is_wcroot, svn_wc__db_t *db, @@ -14913,95 +14805,164 @@ svn_wc__db_temp_op_start_directory_updat static svn_error_t * make_copy_txn(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, - int op_depth, + apr_int64_t last_repos_id, + const char *last_repos_relpath, + svn_revnum_t last_revision, + int last_op_depth, + svn_boolean_t shadowed, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - svn_boolean_t add_working_base_deleted = FALSE; - svn_boolean_t remove_working = FALSE; - const apr_array_header_t *children; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - int i; - - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_LOWEST_WORKING_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); + svn_boolean_t have_row = FALSE; + svn_revnum_t revision; + apr_int64_t repos_id; + const char *repos_relpath; + svn_node_kind_t kind; + int op_depth = relpath_depth(local_relpath); - if (have_row) + if (last_op_depth != op_depth) { - svn_wc__db_status_t working_status; - int working_op_depth; - - working_status = svn_sqlite__column_token(stmt, 1, presence_map); - working_op_depth = svn_sqlite__column_int(stmt, 0); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_DEPTH_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, + op_depth)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); SVN_ERR(svn_sqlite__reset(stmt)); + if (have_row) + shadowed = TRUE; + } - SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal - || working_status == svn_wc__db_status_base_deleted - || working_status == svn_wc__db_status_not_present - || working_status == svn_wc__db_status_incomplete); + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &kind, &revision, + &repos_relpath, &repos_id, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + wcroot, local_relpath, + scratch_pool, scratch_pool)); - /* Only change nodes in the layers where we are creating the copy. - Deletes in higher layers will just apply to the copy */ - if (working_op_depth <= op_depth) - { - add_working_base_deleted = TRUE; + if (last_repos_relpath + && repos_id == last_repos_id + && revision == last_revision) + { + const char *name = svn_relpath_skip_ancestor(last_repos_relpath, + repos_relpath); - if (working_status == svn_wc__db_status_base_deleted) - remove_working = TRUE; - } + if (strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0) + op_depth = last_op_depth; } - else - SVN_ERR(svn_sqlite__reset(stmt)); - if (remove_working) + /* Insert a not-present node to mark that we don't know what exists + here */ + if (last_op_depth > 0 && last_op_depth != op_depth) { - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_DELETE_LOWEST_WORKING_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step_done(stmt)); + insert_working_baton_t iwb; + + blank_iwb(&iwb); + iwb.presence = svn_wc__db_status_not_present; + iwb.op_depth = last_op_depth; + + iwb.original_repos_id = repos_id; + iwb.original_repos_relpath = repos_relpath; + iwb.original_revnum = revision; + iwb.kind = kind; + + SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool)); } - if (add_working_base_deleted) + /* Can we add a new copy node at the wanted op-depth? */ + if (!have_row || op_depth == last_op_depth) { - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_INSERT_DELETE_FROM_BASE)); + int i; + + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_INSERT_WORKING_NODE_FROM_BASE_COPY)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, op_depth)); SVN_ERR(svn_sqlite__step_done(stmt)); + + if (shadowed) + SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, kind, + op_depth, scratch_pool)); + + if (kind == svn_node_dir) + { + const apr_array_header_t *children; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + SVN_ERR(gather_children(&children, wcroot, local_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, 0, + scratch_pool, iterpool)); + + for (i = 0; i < children->nelts; i++) + { + const char *name = APR_ARRAY_IDX(children, i, const char *); + const char *copy_relpath; + + svn_pool_clear(iterpool); + + copy_relpath = svn_relpath_join(local_relpath, name, iterpool); + + SVN_ERR(make_copy_txn(wcroot, copy_relpath, + repos_id, repos_relpath, revision, + op_depth, shadowed, scratch_pool)); + } + svn_pool_destroy(iterpool); + } } else { + /* Auch... we can't make a copy of whatever comes deeper, as this + op-depth is already filled by something else. Let's hope + the user doesn't mind. + + Luckily we know that the moves are already moved to the shadowing + layer, so we can just remove dangling base-deletes if there are + any. + */ + /* BASE_DELETED may be at op_depth, so let's use last_op_depth! */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_INSERT_WORKING_NODE_FROM_BASE_COPY)); + STMT_DELETE_WORKING_BASE_DELETE)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, - op_depth)); + last_op_depth)); + SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, + last_op_depth)); SVN_ERR(svn_sqlite__step_done(stmt)); } - /* Get the BASE children, as WORKING children don't need modifications */ - SVN_ERR(gather_repo_children(&children, wcroot, local_relpath, - 0, scratch_pool, iterpool)); - - for (i = 0; i < children->nelts; i++) - { - const char *name = APR_ARRAY_IDX(children, i, const char *); - const char *copy_relpath; - - svn_pool_clear(iterpool); + return SVN_NO_ERROR; +} - copy_relpath = svn_relpath_join(local_relpath, name, iterpool); +/* Helper for svn_wc__db_op_make_copy_internal */ +static svn_error_t * +make_copy_move_moved_to(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + int cur_op_depth, + int new_op_depth, + const char *moved_to, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; - SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, iterpool)); - } + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_MOVED_TO_RELPATH)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, + local_relpath, cur_op_depth)); + SVN_ERR(svn_sqlite__step_done(stmt)); - svn_pool_destroy(iterpool); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_MOVED_TO_RELPATH)); + SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id, + local_relpath, new_op_depth, moved_to)); + SVN_ERR(svn_sqlite__step_done(stmt)); return SVN_NO_ERROR; } + svn_error_t * svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, @@ -15043,12 +15004,56 @@ svn_wc__db_op_make_copy_internal(svn_wc_ } else { + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + svn_error_t *err = NULL; + int affected_rows; + + op_depth = relpath_depth(local_relpath); /* We don't allow copies to contain server-excluded nodes; the update editor is going to have to bail out. */ - SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, scratch_pool)); + SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, iterpool)); + + /* Insert a shadowing layer */ + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_INSERT_DELETE_FROM_NODE_RECURSIVE)); + + /* As we are keeping whatever is below, move the*/ + + SVN_ERR(svn_sqlite__bindf(stmt, "isdd", + wcroot->wc_id, local_relpath, + 0, op_depth)); + SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); + SVN_ERR_ASSERT(affected_rows > 0); + + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_SELECT_MOVED_DESCENDANTS_SRC)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", + wcroot->wc_id, local_relpath, + op_depth)); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + while (have_row && !err) + { + err = make_copy_move_moved_to( + wcroot, + svn_sqlite__column_text(stmt, 1, iterpool), + svn_sqlite__column_int(stmt, 0), + op_depth, + svn_sqlite__column_text(stmt, 4, iterpool), + iterpool); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); + SVN_ERR(make_copy_txn(wcroot, local_relpath, - relpath_depth(local_relpath), scratch_pool)); + INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM, + relpath_depth(local_relpath), FALSE, scratch_pool)); } if (conflicts) @@ -15803,6 +15808,69 @@ svn_wc__db_verify(svn_wc__db_t *db, return SVN_NO_ERROR; } + +svn_error_t * +svn_wc__db_verify_db_full_internal(svn_wc__db_wcroot_t *wcroot, + svn_wc__db_verify_cb_t callback, + void *baton, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + svn_error_t *err = NULL; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_STATIC_VERIFY)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + while (have_row) + { + const char *local_relpath; + int op_depth = svn_sqlite__column_int(stmt, 1); + int id = svn_sqlite__column_int(stmt, 2); + const char *msg; + + svn_pool_clear(iterpool); + + local_relpath = svn_sqlite__column_text(stmt, 0, iterpool); + msg = svn_sqlite__column_text(stmt, 3, scratch_pool); + + err = callback(baton, wcroot->abspath, local_relpath, op_depth, + id, msg, iterpool); + + if (err) + break; + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + svn_pool_destroy(iterpool); + + return svn_error_trace( + svn_error_compose_create(err, svn_sqlite__reset(stmt))); +} + +svn_error_t * +svn_wc__db_verify_db_full(svn_wc__db_t *db, + const char *wri_abspath, + svn_wc__db_verify_cb_t callback, + void *baton, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + wri_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + return svn_error_trace( + svn_wc__db_verify_db_full_internal(wcroot, callback, baton, + scratch_pool)); +} + svn_error_t * svn_wc__db_bump_format(int *result_format, svn_boolean_t *bumped_format, @@ -16199,6 +16267,7 @@ process_committed_internal(svn_wc__db_t /* Read PATH's entries; this is the absolute path. */ SVN_ERR(gather_children(&children, wcroot, local_relpath, + STMT_SELECT_NODE_CHILDREN, -1, scratch_pool, iterpool)); /* Recursively loop over all children. */
Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.h?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db.h Sun Feb 22 16:52:05 2015 @@ -1421,8 +1421,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, const char *original_uuid, svn_revnum_t original_revision, const apr_array_header_t *children, - svn_boolean_t is_move, svn_depth_t depth, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool); @@ -1463,6 +1463,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t const char *original_uuid, svn_revnum_t original_revision, const char *target, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool); @@ -2136,15 +2137,26 @@ svn_wc__db_read_children_walker_info(apr /** - * Set *URL to the corresponding url for LOCAL_ABSPATH. - * If the node is added, return the url it will have in the repository. - */ -svn_error_t * -svn_wc__db_read_url(const char **url, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); + * Set *revision, *repos_relpath, *repos_root_url, *repos_uuid to + * the intended/commit location of LOCAL_ABSPATH. These arguments may be + * NULL if they are not needed. + * + * If the node is deleted, return the url it would have in the repository + * if it wouldn't be deleted. If the node is added return the url it will + * have in the repository, once committed. + * + * If the node is not added and has an existing repository location, set + * revision to its existing revision, otherwise to SVN_INVALID_REVNUM. + */ +svn_error_t * +svn_wc__db_read_repos_info(svn_revnum_t *revision, + const char **repos_relpath, + const char **repos_root_url, + const char **repos_uuid, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Set *PROPS to the properties of the node LOCAL_ABSPATH in the ACTUAL @@ -2308,6 +2320,14 @@ svn_wc__db_read_children_of_working_node apr_pool_t *result_pool, apr_pool_t *scratch_pool); +svn_error_t * +svn_wc__db_base_read_not_present_children( + const apr_array_header_t **children, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + /* Like svn_wc__db_read_children_of_working_node(), except also include any path that was a child of a deleted directory that existed at LOCAL_ABSPATH, even if that directory is now scheduled to be replaced by @@ -2396,16 +2416,6 @@ svn_wc__db_read_kind(svn_node_kind_t *ki svn_boolean_t show_hidden, apr_pool_t *scratch_pool); - -/* An analog to svn_wc__entry_is_hidden(). Set *HIDDEN to TRUE if - LOCAL_ABSPATH in DB "is not present, and I haven't scheduled something - over the top of it." */ -svn_error_t * -svn_wc__db_node_hidden(svn_boolean_t *hidden, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *scratch_pool); - /* Checks if a node replaces a node in a different layer. Also check if it replaces a BASE (op_depth 0) node or just a node in a higher layer (a copy). Finally check if this is the root of the replacement, or if the replacement @@ -2935,34 +2945,6 @@ svn_wc__db_upgrade_begin(svn_sqlite__db_ const char *repos_uuid, apr_pool_t *scratch_pool); - -svn_error_t * -svn_wc__db_upgrade_apply_dav_cache(svn_sqlite__db_t *sdb, - const char *dir_relpath, - apr_hash_t *cache_values, - apr_pool_t *scratch_pool); - - -/* ### need much more docco - - ### this function should be called within a sqlite transaction. it makes - ### assumptions around this fact. - - Apply the various sets of properties to the database nodes based on - their existence/presence, the current state of the node, and the original - format of the working copy which provided these property sets. -*/ -svn_error_t * -svn_wc__db_upgrade_apply_props(svn_sqlite__db_t *sdb, - const char *dir_abspath, - const char *local_relpath, - apr_hash_t *base_props, - apr_hash_t *revert_props, - apr_hash_t *working_props, - int original_format, - apr_int64_t wc_id, - apr_pool_t *scratch_pool); - /* Simply insert (or replace) one row in the EXTERNALS table. */ svn_error_t * svn_wc__db_upgrade_insert_external(svn_wc__db_t *db, @@ -2977,20 +2959,6 @@ svn_wc__db_upgrade_insert_external(svn_w svn_revnum_t def_revision, apr_pool_t *scratch_pool); -/* Get the repository identifier corresponding to REPOS_ROOT_URL from the - database in SDB. The value is returned in *REPOS_ID. All allocations - are allocated in SCRATCH_POOL. - - NOTE: the row in REPOSITORY must exist. If not, then SVN_ERR_WC_DB_ERROR - is returned. - - ### unclear on whether/how this interface will stay/evolve. */ -svn_error_t * -svn_wc__db_upgrade_get_repos_id(apr_int64_t *repos_id, - svn_sqlite__db_t *sdb, - const char *repos_root_url, - apr_pool_t *scratch_pool); - /* Upgrade the metadata concerning the WC at WCROOT_ABSPATH, in DB, * to the SVN_WC__VERSION format. * @@ -3526,6 +3494,28 @@ svn_wc__required_lock_for_resolve(const apr_pool_t *scratch_pool); /* @} */ +typedef svn_error_t * (*svn_wc__db_verify_cb_t)(void *baton, + const char *wc_abspath, + const char *local_relpath, + int op_depth, + int id, + const char *description, + apr_pool_t *scratch_pool); + +/* Checks the database for FULL-correctness according to the spec. + + Note that typical 1.7-1.9 databases WILL PRODUCE warnings. + + This is mainly useful for WC-NG developers, as there will be + warnings without the database being corrupt +*/ +svn_error_t * +svn_wc__db_verify_db_full(svn_wc__db_t *db, + const char *wri_abspath, + svn_wc__db_verify_cb_t callback, + void *baton, + apr_pool_t *scratch_pool); + #ifdef __cplusplus } Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_private.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_private.h?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_private.h (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_private.h Sun Feb 22 16:52:05 2015 @@ -511,4 +511,10 @@ svn_wc__db_update_move_list_notify(svn_w void *notify_baton, apr_pool_t *scratch_pool); +svn_error_t * +svn_wc__db_verify_db_full_internal(svn_wc__db_wcroot_t *wcroot, + svn_wc__db_verify_cb_t callback, + void *baton, + apr_pool_t *scratch_pool); + #endif /* WC_DB_PRIVATE_H */ Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_util.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_util.c?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_util.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_util.c Sun Feb 22 16:52:05 2015 @@ -83,7 +83,7 @@ static svn_error_t * relpath_depth_sqlite(svn_sqlite__context_t *sctx, int argc, svn_sqlite__value_t *values[], - apr_pool_t *scratch_pool) + void *baton) { const char *path = NULL; apr_int64_t depth; Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_wcroot.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_wcroot.c?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_wcroot.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/wc_db_wcroot.c Sun Feb 22 16:52:05 2015 @@ -28,6 +28,7 @@ #include "svn_dirent_uri.h" #include "svn_hash.h" #include "svn_path.h" +#include "svn_pools.h" #include "svn_version.h" #include "wc.h" @@ -42,7 +43,7 @@ #define UNKNOWN_WC_ID ((apr_int64_t) -1) #define FORMAT_FROM_SDB (-1) - +/* #define VERIFY_ON_CLOSE */ /* Get the format version from a wc-1 directory. If it is not a working copy directory, then it sets VERSION to zero and returns no error. */ @@ -162,6 +163,27 @@ svn_wc__db_verify_no_work(svn_sqlite__db return SVN_NO_ERROR; } +#if defined(VERIFY_ON_CLOSE) && defined(SVN_DEBUG) +/* Implements svn_wc__db_verify_cb_t */ +static svn_error_t * +verify_db_cb(void *baton, + const char *wc_abspath, + const char *local_relpath, + int op_depth, + int id, + const char *msg, + apr_pool_t *scratch_pool) +{ + if (op_depth >= 0) + SVN_DBG(("DB-VRFY: %s: %s (%d): SV%04d %s", + wc_abspath, local_relpath, op_depth, id, msg)); + else + SVN_DBG(("DB-VRFY: %s: %s: SV%04d %s", + wc_abspath, local_relpath, id, msg)); + + return SVN_NO_ERROR; +} +#endif /* */ static apr_status_t @@ -172,6 +194,18 @@ close_wcroot(void *data) SVN_ERR_ASSERT_NO_RETURN(wcroot->sdb != NULL); +#if defined(VERIFY_ON_CLOSE) && defined(SVN_DEBUG) + if (getenv("SVN_CMDLINE_VERIFY_SQL_AT_CLOSE")) + { + apr_pool_t *scratch_pool = svn_pool_create(NULL); + + svn_error_clear(svn_wc__db_verify_db_full_internal( + wcroot, verify_db_cb, NULL, scratch_pool)); + + svn_pool_destroy(scratch_pool); + } +#endif + err = svn_sqlite__close(wcroot->sdb); wcroot->sdb = NULL; if (err) Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/mod_dav_svn.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/mod_dav_svn.c?rev=1661492&r1=1661491&r2=1661492&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/mod_dav_svn/mod_dav_svn.c (original) +++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/mod_dav_svn.c Sun Feb 22 16:52:05 2015 @@ -143,6 +143,25 @@ init(apr_pool_t *p, apr_pool_t *plog, ap return OK; } +static svn_error_t * +malfunction_handler(svn_boolean_t can_return, + const char *file, int line, + const char *expr) +{ + if (expr) + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, + "mod_dav_svn: file '%s', line %d, assertion \"%s\" failed", + file, line, expr); + else + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, + "mod_dav_svn: file '%s', line %d, internal malfunction", + file, line); + abort(); + + /* Should not be reached. */ + return SVN_NO_ERROR; +} + static int init_dso(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { @@ -162,6 +181,8 @@ init_dso(apr_pool_t *pconf, apr_pool_t * return HTTP_INTERNAL_SERVER_ERROR; } + svn_error_set_malfunction_handler(malfunction_handler); + return OK; }
