Author: rhuijben
Date: Mon Jun 13 22:35:34 2011
New Revision: 1135331

URL: http://svn.apache.org/viewvc?rev=1135331&view=rev
Log:
Optimize the check for existing working copy locks from best case one query
to worst case one query.

The resulting query is a limited table/index scan over the table (which itself
is used as the index), which is far more efficient than performing multiple
queries.

* subversion/libsvn_wc/wc-queries.sql
  (STMT_HAS_WC_LOCK): Remove statement.
  (STMT_SELECT_ANCESTOR_WCLOCKS): New statement.

* subversion/libsvn_wc/wc_db.c
  (is_wclocked) Use STMT_SELECT_ANCESTOR_WCLOCKS instead of several
    queries and a lot of argument binding.

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=1135331&r1=1135330&r2=1135331&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Mon Jun 13 22:35:34 
2011
@@ -737,10 +737,12 @@ VALUES (?1, ?2, ?3)
 SELECT locked_levels FROM wc_lock
 WHERE wc_id = ?1 AND local_dir_relpath = ?2
 
--- STMT_HAS_WC_LOCK
-SELECT 1 FROM wc_lock
+-- STMT_SELECT_ANCESTOR_WCLOCKS
+SELECT local_dir_relpath, locked_levels FROM wc_lock
 WHERE wc_id = ?1
-LIMIT 1
+  AND ((local_dir_relpath <= ?2 AND local_dir_relpath >= ?3)
+       OR local_dir_relpath = '')
+ORDER BY local_dir_relpath DESC
 
 -- STMT_DELETE_WC_LOCK
 DELETE FROM wc_lock

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1135331&r1=1135330&r2=1135331&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Mon Jun 13 22:35:34 2011
@@ -10732,50 +10732,56 @@ is_wclocked(void *baton,
   svn_boolean_t *locked = baton;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  apr_int64_t locked_levels;
-  apr_int64_t dir_depth, depth = relpath_depth(dir_relpath);
+  apr_int64_t dir_depth = relpath_depth(dir_relpath);
+  const char *first_relpath;
+
+  /* Check for locks on all directories that might be ancestors.
+     As our new apis only use recursive locks the number of locks stored
+     in the DB will be very low */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_ANCESTOR_WCLOCKS));
+
+  /* Get the top level relpath to reduce the worst case number of results
+     to the number of directories below this node plus two.
+     (1: the node itself and 2: the wcroot). */
+  first_relpath = strchr(dir_relpath, '/');
+
+  if (first_relpath != NULL)
+    first_relpath = apr_pstrndup(scratch_pool, dir_relpath,
+                                 first_relpath - dir_relpath);
+  else
+    first_relpath = dir_relpath;
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "iss",
+                            wcroot->wc_id,
+                            dir_relpath,
+                            first_relpath));
 
-  /* First check for no locks at all, a common scenario for status. */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_HAS_WC_LOCK));
-  SVN_ERR(svn_sqlite__bindf(stmt, "i", wcroot->wc_id));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  SVN_ERR(svn_sqlite__reset(stmt));
-  if (!have_row)
-    {
-      *locked = FALSE;
-      return SVN_NO_ERROR;
-    }
 
-  /* Now check for locks on on the directory. I'm not sure what order
-     is best here but from the target to the root is easy to code.  */
-  dir_depth = depth;
-  while (TRUE)
+  while (have_row)
     {
-      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)
+      const char *relpath = svn_sqlite__column_text(stmt, 0, NULL);
+
+      if (svn_relpath_is_ancestor(relpath, dir_relpath))
         {
           /* 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);
+          apr_int64_t locked_levels = svn_sqlite__column_int64(stmt, 1);
+          apr_int64_t row_depth = relpath_depth(relpath);
+
+          *locked = (locked_levels == -1 
+                     || locked_levels + row_depth >= dir_depth);
+          SVN_ERR(svn_sqlite__reset(stmt));
           return SVN_NO_ERROR;
         }
 
-      if (!*dir_relpath)
-        break;
-
-      dir_relpath = svn_relpath_dirname(dir_relpath, scratch_pool);
-      --dir_depth;
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
 
   *locked = FALSE;
 
-  return SVN_NO_ERROR;
+  return svn_error_return(svn_sqlite__reset(stmt));
 }
 
 


Reply via email to