Author: philip Date: Thu Jun 2 16:32:18 2011 New Revision: 1130637 URL: http://svn.apache.org/viewvc?rev=1130637&view=rev Log: As a prelude to fixing issue 3908, status doesn't show wc-locks, optimise is_wclocked to reduce the number of queries when the working copy is not locked.
* subversion/libsvn_wc/wc_db.c (is_wclocked): Change signature, reimplement. (svn_wc__db_wclocked): Use svn_wc__db_with_txn. * subversion/libsvn_wc/wc-queries.sql (STMT_COUNT_WC_LOCK): New. Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql subversion/trunk/subversion/libsvn_wc/wc_db.c Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1130637&r1=1130636&r2=1130637&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Thu Jun 2 16:32:18 2011 @@ -726,6 +726,10 @@ VALUES (?1, ?2, ?3) SELECT locked_levels FROM wc_lock WHERE wc_id = ?1 AND local_dir_relpath = ?2 +-- STMT_COUNT_WC_LOCK +SELECT COUNT(*) FROM wc_lock +WHERE wc_id = ?1 + -- STMT_DELETE_WC_LOCK DELETE FROM wc_lock WHERE wc_id = ?1 AND local_dir_relpath = ?2 Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1130637&r1=1130636&r2=1130637&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/wc_db.c (original) +++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Jun 2 16:32:18 2011 @@ -10613,54 +10613,78 @@ svn_wc__db_wclock_obtain(svn_wc__db_t *d } -/* */ +/* Implements svn_wc__db_txn_callback_t. */ static svn_error_t * -is_wclocked(svn_boolean_t *locked, - svn_wc__db_t *db, - const char *local_abspath, - apr_int64_t recurse_depth, +is_wclocked(void *baton, + svn_wc__db_wcroot_t *wcroot, + const char *dir_relpath, apr_pool_t *scratch_pool) { + svn_boolean_t *locked = baton; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - svn_error_t *err; + apr_int64_t locked_levels, num_locks; + apr_int64_t dir_depth, depth = relpath_depth(dir_relpath); - err = get_statement_for_path(&stmt, db, local_abspath, - STMT_SELECT_WC_LOCK, scratch_pool); - if (err && SVN_WC__ERR_IS_NOT_CURRENT_WC(err)) + /* The most common scenarios are no locks in the wc, or a single + fully recursive lock at the root, only legacy API users will + create any other locks. First check for no locks at all. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_COUNT_WC_LOCK)); + SVN_ERR(svn_sqlite__bindf(stmt, "i", wcroot->wc_id)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (!have_row) + return svn_error_createf(SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt), + _("Count of WC_LOCK for id '%ld' failed"), + wcroot->wc_id); + num_locks = svn_sqlite__column_int64(stmt, 0); + SVN_ERR(svn_sqlite__reset(stmt)); + if (!num_locks) { - svn_error_clear(err); *locked = FALSE; return SVN_NO_ERROR; } - else - SVN_ERR(err); + /* Next check for a lock at root. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_WC_LOCK)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, "")); SVN_ERR(svn_sqlite__step(&have_row, stmt)); - + if (have_row) + locked_levels = svn_sqlite__column_int64(stmt, 0); + SVN_ERR(svn_sqlite__reset(stmt)); if (have_row) { - apr_int64_t locked_levels = svn_sqlite__column_int64(stmt, 0); - - /* The directory in question is considered locked if we find a lock - with depth -1 or the depth of the lock is greater than or equal to - the depth we've recursed. */ - *locked = (locked_levels == -1 || locked_levels >= recurse_depth); - return svn_error_return(svn_sqlite__reset(stmt)); + *locked = (locked_levels == -1 || locked_levels >= depth); + if (*locked || num_locks == 1) + return SVN_NO_ERROR; } - SVN_ERR(svn_sqlite__reset(stmt)); - - if (svn_dirent_is_root(local_abspath, strlen(local_abspath))) + /* Finally check for locks on dirs above root, only legacy API users + create these. I'm not sure what order is best here but from the + target to the root is easy to code. */ + dir_depth = depth; + while (*dir_relpath) { - *locked = FALSE; - return SVN_NO_ERROR; + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_WC_LOCK)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (have_row) + locked_levels = svn_sqlite__column_int64(stmt, 0); + SVN_ERR(svn_sqlite__reset(stmt)); + if (have_row) + { + /* Any row here means there can be no locks closer to root + that extend past here. */ + *locked = (locked_levels == -1 || locked_levels + dir_depth >= depth); + return SVN_NO_ERROR; + } + dir_relpath = svn_relpath_dirname(dir_relpath, scratch_pool); + --dir_depth; } - return svn_error_return(is_wclocked(locked, db, - svn_dirent_dirname(local_abspath, - scratch_pool), - recurse_depth + 1, scratch_pool)); + *locked = FALSE; + + return SVN_NO_ERROR; } @@ -10670,8 +10694,17 @@ svn_wc__db_wclocked(svn_boolean_t *locke const char *local_abspath, apr_pool_t *scratch_pool) { - return svn_error_return(is_wclocked(locked, db, local_abspath, 0, - 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, + local_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, is_wclocked, locked, + scratch_pool)); + + return SVN_NO_ERROR; }