Author: cmpilato
Date: Thu Dec 17 18:10:27 2009
New Revision: 891813

URL: http://svn.apache.org/viewvc?rev=891813&view=rev
Log:
On the 'issue-3550-dev' branch, fix the `changes' table key
reservation system.  (Old behavior was to just keep adding row after
row of `next-key'-keyed items.  Oops!)

* subversion/tests/libsvn_fs_base/changes-test.c
  (txn_body_changes_reserve_id): New helper function.
  (changes_reserve_id): New test.
  (test_funcs): Add reference to changes_reserve_id.

* subversion/libsvn_fs_base/bdb/changes-table.c
  (add_next_key_row): New helper function.
  (svn_fs_bdb__open_changes_table, svn_fs_bdb__changes_init_next_key):
    Now use add_next_key_row() helper instead of doing related work.
  (svn_fs_bdb__changes_reserve_id): Delete existing 'next-key' row
    before put()ting another one, required because this table uses dupkeys.

Modified:
    
subversion/branches/issue-3550-dev/subversion/libsvn_fs_base/bdb/changes-table.c
    
subversion/branches/issue-3550-dev/subversion/tests/libsvn_fs_base/changes-test.c

Modified: 
subversion/branches/issue-3550-dev/subversion/libsvn_fs_base/bdb/changes-table.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/issue-3550-dev/subversion/libsvn_fs_base/bdb/changes-table.c?rev=891813&r1=891812&r2=891813&view=diff
==============================================================================
--- 
subversion/branches/issue-3550-dev/subversion/libsvn_fs_base/bdb/changes-table.c
 (original)
+++ 
subversion/branches/issue-3550-dev/subversion/libsvn_fs_base/bdb/changes-table.c
 Thu Dec 17 18:10:27 2009
@@ -45,6 +45,28 @@
 
 /*** Creating and opening the changes table. ***/
 
+/* Add a new 'next-key' row with value INITIAL_VALUE to the CHANGES
+   table as part of Berkeley DB transaction TXN_ID (which may be 0 if
+   no transaction support is needed).  This function assumes that the
+   CHANGES table does *not* already have a 'next-key' row.  */
+static int
+add_next_key_row(DB *changes,
+                 DB_TXN *txn_id,
+                 const char *initial_value)
+{
+  DBT key, value;
+
+  /* The `changes' table uses duplicate keys, so we need to specify
+     DB_NOOVERWRITE to avoid simply appending another 'next-key' row if
+     one already exists (which is not expected by callers of this
+     function). */
+  return changes->put(changes, txn_id,
+                      svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
+                      svn_fs_base__str_to_dbt(&value, initial_value),
+                      DB_NOOVERWRITE);
+}
+
+
 int
 svn_fs_bdb__open_changes_table(DB **changes_p,
                                DB_ENV *env,
@@ -69,10 +91,7 @@
      supports the arbitrary changes table keys, init our 'next-key' item. */
   if (create && (version >= SVN_FS_BASE__MIN_CHANGES_INFO_FORMAT))
     {
-      DBT key, value;
-      BDB_ERR(changes->put(changes, 0,
-                           svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
-                           svn_fs_base__str_to_dbt(&value, "0"), 0));
+      BDB_ERR(add_next_key_row(changes, 0, "0"));
     }
 
   *changes_p = changes;
@@ -87,32 +106,9 @@
                                   apr_pool_t *pool)
 {
   base_fs_data_t *bfd = fs->fsap_data;
-  DBT key, value;
-  int db_err;
-
-  svn_fs_base__trail_debug(trail, "changes", "get");
-  db_err = bfd->changes->get(bfd->changes, trail->db_txn,
-                             svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
-                             svn_fs_base__result_dbt(&value), 0);
-  svn_fs_base__track_dbt(&value, pool);
-
-  /* A not-found error is ideal -- let's add our 'next-key' row and
-     get outta here.  */
-  if (db_err == DB_NOTFOUND)
-    {
-      return BDB_WRAP(fs, _("initializing next changes key"),
-                      (bfd->changes->put(
-                          bfd->changes, trail->db_txn,
-                          svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
-                          svn_fs_base__str_to_dbt(&value, initial_value), 0)));
-    }
-
-  /* If there was some other error, though, we'll propogate that up. */
-  SVN_ERR(BDB_WRAP(fs, "fetching next changes key", db_err));
-  
-  /* If there wasn't an error above, that, too, is a problem. */
-  return svn_error_create(SVN_ERR_FS_CORRUPT, 0,
-                          _("Found unexpected 'next-key' in changes table"));
+  return BDB_WRAP(fs, "init changes 'next-key' row",
+                  add_next_key_row(bfd->changes, trail->db_txn,
+                                   initial_value));
 }
 
 
@@ -142,15 +138,18 @@
   /* Set our return value. */
   *id_p = apr_pstrmemdup(pool, result.data, result.size);
 
-  /* Bump to future key. */
+  /* Bump to future key.  Because this table uses duplicate keys, we
+     have to first remove the old 'next-key' row. */
+  svn_fs_base__trail_debug(trail, "changes", "del");
+  SVN_ERR(BDB_WRAP(fs, _("delete changes 'next-key' record"),
+                   bfd->changes->del(bfd->changes, trail->db_txn,
+                                     &query, 0)));
   len = result.size;
   svn_fs_base__next_key(result.data, &len, next_key);
   svn_fs_base__trail_debug(trail, "changes", "put");
-  db_err = bfd->changes->put(bfd->changes, trail->db_txn,
-                             svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY),
+  db_err = bfd->changes->put(bfd->changes, trail->db_txn, &query,
                              svn_fs_base__str_to_dbt(&result, next_key),
-                             0);
-
+                             DB_NOOVERWRITE);
   return BDB_WRAP(fs, _("bumping next changes key"), db_err);
 }
 

Modified: 
subversion/branches/issue-3550-dev/subversion/tests/libsvn_fs_base/changes-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/issue-3550-dev/subversion/tests/libsvn_fs_base/changes-test.c?rev=891813&r1=891812&r2=891813&view=diff
==============================================================================
--- 
subversion/branches/issue-3550-dev/subversion/tests/libsvn_fs_base/changes-test.c
 (original)
+++ 
subversion/branches/issue-3550-dev/subversion/tests/libsvn_fs_base/changes-test.c
 Thu Dec 17 18:10:27 2009
@@ -161,11 +161,46 @@
   return svn_fs_bdb__changes_delete(b->fs, b->key, trail, trail->pool);
 }
 
+static svn_error_t *
+txn_body_changes_reserve_id(void *baton, trail_t *trail)
+{
+  const char *expected_key = baton;
+  const char *reserved_key;
+  SVN_ERR(svn_fs_bdb__changes_reserve_id(&reserved_key, trail->fs,
+                                         trail, trail->pool));
+  if (strcmp(reserved_key, expected_key) != 0)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                             "got reserved key '%s'; expected '%s'",
+                             reserved_key, expected_key);
+  return SVN_NO_ERROR;
+}
 
 
 /* The tests.  */
 
 static svn_error_t *
+changes_reserve_id(const svn_test_opts_t *opts,
+                   apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+
+  /* Create a new fs and repos */
+  SVN_ERR(svn_test__create_bdb_fs(&fs, "test-repo-changes-reserve-id",
+                                  opts, pool));
+  
+  /* Run the real test, which is all trail-y. */
+  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_reserve_id,
+                                 (void *)"1", FALSE, pool));
+  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_reserve_id,
+                                 (void *)"2", FALSE, pool));
+  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_reserve_id,
+                                 (void *)"3", FALSE, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
 changes_add(const svn_test_opts_t *opts,
             apr_pool_t *pool)
 {
@@ -704,6 +739,8 @@
 struct svn_test_descriptor_t test_funcs[] =
   {
     SVN_TEST_NULL,
+    SVN_TEST_OPTS_PASS(changes_reserve_id,
+                       "test changes next-key reservation"),
     SVN_TEST_OPTS_PASS(changes_add,
                        "add changes to the changes table"),
     SVN_TEST_OPTS_PASS(changes_fetch_raw,


Reply via email to