Index: subversion/libsvn_wc/entries.c =================================================================== --- subversion/libsvn_wc/entries.c (revision 1135795) +++ subversion/libsvn_wc/entries.c (working copy) @@ -2199,38 +2199,29 @@ return SVN_NO_ERROR; } -struct entries_write_baton +svn_error_t * +svn_wc__write_upgraded_entries(void **dir_baton, + void *parent_baton, + svn_wc__db_t *db, + svn_sqlite__db_t *sdb, + apr_int64_t repos_id, + apr_int64_t wc_id, + const char *dir_abspath, + const char *new_root_abspath, + apr_hash_t *entries, + apr_hash_t *text_bases_info, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - svn_wc__db_t *db; - apr_int64_t repos_id; - apr_int64_t wc_id; - const char *dir_abspath; - const char *new_root_abspath; - apr_hash_t *entries; - apr_hash_t *text_bases_info; - struct write_baton *parent_node; - struct write_baton *dir_node; - apr_pool_t *result_pool; -}; - -/* Writes entries inside a sqlite transaction - Implements svn_sqlite__transaction_callback_t. */ -static svn_error_t * -entries_write_new_cb(void *baton, - svn_sqlite__db_t *sdb, - apr_pool_t *scratch_pool) -{ - struct entries_write_baton *ewb = baton; - svn_wc__db_t *db = ewb->db; - const char *dir_abspath = ewb->dir_abspath; - const char *new_root_abspath = ewb->new_root_abspath; const svn_wc_entry_t *this_dir; apr_hash_index_t *hi; apr_pool_t *iterpool = svn_pool_create(scratch_pool); const char *old_root_abspath, *dir_relpath; + struct write_baton *parent_node = parent_baton; + struct write_baton *dir_node; /* Get a copy of the "this dir" entry for comparison purposes. */ - this_dir = apr_hash_get(ewb->entries, SVN_WC_ENTRY_THIS_DIR, + this_dir = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); /* If there is no "this dir" entry, something is wrong. */ @@ -2248,21 +2239,21 @@ dir_relpath = svn_dirent_skip_ancestor(old_root_abspath, dir_abspath); /* Write out "this dir" */ - SVN_ERR(write_entry(&ewb->dir_node, ewb->parent_node, db, sdb, - ewb->wc_id, ewb->repos_id, this_dir, NULL, dir_relpath, + SVN_ERR(write_entry(&dir_node, parent_node, db, sdb, + wc_id, repos_id, this_dir, NULL, dir_relpath, svn_dirent_join(new_root_abspath, dir_relpath, - scratch_pool), + iterpool), old_root_abspath, - this_dir, FALSE, ewb->result_pool, iterpool)); + this_dir, FALSE, result_pool, iterpool)); - for (hi = apr_hash_first(scratch_pool, ewb->entries); hi; + for (hi = apr_hash_first(scratch_pool, entries); hi; hi = apr_hash_next(hi)) { const char *name = svn__apr_hash_index_key(hi); const svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi); const char *child_abspath, *child_relpath; svn_wc__text_base_info_t *text_base_info - = apr_hash_get(ewb->text_bases_info, name, APR_HASH_KEY_STRING); + = apr_hash_get(text_bases_info, name, APR_HASH_KEY_STRING); svn_pool_clear(iterpool); @@ -2274,61 +2265,25 @@ use this function for upgrading old working copies. */ child_abspath = svn_dirent_join(dir_abspath, name, iterpool); child_relpath = svn_dirent_skip_ancestor(old_root_abspath, child_abspath); - SVN_ERR(write_entry(NULL, ewb->dir_node, db, sdb, - ewb->wc_id, ewb->repos_id, + SVN_ERR(write_entry(NULL, dir_node, db, sdb, + wc_id, repos_id, this_entry, text_base_info, child_relpath, svn_dirent_join(new_root_abspath, child_relpath, - scratch_pool), + iterpool), old_root_abspath, this_dir, TRUE, iterpool, iterpool)); } - if (ewb->dir_node->tree_conflicts) - SVN_ERR(write_actual_only_entries(ewb->dir_node->tree_conflicts, sdb, - ewb->wc_id, dir_relpath, iterpool)); + if (dir_node->tree_conflicts) + SVN_ERR(write_actual_only_entries(dir_node->tree_conflicts, sdb, + wc_id, dir_relpath, iterpool)); + *dir_baton = dir_node; svn_pool_destroy(iterpool); return SVN_NO_ERROR; } -svn_error_t * -svn_wc__write_upgraded_entries(void **dir_baton, - void *parent_baton, - svn_wc__db_t *db, - svn_sqlite__db_t *sdb, - apr_int64_t repos_id, - apr_int64_t wc_id, - const char *dir_abspath, - const char *new_root_abspath, - apr_hash_t *entries, - apr_hash_t *text_bases_info, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - struct entries_write_baton ewb; - - ewb.db = db; - ewb.repos_id = repos_id; - ewb.wc_id = wc_id; - ewb.dir_abspath = dir_abspath; - ewb.new_root_abspath = new_root_abspath; - ewb.entries = entries; - ewb.text_bases_info = text_bases_info; - ewb.parent_node = parent_baton; - ewb.result_pool = result_pool; - - /* Run this operation in a transaction to speed up SQLite. - See http://www.sqlite.org/faq.html#q19 for more details */ - SVN_ERR(svn_sqlite__with_transaction(sdb, entries_write_new_cb, &ewb, - scratch_pool)); - - *dir_baton = ewb.dir_node; - - return SVN_NO_ERROR; -} - - svn_wc_entry_t * svn_wc_entry_dup(const svn_wc_entry_t *entry, apr_pool_t *pool) { Index: subversion/libsvn_wc/upgrade.c =================================================================== --- subversion/libsvn_wc/upgrade.c (revision 1135795) +++ subversion/libsvn_wc/upgrade.c (working copy) @@ -1366,9 +1366,7 @@ REPOS_CACHE if it doesn't have a cached entry for this repository. - DATA->SDB will be null if this is the root directory, in which case - the db must be created and *DATA filled in, otherwise *DATA refer - to the single root db. + *DATA refers to the single root db. Uses SCRATCH_POOL for all temporary allocation. */ static svn_error_t * @@ -1452,39 +1450,6 @@ apr_pstrdup(hash_pool, this_dir->uuid)); } - /* Create the new DB if it hasn't already been created. */ - if (!data->sdb) - { - const char *root_adm_abspath; - - /* In root wc construst path to temporary root wc/.svn/tmp/wcng/.svn */ - - data->root_abspath = svn_dirent_join(svn_wc__adm_child(dir_abspath, "tmp", - scratch_pool), - "wcng", result_pool); - root_adm_abspath = svn_wc__adm_child(data->root_abspath, "", - scratch_pool); - SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL, - scratch_pool)); - SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool)); - - /* Create an empty sqlite database for this directory. */ - SVN_ERR(svn_wc__db_upgrade_begin(&data->sdb, - &data->repos_id, &data->wc_id, - data->root_abspath, - this_dir->repos, this_dir->uuid, - result_pool, scratch_pool)); - - /* Migrate the entries over to the new database. - ### We need to think about atomicity here. - - entries_write_new() writes in current format rather than - f12. Thus, this function bumps a working copy all the way to - current. */ - SVN_ERR(svn_wc__db_wclock_obtain(db, data->root_abspath, 0, FALSE, - scratch_pool)); - } - old_wcroot_abspath = svn_dirent_get_longest_ancestor(dir_abspath, data->root_abspath, scratch_pool); @@ -1833,6 +1798,40 @@ svn_dirent_local_style(parent_abspath, scratch_pool)); } +/* Data for upgrade_working_copy_txn(). */ +typedef struct upgrade_working_copy_baton_t +{ + svn_wc__db_t *db; + const char *dir_abspath; + svn_wc_upgrade_get_repos_info_t repos_info_func; + void *repos_info_baton; + apr_hash_t *repos_cache; + struct upgrade_data_t *data; + svn_cancel_func_t cancel_func; + void *cancel_baton; + svn_wc_notify_func2_t notify_func; + void *notify_baton; + apr_pool_t *result_pool; +} upgrade_working_copy_baton_t; + + +/* Helper for svn_wc_upgrade. Implements svn_sqlite__transaction_callback_t */ +static svn_error_t * +upgrade_working_copy_txn(void *baton, + svn_sqlite__db_t *sdb, + apr_pool_t *scratch_pool) +{ + upgrade_working_copy_baton_t *b = baton; + + /* Upgrade the pre-wcng into a wcng in a temporary location. */ + return(upgrade_working_copy(NULL, b->db, b->dir_abspath, + b->repos_info_func, b->repos_info_baton, + b->repos_cache, b->data, + b->cancel_func, b->cancel_baton, + b->notify_func, b->notify_baton, + b->result_pool, scratch_pool)); +} + svn_error_t * svn_wc_upgrade(svn_wc_context_t *wc_ctx, const char *local_abspath, @@ -1848,6 +1847,11 @@ struct upgrade_data_t data = { NULL }; svn_skel_t *work_item, *work_items = NULL; const char *pristine_from, *pristine_to, *db_from, *db_to; + apr_hash_t *repos_cache = apr_hash_make(scratch_pool); + svn_wc_entry_t *this_dir; + apr_hash_t *entries; + const char *root_adm_abspath; + upgrade_working_copy_baton_t cb_baton; SVN_ERR(is_old_wcroot(local_abspath, scratch_pool)); @@ -1864,14 +1868,65 @@ NULL /* ### config */, FALSE, FALSE, scratch_pool, scratch_pool)); - /* Upgrade the pre-wcng into a wcng in a temporary location. */ - SVN_ERR(upgrade_working_copy(NULL, db, local_abspath, - repos_info_func, repos_info_baton, - apr_hash_make(scratch_pool), &data, - cancel_func, cancel_baton, - notify_func, notify_baton, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath, + scratch_pool, scratch_pool)); + this_dir = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, + APR_HASH_KEY_STRING); + SVN_ERR(ensure_repos_info(this_dir, local_abspath, repos_info_func, + repos_info_baton, repos_cache, + scratch_pool, scratch_pool)); + + /* Cache repos UUID pairs for when a subdir doesn't have this information */ + if (!apr_hash_get(repos_cache, this_dir->repos, APR_HASH_KEY_STRING)) + apr_hash_set(repos_cache, + apr_pstrdup(scratch_pool, this_dir->repos), + APR_HASH_KEY_STRING, + apr_pstrdup(scratch_pool, this_dir->uuid)); + + /* Create the new DB in the temporary root wc/.svn/tmp/wcng/.svn */ + data.root_abspath = svn_dirent_join(svn_wc__adm_child(local_abspath, "tmp", + scratch_pool), + "wcng", scratch_pool); + root_adm_abspath = svn_wc__adm_child(data.root_abspath, "", + scratch_pool); + SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL, + scratch_pool)); + SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool)); + + /* Create an empty sqlite database for this directory. */ + SVN_ERR(svn_wc__db_upgrade_begin(&data.sdb, + &data.repos_id, &data.wc_id, + data.root_abspath, + this_dir->repos, this_dir->uuid, + scratch_pool, scratch_pool)); + + /* Migrate the entries over to the new database. + ### We need to think about atomicity here. + + entries_write_new() writes in current format rather than + f12. Thus, this function bumps a working copy all the way to + current. */ + SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE, + scratch_pool)); + + cb_baton.db = db; + cb_baton.dir_abspath = local_abspath; + cb_baton.repos_info_func = repos_info_func; + cb_baton.repos_info_baton = repos_info_baton; + cb_baton.repos_cache = repos_cache; + cb_baton.data = &data; + cb_baton.cancel_func = cancel_func; + cb_baton.cancel_baton = cancel_baton; + cb_baton.notify_func = notify_func; + cb_baton.notify_baton = notify_baton; + cb_baton.result_pool = scratch_pool; + + SVN_ERR(svn_sqlite__with_lock(data.sdb, + upgrade_working_copy_txn, + &cb_baton, + scratch_pool)); + /* A workqueue item to move the pristine dir into place */ pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH, scratch_pool);