Author: julianfoad Date: Wed May 11 11:58:11 2011 New Revision: 1101848 URL: http://svn.apache.org/viewvc?rev=1101848&view=rev Log: Implement some (initially very simplistic) verification of the WC metadata in the DB. When compiled in SVN_DEBUG mode, make 'svn cleanup' run these checks and report any violations.
The purpose of this is to get some verification code started and for developers to be able to run it and extend it. Running it in 'svn cleanup' is just an initial and rather arbitrary UI choice; we could instead use a new subcommand or option or an external program. * subversion/libsvn_wc/cleanup.c (cleanup_internal): Call svn_wc__db_verify() if SVN_DEBUG is defined. * subversion/libsvn_wc/wc_db.c (VERIFY): New macro. (db_verify, svn_wc__db_verify): New functions. * subversion/libsvn_wc/wc_db.h (svn_wc__db_verify): New function. * subversion/libsvn_wc/wc-queries.sql (STMT_SELECT_ALL_NODES): New query. Modified: subversion/trunk/subversion/libsvn_wc/cleanup.c subversion/trunk/subversion/libsvn_wc/wc-queries.sql subversion/trunk/subversion/libsvn_wc/wc_db.c subversion/trunk/subversion/libsvn_wc/wc_db.h Modified: subversion/trunk/subversion/libsvn_wc/cleanup.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/cleanup.c?rev=1101848&r1=1101847&r2=1101848&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/cleanup.c (original) +++ subversion/trunk/subversion/libsvn_wc/cleanup.c Wed May 11 11:58:11 2011 @@ -160,6 +160,10 @@ cleanup_internal(svn_wc__db_t *db, SVN_ERR(svn_wc__db_get_wcroot(&cleanup_abspath, db, dir_abspath, scratch_pool, scratch_pool)); +#ifdef SVN_DEBUG + SVN_ERR(svn_wc__db_verify(db, dir_abspath, scratch_pool)); +#endif + /* Perform these operations if we lock the entire working copy. Note that we really need to check a wcroot value and not svn_wc__check_wcroot() as that function, will just return true Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1101848&r1=1101847&r2=1101848&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed May 11 11:58:11 2011 @@ -1168,6 +1168,16 @@ WHERE wc_id = ?1 AND presence IN ('normal', 'incomplete') AND file_external IS NULL +/* ------------------------------------------------------------------------- */ + +/* Queries for verification. */ + +-- STMT_SELECT_ALL_NODES +SELECT op_depth, local_relpath, parent_relpath FROM nodes +WHERE wc_id == ?1 + +/* ------------------------------------------------------------------------- */ + /* Grab all the statements related to the schema. */ -- include: wc-metadata Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1101848&r1=1101847&r2=1101848&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/wc_db.c (original) +++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed May 11 11:58:11 2011 @@ -12178,3 +12178,99 @@ svn_wc__db_base_get_lock_tokens_recursiv } return svn_sqlite__reset(stmt); } + + +/* If EXPRESSION is false, cause the caller to return an SVN_ERR_WC_CORRUPT + * error, showing EXPRESSION and the caller's LOCAL_RELPATH in the message. */ +#define VERIFY(expression) \ + do { \ + if (! (expression)) \ + return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, \ + _("database inconsistency at local_relpath='%s' verifying " \ + "expression '%s'"), local_relpath, #expression); \ + } while (0) + + +/* Verify consistency of the metadata concerning WCROOT. This is intended + * for use only during testing and debugging, so is not intended to be + * blazingly fast. + * + * This code is a complement to any verification that we can do in SQLite + * triggers. See, for example, 'wc-checks.sql'. + * + * Some more verification steps we might want to add are: + * + * * on every ACTUAL row (except root): a NODES row exists at its parent path + * * the op-depth root must always exist and every intermediate too + */ +static svn_error_t * +verify_wcroot(svn_wc__db_wcroot_t *wcroot, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_ALL_NODES)); + SVN_ERR(svn_sqlite__bindf(stmt, "i", wcroot->wc_id)); + while (TRUE) + { + svn_boolean_t have_row; + const char *local_relpath, *parent_relpath; + apr_int64_t op_depth; + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (!have_row) + break; + + op_depth = svn_sqlite__column_int(stmt, 0); + local_relpath = svn_sqlite__column_text(stmt, 1, iterpool); + parent_relpath = svn_sqlite__column_text(stmt, 2, iterpool); + + /* Verify parent_relpath is the parent path of local_relpath */ + VERIFY((parent_relpath == NULL) + ? (local_relpath[0] == '\0') + : (strcmp(svn_relpath_dirname(local_relpath, iterpool), + parent_relpath) == 0)); + + /* Verify op_depth <= the tree depth of local_relpath */ + VERIFY(op_depth <= relpath_depth(local_relpath)); + + /* Verify parent_relpath refers to a row that exists */ + /* TODO: Verify there is a suitable parent row - e.g. has op_depth <= + * the child's and a suitable presence */ + if (parent_relpath) + { + svn_sqlite__stmt_t *stmt2; + svn_boolean_t have_a_parent_row; + + SVN_ERR(svn_sqlite__get_statement(&stmt2, wcroot->sdb, + STMT_SELECT_NODE_INFO)); + SVN_ERR(svn_sqlite__bindf(stmt2, "is", wcroot->wc_id, + parent_relpath)); + SVN_ERR(svn_sqlite__step(&have_a_parent_row, stmt2)); + VERIFY(have_a_parent_row); + SVN_ERR(svn_sqlite__reset(stmt2)); + } + } + svn_pool_destroy(iterpool); + + return svn_error_return(svn_sqlite__reset(stmt)); +} + +svn_error_t * +svn_wc__db_verify(svn_wc__db_t *db, + const char *wri_abspath, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, + db, wri_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(verify_wcroot(wcroot, scratch_pool)); + return SVN_NO_ERROR; +} Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1101848&r1=1101847&r2=1101848&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/wc_db.h (original) +++ subversion/trunk/subversion/libsvn_wc/wc_db.h Wed May 11 11:58:11 2011 @@ -3022,6 +3022,14 @@ svn_wc__db_has_local_mods(svn_boolean_t apr_pool_t *scratch_pool); +/* Verify the consistency of metadata concerning the WC that contains + * WRI_ABSPATH, in DB. Return an error if any problem is found. */ +svn_error_t * +svn_wc__db_verify(svn_wc__db_t *db, + const char *wri_abspath, + apr_pool_t *scratch_pool); + + /* @} */