You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/08/10 22:56:05 UTC
svn commit: r984206 [25/35] - in /subversion/branches/ignore-mergeinfo: ./
build/ build/generator/ build/generator/templates/ build/hudson/
build/hudson/jobs/subversion-1.6.x-solaris/
build/hudson/jobs/subversion-1.6.x-ubuntu/ build/hudson/jobs/subvers...
Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c?rev=984206&r1=984205&r2=984206&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c Tue Aug 10 20:55:56 2010
@@ -21,6 +21,8 @@
* ====================================================================
*/
+#define SVN_WC__I_AM_WC_DB
+
#include <assert.h>
#include <apr_pools.h>
#include <apr_hash.h>
@@ -40,6 +42,8 @@
#include "entries.h"
#include "lock.h"
#include "tree_conflicts.h"
+#include "wc_db_private.h"
+#include "workqueue.h"
#include "svn_private_config.h"
#include "private/svn_sqlite.h"
@@ -102,80 +106,6 @@
#define FORMAT_FROM_SDB (-1)
-struct svn_wc__db_t {
- /* What's the appropriate mode for this datastore? */
- svn_wc__db_openmode_t mode;
-
- /* We need the config whenever we run into a new WC directory, in order
- to figure out where we should look for the corresponding datastore. */
- svn_config_t *config;
-
- /* Should we attempt to automatically upgrade the database when it is
- opened, and found to be not-current? */
- svn_boolean_t auto_upgrade;
-
- /* Should we ensure the WORK_QUEUE is empty when a WCROOT is opened? */
- svn_boolean_t enforce_empty_wq;
-
- /* Map a given working copy directory to its relevant data.
- const char *local_abspath -> svn_wc__db_pdh_t *pdh */
- apr_hash_t *dir_data;
-
- /* As we grow the state of this DB, allocate that state here. */
- apr_pool_t *state_pool;
-};
-
-/** Hold information about a WCROOT.
- *
- * This structure is referenced by all per-directory handles underneath it.
- */
-typedef struct {
- /* Location of this wcroot in the filesystem. */
- const char *abspath;
-
- /* The SQLite database containing the metadata for everything in
- this wcroot. */
- svn_sqlite__db_t *sdb;
-
- /* The WCROOT.id for this directory (and all its children). */
- apr_int64_t wc_id;
-
- /* The format of this wcroot's metadata storage (see wc.h). If the
- format has not (yet) been determined, this will be UNKNOWN_FORMAT. */
- int format;
-
-} wcroot_t;
-
-/** Pristine Directory Handle
- *
- * This structure records all the information that we need to deal with
- * a given working copy directory.
- */
-typedef struct svn_wc__db_pdh_t {
- /* This (versioned) working copy directory is obstructing what *should*
- be a file in the parent directory (according to its metadata).
-
- Note: this PDH should probably be ignored (or not created).
-
- ### obstruction is only possible with per-dir wc.db databases. */
- svn_boolean_t obstructed_file;
-
- /* The absolute path to this working copy directory. */
- const char *local_abspath;
-
- /* What wcroot does this directory belong to? */
- wcroot_t *wcroot;
-
- /* The parent directory's per-dir information. */
- struct svn_wc__db_pdh_t *parent;
-
- /* Whether this process owns a write-lock on this directory. */
- svn_boolean_t locked;
-
- /* Hold onto the old-style access baton that corresponds to this PDH. */
- svn_wc_adm_access_t *adm_access;
-} svn_wc__db_pdh_t;
-
/* Assert that the given PDH is usable.
NOTE: the expression is multiply-evaluated!! */
#define VERIFY_USABLE_PDH(pdh) SVN_ERR_ASSERT( \
@@ -183,19 +113,6 @@ typedef struct svn_wc__db_pdh_t {
&& (pdh)->wcroot->format == SVN_WC__VERSION)
-/* Verify the checksum kind for pristine storage. */
-#define VERIFY_CHECKSUM_KIND(checksum) \
- do { \
- if ((checksum)->kind != svn_checksum_sha1) \
- return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, \
- _("Only SHA1 checksums can be used as keys " \
- "in the pristine file storage.\n")); \
- } while (0)
-/* ### not ready to enforce SHA1 yet. disable the check. */
-#undef VERIFY_CHECKSUM_KIND
-#define VERIFY_CHECKSUM_KIND(checksum) ((void)0)
-
-
/* ### since we're putting the pristine files per-dir, then we don't need
### to create subdirectories in order to keep the directory size down.
### when we can aggregate pristine files across dirs/wcs, then we will
@@ -239,9 +156,48 @@ typedef struct {
/* for inserting symlinks */
const char *target;
+ /* may need to insert/update ACTUAL to record a conflict */
+ const svn_skel_t *conflict;
+
+ /* may have work items to queue in this transaction */
+ const svn_skel_t *work_items;
+
} insert_base_baton_t;
+typedef struct {
+ /* common to all insertions into WORKING */
+ svn_wc__db_status_t presence;
+ svn_wc__db_kind_t kind;
+ apr_int64_t wc_id;
+ const char *local_relpath;
+
+ /* common to all "normal" presence insertions */
+ const apr_hash_t *props;
+ svn_revnum_t changed_rev;
+ apr_time_t changed_date;
+ const char *changed_author;
+ apr_int64_t original_repos_id;
+ const char *original_repos_relpath;
+ svn_revnum_t original_revnum;
+ svn_boolean_t moved_here;
+
+ /* for inserting directories */
+ const apr_array_header_t *children;
+ svn_depth_t depth;
+
+ /* for inserting (copied/moved-here) files */
+ const svn_checksum_t *checksum;
+
+ /* for inserting symlinks */
+ const char *target;
+
+ /* may have work items to queue in this transaction */
+ const svn_skel_t *work_items;
+
+} insert_working_baton_t;
+
+
static const svn_token_map_t kind_map[] = {
{ "file", svn_wc__db_kind_file },
{ "dir", svn_wc__db_kind_dir },
@@ -264,6 +220,13 @@ static const svn_token_map_t presence_ma
};
+/* Forward declarations */
+static svn_error_t *
+add_work_items(svn_sqlite__db_t *sdb,
+ const svn_skel_t *skel,
+ apr_pool_t *scratch_pool);
+
+
/* */
static svn_filesize_t
get_translated_size(svn_sqlite__stmt_t *stmt, int slot)
@@ -313,138 +276,6 @@ escape_sqlite_like(const char * const st
}
-/* */
-static svn_error_t *
-verify_no_work(svn_sqlite__db_t *sdb)
-{
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_LOOK_FOR_WORK));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- SVN_ERR(svn_sqlite__reset(stmt));
-
- if (have_row)
- return svn_error_create(SVN_ERR_WC_CLEANUP_REQUIRED, NULL,
- NULL /* nothing to add. */);
-
- return SVN_NO_ERROR;
-}
-
-
-/* */
-static apr_status_t
-close_wcroot(void *data)
-{
- wcroot_t *wcroot = data;
- svn_error_t *err;
-
- SVN_ERR_ASSERT_NO_RETURN(wcroot->sdb != NULL);
-
- err = svn_sqlite__close(wcroot->sdb);
- wcroot->sdb = NULL;
- if (err)
- {
- apr_status_t result = err->apr_err;
- svn_error_clear(err);
- return result;
- }
-
- return APR_SUCCESS;
-}
-
-
-/* */
-static svn_error_t *
-close_many_wcroots(apr_hash_t *roots,
- apr_pool_t *state_pool,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first(scratch_pool, roots); hi; hi = apr_hash_next(hi))
- {
- wcroot_t *wcroot = svn__apr_hash_index_val(hi);
- apr_status_t result;
-
- result = apr_pool_cleanup_run(state_pool, wcroot, close_wcroot);
- if (result != APR_SUCCESS)
- return svn_error_wrap_apr(result, NULL);
- }
-
- return SVN_NO_ERROR;
-}
-
-
-/* Construct a new wcroot_t. The WCROOT_ABSPATH and SDB parameters must
- have lifetime of at least RESULT_POOL. */
-static svn_error_t *
-create_wcroot(wcroot_t **wcroot,
- const char *wcroot_abspath,
- svn_sqlite__db_t *sdb,
- apr_int64_t wc_id,
- int format,
- svn_boolean_t auto_upgrade,
- svn_boolean_t enforce_empty_wq,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- if (sdb != NULL)
- SVN_ERR(svn_sqlite__read_schema_version(&format, sdb, scratch_pool));
-
- /* If we construct a wcroot, then we better have a format. */
- SVN_ERR_ASSERT(format >= 1);
-
- /* If this working copy is PRE-1.0, then simply bail out. */
- if (format < 4)
- {
- return svn_error_createf(
- SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
- _("Working copy format of '%s' is too old (%d); "
- "please check out your working copy again"),
- svn_dirent_local_style(wcroot_abspath, scratch_pool), format);
- }
-
- /* If this working copy is from a future version, then bail out. */
- if (format > SVN_WC__VERSION)
- {
- return svn_error_createf(
- SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
- _("This client is too old to work with the working copy at\n"
- "'%s' (format %d).\n"
- "You need to get a newer Subversion client. For more details, see\n"
- " http://subversion.apache.org/faq.html#working-copy-format-change\n"
- ),
- svn_dirent_local_style(wcroot_abspath, scratch_pool),
- format);
- }
-
- /* Auto-upgrade the SDB if possible. */
- if (format < SVN_WC__VERSION && auto_upgrade)
- SVN_ERR(svn_wc__upgrade_sdb(&format, wcroot_abspath, sdb, format,
- scratch_pool));
-
- /* Verify that no work items exists. If they do, then our integrity is
- suspect and, thus, we cannot use this database. */
- if (format >= SVN_WC__HAS_WORK_QUEUE && enforce_empty_wq)
- SVN_ERR(verify_no_work(sdb));
-
- *wcroot = apr_palloc(result_pool, sizeof(**wcroot));
-
- (*wcroot)->abspath = wcroot_abspath;
- (*wcroot)->sdb = sdb;
- (*wcroot)->wc_id = wc_id;
- (*wcroot)->format = format;
-
- /* SDB will be NULL for pre-NG working copies. We only need to run a
- cleanup when the SDB is present. */
- if (sdb != NULL)
- apr_pool_cleanup_register(result_pool, *wcroot, close_wcroot,
- apr_pool_cleanup_null);
- return SVN_NO_ERROR;
-}
-
-
/* Returns in PRISTINE_ABSPATH a new string allocated from RESULT_POOL,
holding the local absolute path to the file location that is dedicated
to hold CHECKSUM's pristine file, relating to the pristine store
@@ -459,22 +290,22 @@ create_wcroot(wcroot_t **wcroot,
static svn_error_t *
get_pristine_fname(const char **pristine_abspath,
svn_wc__db_pdh_t *pdh,
- const svn_checksum_t *checksum,
-#ifndef SVN__SKIP_SUBDIR
+ const svn_checksum_t *sha1_checksum,
svn_boolean_t create_subdir,
-#endif
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *base_dir_abspath;
- const char *hexdigest = svn_checksum_to_cstring(checksum, scratch_pool);
+ const char *hexdigest = svn_checksum_to_cstring(sha1_checksum, scratch_pool);
#ifndef SVN__SKIP_SUBDIR
char subdir[3];
#endif
/* ### code is in transition. make sure we have the proper data. */
+ SVN_ERR_ASSERT(pristine_abspath != NULL);
SVN_ERR_ASSERT(pdh->wcroot != NULL);
- SVN_ERR_ASSERT(checksum->kind == svn_checksum_sha1);
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
/* ### need to fix this to use a symbol for ".svn". we don't need
### to use join_many since we know "/" is the separator for
@@ -538,7 +369,7 @@ fetch_repos_info(const char **repos_root
SVN_ERR(svn_sqlite__bindf(stmt, "i", repos_id));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
- return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt),
_("No REPOSITORY table entry for id '%ld'"),
(long int)repos_id);
@@ -558,7 +389,7 @@ fetch_repos_info(const char **repos_root
static svn_error_t *
scan_upwards_for_repos(apr_int64_t *repos_id,
const char **repos_relpath,
- const wcroot_t *wcroot,
+ const svn_wc__db_wcroot_t *wcroot,
const char *local_abspath,
const char *local_relpath,
apr_pool_t *result_pool,
@@ -656,759 +487,312 @@ scan_upwards_for_repos(apr_int64_t *repo
}
-/* 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. */
+/* 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_old_version(int *version,
- const char *abspath,
- apr_pool_t *scratch_pool)
+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_error_t *err;
- const char *format_file_path;
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
- /* Try reading the format number from the entries file. */
- format_file_path = svn_wc__adm_child(abspath, SVN_WC__ADM_ENTRIES,
- scratch_pool);
- err = svn_io_read_version_file(version, format_file_path, scratch_pool);
- if (err == NULL)
- return SVN_NO_ERROR;
- if (err->apr_err != SVN_ERR_BAD_VERSION_FILE_FORMAT
- && !APR_STATUS_IS_ENOENT(err->apr_err)
- && !APR_STATUS_IS_ENOTDIR(err->apr_err))
- return svn_error_createf(SVN_ERR_WC_MISSING, err, _("'%s' does not exist"),
- svn_dirent_local_style(abspath, scratch_pool));
- svn_error_clear(err);
-
- /* This must be a really old working copy! Fall back to reading the
- format file.
-
- Note that the format file might not exist in newer working copies
- (format 7 and higher), but in that case, the entries file should
- have contained the format number. */
- format_file_path = svn_wc__adm_child(abspath, SVN_WC__ADM_FORMAT,
- scratch_pool);
- err = svn_io_read_version_file(version, format_file_path, scratch_pool);
- if (err == NULL)
- return SVN_NO_ERROR;
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- /* Whatever error may have occurred... we can just ignore. This is not
- a working copy directory. Signal the caller. */
- svn_error_clear(err);
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(stmt, pdh->wcroot->sdb, stmt_idx));
+ SVN_ERR(svn_sqlite__bindf(*stmt, "is", pdh->wcroot->wc_id, local_relpath));
- *version = 0;
return SVN_NO_ERROR;
}
/* */
-static svn_wc__db_pdh_t *
-get_or_create_pdh(svn_wc__db_t *db,
- const char *local_dir_abspath,
- svn_boolean_t create_allowed,
- apr_pool_t *scratch_pool)
+static svn_error_t *
+navigate_to_parent(svn_wc__db_pdh_t **parent_pdh,
+ svn_wc__db_t *db,
+ svn_wc__db_pdh_t *child_pdh,
+ svn_sqlite__mode_t smode,
+ apr_pool_t *scratch_pool)
{
- svn_wc__db_pdh_t *pdh = apr_hash_get(db->dir_data,
- local_dir_abspath, APR_HASH_KEY_STRING);
-
- if (pdh == NULL && create_allowed)
- {
- pdh = apr_pcalloc(db->state_pool, sizeof(*pdh));
-
- /* Copy the path for the proper lifetime. */
- pdh->local_abspath = apr_pstrdup(db->state_pool, local_dir_abspath);
-
- /* We don't know anything about this directory, so we cannot construct
- a wcroot_t for it (yet). */
-
- /* ### parent */
+ const char *parent_abspath;
+ const char *local_relpath;
- apr_hash_set(db->dir_data, pdh->local_abspath, APR_HASH_KEY_STRING, pdh);
- }
+ if ((*parent_pdh = child_pdh->parent) != NULL
+ && (*parent_pdh)->wcroot != NULL)
+ return SVN_NO_ERROR;
- return pdh;
-}
+ parent_abspath = svn_dirent_dirname(child_pdh->local_abspath, scratch_pool);
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(parent_pdh, &local_relpath, db,
+ parent_abspath, smode,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(*parent_pdh);
+ child_pdh->parent = *parent_pdh;
-/* POOL may be NULL if the lifetime of LOCAL_ABSPATH is sufficient. */
-static const char *
-compute_pdh_relpath(const svn_wc__db_pdh_t *pdh,
- apr_pool_t *result_pool)
-{
- const char *relpath = svn_dirent_is_child(pdh->wcroot->abspath,
- pdh->local_abspath,
- result_pool);
- if (relpath == NULL)
- return "";
- return relpath;
+ return SVN_NO_ERROR;
}
-/* The filesystem has a directory at LOCAL_RELPATH. Examine the metadata
- to determine if a *file* was supposed to be there.
-
- ### this function is only required for per-dir .svn support. once all
- ### metadata is collected in a single wcroot, then we won't need to
- ### look in subdirs for other metadata. */
+/* 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 *
-determine_obstructed_file(svn_boolean_t *obstructed_file,
- const wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
+create_repos_id(apr_int64_t *repos_id,
+ const char *repos_root_url,
+ const char *repos_uuid,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
{
- svn_sqlite__stmt_t *stmt;
+ svn_sqlite__stmt_t *get_stmt;
+ svn_sqlite__stmt_t *insert_stmt;
svn_boolean_t have_row;
- SVN_ERR_ASSERT(wcroot->sdb != NULL && wcroot->wc_id != UNKNOWN_WC_ID);
+ SVN_ERR(svn_sqlite__get_statement(&get_stmt, sdb, STMT_SELECT_REPOSITORY));
+ SVN_ERR(svn_sqlite__bindf(get_stmt, "s", repos_root_url));
+ SVN_ERR(svn_sqlite__step(&have_row, get_stmt));
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_WORKING_IS_FILE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is",
- wcroot->wc_id,
- local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
- *obstructed_file = svn_sqlite__column_boolean(stmt, 0);
+ *repos_id = svn_sqlite__column_int64(get_stmt, 0);
+ return svn_error_return(svn_sqlite__reset(get_stmt));
}
- else
- {
- SVN_ERR(svn_sqlite__reset(stmt));
+ SVN_ERR(svn_sqlite__reset(get_stmt));
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_BASE_IS_FILE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is",
- wcroot->wc_id,
- local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- *obstructed_file = svn_sqlite__column_boolean(stmt, 0);
- }
+ /* NOTE: strictly speaking, there is a race condition between the
+ above query and the insertion below. We're simply going to ignore
+ that, as it means two processes are *modifying* the working copy
+ at the same time, *and* new repositores are becoming visible.
+ This is rare enough, let alone the miniscule chance of hitting
+ this race condition. Further, simply failing out will leave the
+ database in a consistent state, and the user can just re-run the
+ failed operation. */
- return svn_sqlite__reset(stmt);
+ SVN_ERR(svn_sqlite__get_statement(&insert_stmt, sdb,
+ STMT_INSERT_REPOSITORY));
+ SVN_ERR(svn_sqlite__bindf(insert_stmt, "ss", repos_root_url, repos_uuid));
+ return svn_error_return(svn_sqlite__insert(repos_id, insert_stmt));
}
-/* */
-static svn_error_t *
-fetch_wc_id(apr_int64_t *wc_id,
- svn_sqlite__db_t *sdb,
- apr_pool_t *scratch_pool)
+/* Initialize the baton with appropriate "blank" values. This allows the
+ insertion function to leave certain columns null. */
+static void
+blank_ibb(insert_base_baton_t *pibb)
{
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
-
- /* ### cheat. we know there is just one WORKING_COPY row, and it has a
- ### NULL value for local_abspath. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_WCROOT_NULL));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (!have_row)
- return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
- _("Missing a row in WCROOT."));
-
- SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 0));
- *wc_id = svn_sqlite__column_int64(stmt, 0);
-
- return svn_error_return(svn_sqlite__reset(stmt));
+ memset(pibb, 0, sizeof(*pibb));
+ pibb->revision = SVN_INVALID_REVNUM;
+ pibb->changed_rev = SVN_INVALID_REVNUM;
+ pibb->depth = svn_depth_infinity;
+ pibb->translated_size = SVN_INVALID_FILESIZE;
}
/* */
static svn_error_t *
-open_db(svn_sqlite__db_t **sdb,
- const char *dir_abspath,
- const char *sdb_fname,
- svn_sqlite__mode_t smode,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname,
- scratch_pool);
-
- return svn_error_return(svn_sqlite__open(sdb, sdb_abspath,
- smode, statements,
- 0, NULL,
- result_pool, scratch_pool));
-}
-
-
-/* For a given LOCAL_ABSPATH, figure out what sqlite database (PDH) to
- use and the RELPATH within that wcroot. If a sqlite database needs
- to be opened, then use SMODE for it. */
-static svn_error_t *
-parse_local_abspath(svn_wc__db_pdh_t **pdh,
- const char **local_relpath,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_sqlite__mode_t smode,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
- const char *original_abspath = local_abspath;
- svn_node_kind_t kind;
- svn_boolean_t special;
- const char *build_relpath;
- svn_wc__db_pdh_t *found_pdh = NULL;
- svn_wc__db_pdh_t *child_pdh;
- svn_boolean_t obstruction_possible = FALSE;
- svn_sqlite__db_t *sdb;
- svn_boolean_t moved_upwards = FALSE;
- svn_boolean_t always_check = FALSE;
- int wc_format = 0;
-
- /* ### we need more logic for finding the database (if it is located
- ### outside of the wcroot) and then managing all of that within DB.
- ### for now: play quick & dirty. */
-
- /* ### for now, overwrite the provided mode. We currently cache the
- ### sdb handles, which is great but for the occasion where we
- ### initially open the sdb in readonly mode and then later want
- ### to write to it. The solution is to reopen the db in readwrite
- ### mode, but that assumes we can track the fact that it was
- ### originally opened readonly. So for now, just punt and open
- ### everything in readwrite mode. */
- smode = svn_sqlite__mode_readwrite;
-
- *pdh = apr_hash_get(db->dir_data, local_abspath, APR_HASH_KEY_STRING);
- if (*pdh != NULL && (*pdh)->wcroot != NULL)
- {
- /* We got lucky. Just return the thing BEFORE performing any I/O. */
- /* ### validate SMODE against how we opened wcroot->sdb? and against
- ### DB->mode? (will we record per-dir mode?) */
-
- /* ### for most callers, we could pass NULL for result_pool. */
- *local_relpath = compute_pdh_relpath(*pdh, result_pool);
+ const insert_base_baton_t *pibb = baton;
+ svn_sqlite__stmt_t *stmt;
- return SVN_NO_ERROR;
- }
+ /* ### we can't handle this right now */
+ SVN_ERR_ASSERT(pibb->conflict == NULL);
- /* ### at some point in the future, we may need to find a way to get
- ### rid of this stat() call. it is going to happen for EVERY call
- ### into wc_db which references a file. calls for directories could
- ### get an early-exit in the hash lookup just above. */
- SVN_ERR(svn_io_check_special_path(local_abspath, &kind,
- &special /* unused */, scratch_pool));
- if (kind != svn_node_dir)
- {
- /* If the node specified by the path is NOT present, then it cannot
- possibly be a directory containing ".svn/wc.db".
-
- If it is a file, then it cannot contain ".svn/wc.db".
-
- For both of these cases, strip the basename off of the path and
- move up one level. Keep record of what we strip, though, since
- we'll need it later to construct local_relpath. */
- svn_dirent_split(local_abspath, &local_abspath, &build_relpath,
- scratch_pool);
-
- /* ### if *pdh != NULL (from further above), then there is (quite
- ### probably) a bogus value in the DIR_DATA hash table. maybe
- ### clear it out? but what if there is an access baton? */
-
- /* Is this directory in our hash? */
- *pdh = apr_hash_get(db->dir_data, local_abspath, APR_HASH_KEY_STRING);
- if (*pdh != NULL && (*pdh)->wcroot != NULL)
- {
- const char *dir_relpath;
-
- /* Stashed directory's local_relpath + basename. */
- dir_relpath = compute_pdh_relpath(*pdh, NULL);
- *local_relpath = svn_relpath_join(dir_relpath,
- build_relpath,
- result_pool);
- return SVN_NO_ERROR;
- }
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pibb->wc_id, pibb->local_relpath));
- /* If the requested path is not on the disk, then we don't know how
- many ancestors need to be scanned until we start hitting content
- on the disk. Set ALWAYS_CHECK to keep looking for .svn/entries
- rather than bailing out after the first check. */
- if (kind == svn_node_none)
- always_check = TRUE;
- }
- else
+ if (TRUE /* maybe_bind_repos() */)
{
- /* Start the local_relpath empty. If *this* directory contains the
- wc.db, then relpath will be the empty string. */
- build_relpath = "";
-
- /* It is possible that LOCAL_ABSPATH was *intended* to be a file,
- but we just found a directory in its place. After we build
- the PDH, then we'll examine the parent to see how it describes
- this particular path.
-
- ### this is only possible with per-dir wc.db databases. */
- obstruction_possible = TRUE;
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 3, pibb->repos_id));
+ SVN_ERR(svn_sqlite__bind_text(stmt, 4, pibb->repos_relpath));
}
- /* LOCAL_ABSPATH refers to a directory at this point. The PDH corresponding
- to that directory is what we need to return. At this point, we've
- determined that a PDH with a discovered WCROOT is NOT in the DB's hash
- table of wcdirs. Let's fill in an existing one, or create one. Then
- go figure out where the WCROOT is. */
+ /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
+ bind the appropriate parent_relpath. */
+ if (*pibb->local_relpath != '\0')
+ SVN_ERR(svn_sqlite__bind_text(stmt, 5,
+ svn_relpath_dirname(pibb->local_relpath,
+ scratch_pool)));
- if (*pdh == NULL)
- {
- *pdh = apr_pcalloc(db->state_pool, sizeof(**pdh));
- (*pdh)->local_abspath = apr_pstrdup(db->state_pool, local_abspath);
- }
- else
- {
- /* The PDH should have been built correctly (so far). */
- SVN_ERR_ASSERT(strcmp((*pdh)->local_abspath, local_abspath) == 0);
- }
-
- /* Assume that LOCAL_ABSPATH is a directory, and look for the SQLite
- database in the right place. If we find it... great! If not, then
- peel off some components, and try again. */
-
- while (TRUE)
- {
- svn_error_t *err;
-
- err = open_db(&sdb, local_abspath, SDB_FILE, smode,
- db->state_pool, scratch_pool);
- if (err == NULL)
- break;
- if (err->apr_err != SVN_ERR_SQLITE_ERROR
- && !APR_STATUS_IS_ENOENT(err->apr_err))
- return svn_error_return(err);
- svn_error_clear(err);
-
- /* If we have not moved upwards, then check for a wc-1 working copy.
- Since wc-1 has a .svn in every directory, and we didn't find one
- in the original directory, then we aren't looking at a wc-1.
-
- If the original path is not present, then we have to check on every
- iteration. The content may be the immediate parent, or possibly
- five ancetors higher. We don't test for directory presence (just
- for the presence of subdirs/files), so we don't know when we can
- stop checking ... so just check always. */
- if (!moved_upwards || always_check)
- {
- SVN_ERR(get_old_version(&wc_format, local_abspath, scratch_pool));
- if (wc_format != 0)
- break;
- }
-
- /* We couldn't open the SDB within the specified directory, so
- move up one more directory. */
- if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
- {
- /* Hit the root without finding a wcroot. */
- return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
- _("'%s' is not a working copy"),
- svn_dirent_local_style(original_abspath,
- scratch_pool));
- }
-
- local_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-
- moved_upwards = TRUE;
-
- /* An obstruction is no longer possible.
-
- Example: we were given "/some/file" and "file" turned out to be
- a directory. We did not find an SDB at "/some/file/.svn/wc.db",
- so we are now going to look at "/some/.svn/wc.db". That SDB will
- contain the correct information for "file".
+ SVN_ERR(svn_sqlite__bind_token(stmt, 6, presence_map, pibb->status));
+ SVN_ERR(svn_sqlite__bind_token(stmt, 7, kind_map, pibb->kind));
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 8, pibb->revision));
- ### obstruction is only possible with per-dir wc.db databases. */
- obstruction_possible = FALSE;
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 9, pibb->props, scratch_pool));
- /* Is the parent directory recorded in our hash? */
- found_pdh = apr_hash_get(db->dir_data,
- local_abspath, APR_HASH_KEY_STRING);
- if (found_pdh != NULL)
- {
- if (found_pdh->wcroot != NULL)
- break;
- found_pdh = NULL;
- }
- }
+ if (SVN_IS_VALID_REVNUM(pibb->changed_rev))
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 10, pibb->changed_rev));
+ if (pibb->changed_date)
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 11, pibb->changed_date));
+ if (pibb->changed_author)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 12, pibb->changed_author));
- if (found_pdh != NULL)
+ if (pibb->kind == svn_wc__db_kind_dir)
{
- /* We found a PDH with data in it. We can now construct the child
- from this, rather than continuing to scan upwards. */
-
- /* The subdirectory uses the same WCROOT as the parent dir. */
- (*pdh)->wcroot = found_pdh->wcroot;
+ SVN_ERR(svn_sqlite__bind_text(stmt, 13, svn_depth_to_word(pibb->depth)));
}
- else if (wc_format == 0)
+ else if (pibb->kind == svn_wc__db_kind_file)
{
- /* We finally found the database. Construct the PDH record. */
-
- apr_int64_t wc_id;
- svn_error_t *err;
-
- err = fetch_wc_id(&wc_id, sdb, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_WC_CORRUPT)
- return svn_error_quick_wrap(
- err, apr_psprintf(scratch_pool,
- _("Missing a row in WCROOT for '%s'."),
- svn_dirent_local_style(original_abspath,
- scratch_pool)));
- return svn_error_return(err);
- }
-
- /* WCROOT.local_abspath may be NULL when the database is stored
- inside the wcroot, but we know the abspath is this directory
- (ie. where we found it). */
-
- SVN_ERR(create_wcroot(&(*pdh)->wcroot,
- apr_pstrdup(db->state_pool, local_abspath),
- sdb, wc_id, FORMAT_FROM_SDB,
- db->auto_upgrade, db->enforce_empty_wq,
- db->state_pool, scratch_pool));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum,
+ scratch_pool));
+ if (pibb->translated_size != SVN_INVALID_FILESIZE)
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 15, pibb->translated_size));
}
- else
+ else if (pibb->kind == svn_wc__db_kind_symlink)
{
- /* We found a wc-1 working copy directory. */
- SVN_ERR(create_wcroot(&(*pdh)->wcroot,
- apr_pstrdup(db->state_pool, local_abspath),
- NULL, UNKNOWN_WC_ID, wc_format,
- db->auto_upgrade, db->enforce_empty_wq,
- db->state_pool, scratch_pool));
-
- /* Don't test for a directory obstructing a versioned file. The wc-1
- code can manage that itself. */
- obstruction_possible = FALSE;
+ /* Note: incomplete nodes may have a NULL target. */
+ if (pibb->target)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 16, pibb->target));
}
- {
- const char *dir_relpath;
-
- /* The subdirectory's relpath is easily computed relative to the
- wcroot that we just found. */
- dir_relpath = compute_pdh_relpath(*pdh, NULL);
-
- /* And the result local_relpath may include a filename. */
- *local_relpath = svn_relpath_join(dir_relpath, build_relpath, result_pool);
- }
-
- /* Check to see if this (versioned) directory is obstructing what should
- be a file in the parent directory.
+ SVN_ERR(svn_sqlite__insert(NULL, stmt));
- ### obstruction is only possible with per-dir wc.db databases. */
- if (obstruction_possible)
+ if (pibb->kind == svn_wc__db_kind_dir && pibb->children)
{
- const char *parent_dir;
- svn_wc__db_pdh_t *parent_pdh;
-
- /* We should NOT have moved up a directory. */
- assert(!moved_upwards);
-
- /* Get/make a PDH for the parent. */
- parent_dir = svn_dirent_dirname(local_abspath, scratch_pool);
- parent_pdh = apr_hash_get(db->dir_data, parent_dir, APR_HASH_KEY_STRING);
- if (parent_pdh == NULL || parent_pdh->wcroot == NULL)
- {
- svn_error_t *err = open_db(&sdb, parent_dir, SDB_FILE, smode,
- db->state_pool, scratch_pool);
- if (err)
- {
- if (err->apr_err != SVN_ERR_SQLITE_ERROR
- && !APR_STATUS_IS_ENOENT(err->apr_err))
- return svn_error_return(err);
- svn_error_clear(err);
-
- /* No parent, so we're at a wcroot apparently. An obstruction
- is (therefore) not possible. */
- parent_pdh = NULL;
- }
- else
- {
- /* ### construct this according to per-dir semantics. */
- if (parent_pdh == NULL)
- {
- parent_pdh = apr_pcalloc(db->state_pool,
- sizeof(*parent_pdh));
- parent_pdh->local_abspath = apr_pstrdup(db->state_pool,
- parent_dir);
- }
- else
- {
- /* The PDH should have been built correctly (so far). */
- SVN_ERR_ASSERT(strcmp(parent_pdh->local_abspath,
- parent_dir) == 0);
- }
-
- SVN_ERR(create_wcroot(&parent_pdh->wcroot,
- parent_pdh->local_abspath,
- sdb,
- 1 /* ### hack. */,
- FORMAT_FROM_SDB,
- db->auto_upgrade, db->enforce_empty_wq,
- db->state_pool, scratch_pool));
-
- apr_hash_set(db->dir_data,
- parent_pdh->local_abspath, APR_HASH_KEY_STRING,
- parent_pdh);
+ int i;
- (*pdh)->parent = parent_pdh;
- }
- }
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_INSERT_BASE_NODE_INCOMPLETE));
- if (parent_pdh)
+ for (i = pibb->children->nelts; i--; )
{
- const char *lookfor_relpath = svn_dirent_basename(local_abspath,
- scratch_pool);
+ const char *name = APR_ARRAY_IDX(pibb->children, i, const char *);
- /* Was there supposed to be a file sitting here? */
- SVN_ERR(determine_obstructed_file(&(*pdh)->obstructed_file,
- parent_pdh->wcroot,
- lookfor_relpath,
- scratch_pool));
-
- /* If we determined that a file was supposed to be at the
- LOCAL_ABSPATH requested, then return the PDH and LOCAL_RELPATH
- which describes that file. */
- if ((*pdh)->obstructed_file)
- {
- *pdh = parent_pdh;
- *local_relpath = apr_pstrdup(result_pool, lookfor_relpath);
- return SVN_NO_ERROR;
- }
+ SVN_ERR(svn_sqlite__bindf(stmt, "issi",
+ pibb->wc_id,
+ svn_dirent_join(pibb->local_relpath,
+ name,
+ scratch_pool),
+ pibb->local_relpath,
+ (apr_int64_t)pibb->revision));
+ SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
}
- /* The PDH is complete. Stash it into DB. */
- apr_hash_set(db->dir_data,
- (*pdh)->local_abspath, APR_HASH_KEY_STRING,
- *pdh);
-
- /* Did we traverse up to parent directories? */
- if (!moved_upwards)
- {
- /* We did NOT move to a parent of the original requested directory.
- We've constructed and filled in a PDH for the request, so we
- are done. */
- return SVN_NO_ERROR;
- }
-
- /* The PDH that we just built was for the LOCAL_ABSPATH originally passed
- into this function. We stepped *at least* one directory above that.
- We should now create PDH records for each parent directory that does
- not (yet) have one. */
-
- child_pdh = *pdh;
-
- do
- {
- const char *parent_dir = svn_dirent_dirname(child_pdh->local_abspath,
- scratch_pool);
- svn_wc__db_pdh_t *parent_pdh;
-
- parent_pdh = apr_hash_get(db->dir_data, parent_dir, APR_HASH_KEY_STRING);
- if (parent_pdh == NULL)
- {
- parent_pdh = apr_pcalloc(db->state_pool, sizeof(*parent_pdh));
- parent_pdh->local_abspath = apr_pstrdup(db->state_pool, parent_dir);
-
- /* All the PDHs have the same wcroot. */
- parent_pdh->wcroot = (*pdh)->wcroot;
-
- apr_hash_set(db->dir_data,
- parent_pdh->local_abspath, APR_HASH_KEY_STRING,
- parent_pdh);
- }
- else if (parent_pdh->wcroot == NULL)
- {
- parent_pdh->wcroot = (*pdh)->wcroot;
- }
-
- /* Point the child PDH at this (new) parent PDH. This will allow for
- easy traversals without path munging. */
- child_pdh->parent = parent_pdh;
- child_pdh = parent_pdh;
-
- /* Loop if we haven't reached the PDH we found, or the abspath
- where we terminated the search (when we found wc.db). Note that
- if we never located a PDH in our ancestry, then FOUND_PDH will
- be NULL and that portion of the test will always be TRUE. */
- }
- while (child_pdh != found_pdh
- && strcmp(child_pdh->local_abspath, local_abspath) != 0);
+ SVN_ERR(add_work_items(sdb, pibb->work_items, scratch_pool));
return SVN_NO_ERROR;
}
-/* 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)
+static void
+blank_iwb(insert_working_baton_t *piwb)
{
- svn_wc__db_pdh_t *pdh;
- const char *local_relpath;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ memset(piwb, 0, sizeof(*piwb));
+ piwb->changed_rev = SVN_INVALID_REVNUM;
+ piwb->depth = svn_depth_infinity;
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_PDH(pdh);
-
- SVN_ERR(svn_sqlite__get_statement(stmt, pdh->wcroot->sdb, stmt_idx));
- SVN_ERR(svn_sqlite__bindf(*stmt, "is", pdh->wcroot->wc_id, local_relpath));
-
- return SVN_NO_ERROR;
+ /* ORIGINAL_REPOS_ID and ORIGINAL_REVNUM could use some kind of "nil"
+ value, but... meh. We'll avoid them if ORIGINAL_REPOS_RELPATH==NULL. */
}
/* */
static svn_error_t *
-navigate_to_parent(svn_wc__db_pdh_t **parent_pdh,
- svn_wc__db_t *db,
- svn_wc__db_pdh_t *child_pdh,
- svn_sqlite__mode_t smode,
- apr_pool_t *scratch_pool)
+insert_working_node(void *baton,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
{
- const char *parent_abspath;
- const char *local_relpath;
-
- if ((*parent_pdh = child_pdh->parent) != NULL
- && (*parent_pdh)->wcroot != NULL)
- return SVN_NO_ERROR;
-
- parent_abspath = svn_dirent_dirname(child_pdh->local_abspath, scratch_pool);
- SVN_ERR(parse_local_abspath(parent_pdh, &local_relpath, db,
- parent_abspath, smode,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_PDH(*parent_pdh);
-
- child_pdh->parent = *parent_pdh;
-
- return SVN_NO_ERROR;
-}
-
+ const insert_working_baton_t *piwb = baton;
+ const char *parent_relpath;
+ svn_sqlite__stmt_t *stmt;
-/* 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 *
-create_repos_id(apr_int64_t *repos_id,
- const char *repos_root_url,
- const char *repos_uuid,
- svn_sqlite__db_t *sdb,
- apr_pool_t *scratch_pool)
-{
- svn_sqlite__stmt_t *get_stmt;
- svn_sqlite__stmt_t *insert_stmt;
- svn_boolean_t have_row;
+ /* We cannot insert a WORKING_NODE row at the wcroot. */
+ /* ### actually, with per-dir DB, we can... */
+#if 0
+ SVN_ERR_ASSERT(*piwb->local_relpath != '\0');
+#endif
+ if (*piwb->local_relpath == '\0')
+ parent_relpath = NULL;
+ else
+ parent_relpath = svn_relpath_dirname(piwb->local_relpath, scratch_pool);
- SVN_ERR(svn_sqlite__get_statement(&get_stmt, sdb, STMT_SELECT_REPOSITORY));
- SVN_ERR(svn_sqlite__bindf(get_stmt, "s", repos_root_url));
- SVN_ERR(svn_sqlite__step(&have_row, get_stmt));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isstt",
+ piwb->wc_id, piwb->local_relpath,
+ parent_relpath,
+ presence_map, piwb->presence,
+ kind_map, piwb->kind));
- if (have_row)
+ if (piwb->original_repos_relpath != NULL)
{
- *repos_id = svn_sqlite__column_int64(get_stmt, 0);
- return svn_error_return(svn_sqlite__reset(get_stmt));
- }
- SVN_ERR(svn_sqlite__reset(get_stmt));
-
- /* NOTE: strictly speaking, there is a race condition between the
- above query and the insertion below. We're simply going to ignore
- that, as it means two processes are *modifying* the working copy
- at the same time, *and* new repositores are becoming visible.
- This is rare enough, let alone the miniscule chance of hitting
- this race condition. Further, simply failing out will leave the
- database in a consistent state, and the user can just re-run the
- failed operation. */
-
- SVN_ERR(svn_sqlite__get_statement(&insert_stmt, sdb,
- STMT_INSERT_REPOSITORY));
- SVN_ERR(svn_sqlite__bindf(insert_stmt, "ss", repos_root_url, repos_uuid));
- return svn_error_return(svn_sqlite__insert(repos_id, insert_stmt));
-}
-
-
-/* */
-static svn_error_t *
-insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
-{
- const insert_base_baton_t *pibb = baton;
- svn_sqlite__stmt_t *stmt;
+ SVN_ERR_ASSERT(piwb->original_repos_id > 0);
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(piwb->original_revnum));
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_BASE_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", pibb->wc_id, pibb->local_relpath));
-
- if (TRUE /* maybe_bind_repos() */)
- {
- SVN_ERR(svn_sqlite__bind_int64(stmt, 3, pibb->repos_id));
- SVN_ERR(svn_sqlite__bind_text(stmt, 4, pibb->repos_relpath));
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 6, piwb->original_repos_id));
+ SVN_ERR(svn_sqlite__bind_text(stmt, 7, piwb->original_repos_relpath));
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 8, piwb->original_revnum));
}
- /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
- bind the appropriate parent_relpath. */
- if (*pibb->local_relpath != '\0')
- SVN_ERR(svn_sqlite__bind_text(stmt, 5,
- svn_dirent_dirname(pibb->local_relpath,
- scratch_pool)));
+ /* Do not bind 'moved_here' (9), nor 'moved_to' (10). */
- SVN_ERR(svn_sqlite__bind_token(stmt, 6, presence_map, pibb->status));
- SVN_ERR(svn_sqlite__bind_token(stmt, 7, kind_map, pibb->kind));
- SVN_ERR(svn_sqlite__bind_int64(stmt, 8, pibb->revision));
+ /* 'checksum' (11) is bound below. */
- SVN_ERR(svn_sqlite__bind_properties(stmt, 9, pibb->props, scratch_pool));
+ /* Do not bind 'translated_size' (12). */
- if (SVN_IS_VALID_REVNUM(pibb->changed_rev))
- SVN_ERR(svn_sqlite__bind_int64(stmt, 10, pibb->changed_rev));
- if (pibb->changed_date)
- SVN_ERR(svn_sqlite__bind_int64(stmt, 11, pibb->changed_date));
- if (pibb->changed_author)
- SVN_ERR(svn_sqlite__bind_text(stmt, 12, pibb->changed_author));
+ if (SVN_IS_VALID_REVNUM(piwb->changed_rev))
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 13, piwb->changed_rev));
+ if (piwb->changed_date)
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 14, piwb->changed_date));
+ if (piwb->changed_author)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 15, piwb->changed_author));
- if (pibb->kind == svn_wc__db_kind_dir)
+ if (piwb->kind == svn_wc__db_kind_dir)
{
- SVN_ERR(svn_sqlite__bind_text(stmt, 13, svn_depth_to_word(pibb->depth)));
+ SVN_ERR(svn_sqlite__bind_text(stmt, 16, svn_depth_to_word(piwb->depth)));
}
- else if (pibb->kind == svn_wc__db_kind_file)
+ else if (piwb->kind == svn_wc__db_kind_file)
{
- SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum,
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 11, piwb->checksum,
scratch_pool));
- if (pibb->translated_size != SVN_INVALID_FILESIZE)
- SVN_ERR(svn_sqlite__bind_int64(stmt, 15, pibb->translated_size));
}
- else if (pibb->kind == svn_wc__db_kind_symlink)
+ else if (piwb->kind == svn_wc__db_kind_symlink)
{
- if (pibb->target)
- SVN_ERR(svn_sqlite__bind_text(stmt, 16, pibb->target));
+ SVN_ERR_ASSERT(piwb->target != NULL);
+
+ SVN_ERR(svn_sqlite__bind_text(stmt, 20, piwb->target));
}
+ /* Do not bind 'last_mod_time' (17). */
+
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 18, piwb->props, scratch_pool));
+
+ /* Do not bind 'keep_local' (19). */
+ /* 'symlink_target' (20) is bound above. */
+
SVN_ERR(svn_sqlite__insert(NULL, stmt));
- if (pibb->kind == svn_wc__db_kind_dir && pibb->children)
+ if (piwb->kind == svn_wc__db_kind_dir && piwb->children)
{
int i;
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
- STMT_INSERT_BASE_NODE_INCOMPLETE));
+ STMT_INSERT_WORKING_NODE_INCOMPLETE));
- for (i = pibb->children->nelts; i--; )
+ for (i = piwb->children->nelts; i--; )
{
- const char *name = APR_ARRAY_IDX(pibb->children, i, const char *);
+ const char *name = APR_ARRAY_IDX(piwb->children, i, const char *);
- SVN_ERR(svn_sqlite__bindf(stmt, "issi",
- pibb->wc_id,
- svn_dirent_join(pibb->local_relpath,
- name,
- scratch_pool),
- pibb->local_relpath,
- (apr_int64_t)pibb->revision));
+ SVN_ERR(svn_sqlite__bindf(stmt, "iss",
+ piwb->wc_id,
+ svn_relpath_join(piwb->local_relpath,
+ name,
+ scratch_pool),
+ piwb->local_relpath));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
}
+ SVN_ERR(add_work_items(sdb, piwb->work_items, scratch_pool));
+
return SVN_NO_ERROR;
}
@@ -1430,8 +814,8 @@ gather_children(const apr_array_header_t
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readonly,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readonly,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
@@ -1510,9 +894,8 @@ add_work_items(svn_sqlite__db_t *sdb,
/* Should have a list. */
SVN_ERR_ASSERT(!skel->is_atom);
- /* If SKEL has an atom as its first child, then this is a work item
- (and that atom is one of the OP_* values). */
- if (skel->children->is_atom)
+ /* Is the list a single work item? Or a list of work items? */
+ if (SVN_WC__SINGLE_WORK_ITEM(skel))
return svn_error_return(add_single_work_item(sdb, skel, scratch_pool));
/* SKEL is a list-of-lists, aka list of work items. */
@@ -1586,9 +969,9 @@ create_db(svn_sqlite__db_t **sdb,
{
svn_sqlite__stmt_t *stmt;
- SVN_ERR(open_db(sdb, dir_abspath, sdb_fname,
- svn_sqlite__mode_rwcreate,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_util_open_db(sdb, dir_abspath, sdb_fname,
+ svn_sqlite__mode_rwcreate, result_pool,
+ scratch_pool));
/* Create the database's schema. */
SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_SCHEMA));
@@ -1607,60 +990,6 @@ create_db(svn_sqlite__db_t **sdb,
svn_error_t *
-svn_wc__db_open(svn_wc__db_t **db,
- svn_wc__db_openmode_t mode,
- svn_config_t *config,
- svn_boolean_t auto_upgrade,
- svn_boolean_t enforce_empty_wq,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- *db = apr_pcalloc(result_pool, sizeof(**db));
- (*db)->mode = mode;
- (*db)->config = config;
- (*db)->auto_upgrade = auto_upgrade;
- (*db)->enforce_empty_wq = enforce_empty_wq;
- (*db)->dir_data = apr_hash_make(result_pool);
- (*db)->state_pool = result_pool;
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_close(svn_wc__db_t *db)
-{
- apr_pool_t *scratch_pool = db->state_pool;
- apr_hash_t *roots = apr_hash_make(scratch_pool);
- apr_hash_index_t *hi;
-
- /* Collect all the unique WCROOT structures, and empty out DIR_DATA. */
- for (hi = apr_hash_first(scratch_pool, db->dir_data);
- hi;
- hi = apr_hash_next(hi))
- {
- const void *key;
- apr_ssize_t klen;
- void *val;
- svn_wc__db_pdh_t *pdh;
-
- apr_hash_this(hi, &key, &klen, &val);
- pdh = val;
-
- if (pdh->wcroot && pdh->wcroot->sdb)
- apr_hash_set(roots, pdh->wcroot->abspath, APR_HASH_KEY_STRING,
- pdh->wcroot);
-
- apr_hash_set(db->dir_data, key, klen, NULL);
- }
-
- /* Run the cleanup for each WCROOT. */
- return svn_error_return(close_many_wcroots(roots, db->state_pool,
- scratch_pool));
-}
-
-
-svn_error_t *
svn_wc__db_init(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
@@ -1694,7 +1023,7 @@ svn_wc__db_init(svn_wc__db_t *db,
pdh->local_abspath = apr_pstrdup(db->state_pool, local_abspath);
/* Create the WCROOT for this directory. */
- SVN_ERR(create_wcroot(&pdh->wcroot, pdh->local_abspath,
+ SVN_ERR(svn_wc__db_pdh_create_wcroot(&pdh->wcroot, pdh->local_abspath,
sdb, wc_id, FORMAT_FROM_SDB,
FALSE /* auto-upgrade */,
FALSE /* enforce_empty_wq */,
@@ -1703,6 +1032,8 @@ svn_wc__db_init(svn_wc__db_t *db,
/* The PDH is complete. Stash it into DB. */
apr_hash_set(db->dir_data, pdh->local_abspath, APR_HASH_KEY_STRING, pdh);
+ blank_ibb(&ibb);
+
if (initial_rev > 0)
ibb.status = svn_wc__db_status_incomplete;
else
@@ -1714,19 +1045,64 @@ svn_wc__db_init(svn_wc__db_t *db,
ibb.repos_relpath = repos_relpath;
ibb.revision = initial_rev;
- ibb.props = NULL;
- ibb.changed_rev = SVN_INVALID_REVNUM;
- ibb.changed_date = 0;
- ibb.changed_author = NULL;
-
+ /* ### what about the children? */
ibb.children = NULL;
ibb.depth = depth;
+ /* ### no children, conflicts, or work items to install in a txn... */
+
return svn_error_return(insert_base_node(&ibb, sdb, scratch_pool));
}
svn_error_t *
+svn_wc__db_to_relpath(const char **local_relpath,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, local_relpath, db,
+ local_abspath, svn_sqlite__mode_readonly,
+ result_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_from_relpath(const char **local_abspath,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const char *local_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *unused_relpath;
+
+#if 0
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(local_abspath));
+#endif
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &unused_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ *local_abspath = svn_dirent_join(pdh->wcroot->abspath,
+ local_relpath,
+ result_pool);
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
svn_wc__db_base_add_directory(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
@@ -1739,6 +1115,8 @@ svn_wc__db_base_add_directory(svn_wc__db
const char *changed_author,
const apr_array_header_t *children,
svn_depth_t depth,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
@@ -1753,16 +1131,20 @@ svn_wc__db_base_add_directory(svn_wc__db
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
+#if 0
SVN_ERR_ASSERT(children != NULL);
+#endif
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid,
pdh->wcroot->sdb, scratch_pool));
+ blank_ibb(&ibb);
+
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_wc__db_kind_dir;
ibb.wc_id = pdh->wcroot->wc_id;
@@ -1779,13 +1161,20 @@ svn_wc__db_base_add_directory(svn_wc__db
ibb.children = children;
ibb.depth = depth;
+ ibb.conflict = conflict;
+ ibb.work_items = work_items;
+
/* Insert the directory and all its children transactionally.
Note: old children can stick around, even if they are no longer present
in this directory's revision. */
- return svn_sqlite__with_transaction(pdh->wcroot->sdb,
- insert_base_node, &ibb,
- scratch_pool);
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+ insert_base_node, &ibb,
+ scratch_pool));
+
+ /* ### worry about flushing child subdirs? */
+ flush_entries(pdh);
+ return SVN_NO_ERROR;
}
@@ -1802,6 +1191,8 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
const char *changed_author,
const svn_checksum_t *checksum,
svn_filesize_t translated_size,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
@@ -1818,14 +1209,16 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
SVN_ERR_ASSERT(checksum != NULL);
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid,
pdh->wcroot->sdb, scratch_pool));
+ blank_ibb(&ibb);
+
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_wc__db_kind_file;
ibb.wc_id = pdh->wcroot->wc_id;
@@ -1842,11 +1235,19 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
ibb.checksum = checksum;
ibb.translated_size = translated_size;
+ ibb.conflict = conflict;
+ ibb.work_items = work_items;
+
/* ### hmm. if this used to be a directory, we should remove children.
### or maybe let caller deal with that, if there is a possibility
### of a node kind change (rather than eat an extra lookup here). */
- return insert_base_node(&ibb, pdh->wcroot->sdb, scratch_pool);
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+ insert_base_node, &ibb,
+ scratch_pool));
+
+ flush_entries(pdh);
+ return SVN_NO_ERROR;
}
@@ -1862,6 +1263,8 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
apr_time_t changed_date,
const char *changed_author,
const char *target,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
@@ -1878,14 +1281,16 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
SVN_ERR_ASSERT(target != NULL);
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid,
pdh->wcroot->sdb, scratch_pool));
+ blank_ibb(&ibb);
+
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_wc__db_kind_symlink;
ibb.wc_id = pdh->wcroot->wc_id;
@@ -1901,11 +1306,19 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
ibb.target = target;
+ ibb.conflict = conflict;
+ ibb.work_items = work_items;
+
/* ### hmm. if this used to be a directory, we should remove children.
### or maybe let caller deal with that, if there is a possibility
### of a node kind change (rather than eat an extra lookup here). */
- return insert_base_node(&ibb, pdh->wcroot->sdb, scratch_pool);
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+ insert_base_node, &ibb,
+ scratch_pool));
+
+ flush_entries(pdh);
+ return SVN_NO_ERROR;
}
@@ -1918,6 +1331,8 @@ svn_wc__db_base_add_absent_node(svn_wc__
svn_revnum_t revision,
svn_wc__db_kind_t kind,
svn_wc__db_status_t status,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
@@ -1934,14 +1349,16 @@ svn_wc__db_base_add_absent_node(svn_wc__
|| status == svn_wc__db_status_excluded
|| status == svn_wc__db_status_not_present);
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid,
pdh->wcroot->sdb, scratch_pool));
+ blank_ibb(&ibb);
+
ibb.status = status;
ibb.kind = kind;
ibb.wc_id = pdh->wcroot->wc_id;
@@ -1950,11 +1367,6 @@ svn_wc__db_base_add_absent_node(svn_wc__
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
- ibb.props = NULL;
- ibb.changed_rev = SVN_INVALID_REVNUM;
- ibb.changed_date = 0;
- ibb.changed_author = NULL;
-
/* Depending upon KIND, any of these might get used. */
ibb.children = NULL;
ibb.depth = svn_depth_unknown;
@@ -1962,13 +1374,18 @@ svn_wc__db_base_add_absent_node(svn_wc__
ibb.translated_size = SVN_INVALID_FILESIZE;
ibb.target = NULL;
+ ibb.conflict = conflict;
+ ibb.work_items = work_items;
+
/* ### hmm. if this used to be a directory, we should remove children.
### or maybe let caller deal with that, if there is a possibility
### of a node kind change (rather than eat an extra lookup here). */
- SVN_ERR(insert_base_node(&ibb, pdh->wcroot->sdb, scratch_pool));
- flush_entries(pdh);
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+ insert_base_node, &ibb,
+ scratch_pool));
+ flush_entries(pdh);
return SVN_NO_ERROR;
}
@@ -2001,8 +1418,8 @@ svn_wc__db_temp_base_add_subdir(svn_wc__
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
@@ -2025,7 +1442,10 @@ svn_wc__db_temp_base_add_subdir(svn_wc__
ibb.children = NULL;
ibb.depth = depth;
- return insert_base_node(&ibb, pdh->wcroot->sdb, scratch_pool);
+ /* ### no children, conflicts, or work items to install in a txn... */
+
+ return svn_error_return(insert_base_node(&ibb, pdh->wcroot->sdb,
+ scratch_pool));
}
@@ -2040,8 +1460,8 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
@@ -2086,8 +1506,8 @@ svn_wc__db_base_get_info(svn_wc__db_stat
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readonly,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readonly,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
@@ -2244,70 +1664,6 @@ svn_wc__db_base_get_info(svn_wc__db_stat
}
-/* A WORKING version of svn_wc__db_base_get_info, stripped down to
- just the status column.
-
- ### This function should not exist! What I really want is presence
- ### not status, and so it's a mistake to return an
- ### svn_wc__db_status_t here as it doesn't have quite the same
- ### meaning as status returned by other functions. I think I need
- ### to abandon this function and work out how to decode status back
- ### into presence :(
-*/
-static svn_error_t *
-db_working_get_status(svn_wc__db_status_t *status,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_pdh_t *pdh;
- const char *local_relpath;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- svn_error_t *err = SVN_NO_ERROR;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readonly,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_PDH(pdh);
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
-
- if (have_row)
- {
- svn_wc__db_kind_t node_kind = svn_sqlite__column_token(stmt, 1,
- kind_map);
-
- *status = svn_sqlite__column_token(stmt, 0, presence_map);
-
- if (node_kind == svn_wc__db_kind_subdir
- && *status == svn_wc__db_status_normal)
- {
- /* We're looking at the subdir record in the *parent* directory,
- which implies per-dir .svn subdirs. We should be looking
- at the subdir itself; therefore, it is missing or obstructed
- in some way. Inform the caller. */
- *status = svn_wc__db_status_obstructed;
- }
- }
- else
- {
- err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
- _("The node '%s' was not found."),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
- }
-
-
- return svn_error_compose_create(err, svn_sqlite__reset(stmt));
-}
-
-
svn_error_t *
svn_wc__db_base_get_prop(const svn_string_t **propval,
svn_wc__db_t *db,
@@ -2414,13 +1770,11 @@ svn_wc__db_base_get_dav_cache(apr_hash_t
STMT_SELECT_BASE_DAV_CACHE, scratch_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
- {
- SVN_ERR(svn_sqlite__reset(stmt));
- return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
- _("The node '%s' was not found."),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
- }
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
+ svn_sqlite__reset(stmt),
+ _("The node '%s' was not found."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
SVN_ERR(svn_sqlite__column_properties(props, stmt, 0, result_pool,
scratch_pool));
@@ -2429,38 +1783,76 @@ svn_wc__db_base_get_dav_cache(apr_hash_t
svn_error_t *
+svn_wc__db_pristine_get_path(const char **pristine_abspath,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+
+ SVN_ERR_ASSERT(pristine_abspath != NULL);
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error
+ * if the pristine text is not in the store. */
+ if (sha1_checksum->kind != svn_checksum_sha1)
+ SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
+ sha1_checksum,
+ scratch_pool, scratch_pool));
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath,
+ db, wri_abspath,
+ svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ /* ### should we look in the PRISTINE table for anything? */
+
+ SVN_ERR(get_pristine_fname(pristine_abspath, pdh, sha1_checksum,
+ FALSE /* create_subdir */,
+ scratch_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
svn_wc__db_pristine_read(svn_stream_t **contents,
svn_wc__db_t *db,
const char *wri_abspath,
- const svn_checksum_t *checksum,
+ const svn_checksum_t *sha1_checksum,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
const char *local_relpath;
const char *pristine_abspath;
- svn_error_t *err;
SVN_ERR_ASSERT(contents != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR_ASSERT(checksum != NULL);
-
- VERIFY_CHECKSUM_KIND(checksum);
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error
+ * if the pristine text is not in the store. */
+ if (sha1_checksum->kind != svn_checksum_sha1)
+ SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
+ sha1_checksum,
+ scratch_pool, scratch_pool));
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, wri_abspath,
- svn_sqlite__mode_readonly,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
/* ### should we look in the PRISTINE table for anything? */
- err = get_pristine_fname(&pristine_abspath, pdh, checksum,
-#ifndef SVN__SKIP_SUBDIR
- FALSE /* create_subdir */,
-#endif
- scratch_pool, scratch_pool);
- SVN_ERR(err);
-
+ SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
+ FALSE /* create_subdir */,
+ scratch_pool, scratch_pool));
return svn_error_return(svn_stream_open_readonly(
contents, pristine_abspath,
result_pool, scratch_pool));
@@ -2480,8 +1872,8 @@ svn_wc__db_pristine_get_tempdir(const ch
SVN_ERR_ASSERT(temp_dir_abspath != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, wri_abspath,
- svn_sqlite__mode_readonly,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
@@ -2507,13 +1899,12 @@ svn_wc__db_pristine_install(svn_wc__db_t
const char *pristine_abspath;
apr_finfo_t finfo;
svn_sqlite__stmt_t *stmt;
- svn_error_t *err;
SVN_ERR_ASSERT(svn_dirent_is_absolute(tempfile_abspath));
SVN_ERR_ASSERT(sha1_checksum != NULL);
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
SVN_ERR_ASSERT(md5_checksum != NULL);
-
- VERIFY_CHECKSUM_KIND(checksum);
+ SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5);
/* ### this logic assumes that TEMPFILE_ABSPATH follows this pattern:
### WCROOT_ABSPATH/COMPONENT/TEMPFNAME
@@ -2523,17 +1914,14 @@ svn_wc__db_pristine_install(svn_wc__db_t
scratch_pool),
scratch_pool);
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, wri_abspath,
- svn_sqlite__mode_readonly,
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- err = get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
-#ifndef SVN__SKIP_SUBDIR
- TRUE /* create_subdir */,
-#endif
- scratch_pool, scratch_pool);
- SVN_ERR(err);
+ SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
+ TRUE /* create_subdir */,
+ scratch_pool, scratch_pool));
/* Put the file into its target location. */
SVN_ERR(svn_io_file_rename(tempfile_abspath, pristine_abspath,
@@ -2554,111 +1942,834 @@ svn_wc__db_pristine_install(svn_wc__db_t
svn_error_t *
+svn_wc__db_pristine_get_md5(const svn_checksum_t **md5_checksum,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_PRISTINE_MD5_CHECKSUM));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (!have_row)
+ return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
+ _("The pristine text with checksum '%s' was "
+ "not found"),
+ svn_checksum_to_cstring_display(sha1_checksum,
+ scratch_pool));
+
+ SVN_ERR(svn_sqlite__column_checksum(md5_checksum, stmt, 0, result_pool));
+ SVN_ERR_ASSERT((*md5_checksum)->kind == svn_checksum_md5);
+
+ return svn_error_return(svn_sqlite__reset(stmt));
+}
+
+
+svn_error_t *
+svn_wc__db_pristine_get_sha1(const svn_checksum_t **sha1_checksum,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const svn_checksum_t *md5_checksum,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5);
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_PRISTINE_SHA1_CHECKSUM));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, md5_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (!have_row)
+ return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
+ _("The pristine text with MD5 checksum '%s' was "
+ "not found"),
+ svn_checksum_to_cstring_display(md5_checksum,
+ scratch_pool));
+
+ SVN_ERR(svn_sqlite__column_checksum(sha1_checksum, stmt, 0, result_pool));
+ SVN_ERR_ASSERT((*sha1_checksum)->kind == svn_checksum_sha1);
+
+ return svn_error_return(svn_sqlite__reset(stmt));
+}
+
+
+svn_error_t *
+svn_wc__db_pristine_remove(svn_wc__db_t *db,
+ const char *wri_abspath,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_boolean_t is_referenced;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error
+ * if the pristine text is not in the store. */
+ if (sha1_checksum->kind != svn_checksum_sha1)
+ SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
+ sha1_checksum,
+ scratch_pool, scratch_pool));
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ /* Find whether the SHA-1 (or the MD-5) is referenced; set IS_REFERENCED. */
+ {
+ const svn_checksum_t *md5_checksum;
+ svn_sqlite__stmt_t *stmt;
+
+ /* ### Transitional: look for references to its MD-5 as well. */
+ SVN_ERR(svn_wc__db_pristine_get_md5(&md5_checksum, db, wri_abspath,
+ sha1_checksum, scratch_pool,
+ scratch_pool));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_ANY_PRISTINE_REFERENCE));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__step(&is_referenced, stmt));
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+ }
+
+ /* If not referenced, remove first the PRISTINE table row, then the file. */
+ if (! is_referenced)
+ {
+ svn_sqlite__stmt_t *stmt;
+ const char *pristine_abspath;
+
+ /* Remove the DB row. */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_PRISTINE));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__update(NULL, stmt));
+
+ /* Remove the file */
+ SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
+ TRUE /* create_subdir */,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
svn_wc__db_pristine_check(svn_boolean_t *present,
svn_wc__db_t *db,
const char *wri_abspath,
- const svn_checksum_t *checksum,
+ const svn_checksum_t *sha1_checksum,
svn_wc__db_checkmode_t mode,
apr_pool_t *scratch_pool)
{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ const char *pristine_abspath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ svn_node_kind_t kind_on_disk;
+
SVN_ERR_ASSERT(present != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR_ASSERT(checksum != NULL);
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error
+ * if the pristine text is not in the store. */
+ if (sha1_checksum->kind != svn_checksum_sha1)
+ SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
+ sha1_checksum,
+ scratch_pool, scratch_pool));
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
- VERIFY_CHECKSUM_KIND(checksum);
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ wri_abspath, svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ /* Check that there is an entry in the PRISTINE table. */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_PRISTINE_MD5_CHECKSUM));
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ /* Check that the pristine text file exists. */
+ SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
+ FALSE /* create_subdir */,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool));
+
+ if (kind_on_disk != (have_row ? svn_node_file : svn_node_none))
+ return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
+ _("The pristine text with checksum '%s' was "
+ "found in the DB or on disk but not both"),
+ svn_checksum_to_cstring_display(sha1_checksum,
+ scratch_pool));
+
+ *present = have_row;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_pristine_repair(svn_wc__db_t *db,
+ const char *wri_abspath,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+ SVN_ERR_ASSERT(sha1_checksum != NULL);
+ SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
NOT_IMPLEMENTED();
}
-svn_error_t *
-svn_wc__db_pristine_repair(svn_wc__db_t *db,
- const char *wri_abspath,
- const svn_checksum_t *checksum,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR_ASSERT(checksum != NULL);
+svn_error_t *
+svn_wc__db_repos_ensure(apr_int64_t *repos_id,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *repos_root_url,
+ const char *repos_uuid,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+ local_abspath, svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ return svn_error_return(create_repos_id(repos_id, repos_root_url,
+ repos_uuid, pdh->wcroot->sdb,
+ scratch_pool));
+}
+
+/* Temporary helper for svn_wc__db_op_copy to handle copying from one
+ db to another, it becomes redundant when we centralise. */
+static svn_error_t *
+temp_cross_db_copy(svn_wc__db_t *db,
+ const char *src_abspath,
+ svn_wc__db_pdh_t *src_pdh,
+ const char *src_relpath,
+ svn_wc__db_pdh_t *dst_pdh,
+ const char *dst_relpath,
+ svn_wc__db_kind_t kind,
+ apr_int64_t copyfrom_id,
+ const char *copyfrom_relpath,
+ svn_revnum_t copyfrom_rev,
+ apr_pool_t *scratch_pool)
+{
+ insert_working_baton_t iwb;
+ svn_revnum_t changed_rev;
+ apr_time_t changed_date;
+ const char *changed_author;
+ const svn_checksum_t *checksum;
+ apr_hash_t *props;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR_ASSERT(kind == svn_wc__db_kind_file);
+
+ SVN_ERR(svn_wc__db_read_info(NULL, /* status */
+ NULL, /* kind */
+ NULL, /* revision */
+ NULL, /* repos_relpath */
+ NULL, /* repos_root_url */
+ NULL, /* repos_uuid */
+ &changed_rev, &changed_date, &changed_author,
+ NULL, /* last_mod_time */
+ NULL, /* depth */
+ &checksum,
+ NULL, /* translated_size */
+ NULL, /* target */
+ NULL, /* changelist */
+ NULL, /* original_repos_relpath */
+ NULL, /* original_root_url */
+ NULL, /* original_uuid */
+ NULL, /* original_revision */
+ NULL, /* text_mod */
+ NULL, /* props_mod */
+ NULL, /* base_shadowed */
[... 2462 lines stripped ...]