[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] [merge-tracking] merge info index refactorisation to a new module libsvn_fs_util

From: Kamesh Jayachandran <kamesh_at_collab.net>
Date: 2006-08-17 15:53:39 CEST

Hi All,
Slightly bigger patch but if you go through the summary of log message
it is easy to understand the crux.

Find the attached patch.

With regards
Kamesh Jayachandran

[[[
Patch by: Kamesh Jayachandran <kamesh@collab.net>

Move mergeinfo indexing code out of libsvn_fs_fs to libsvn_fs_util(new
module)
so that it can be reused bdb repos.

The changes can be summarised as follows,
1. root_vtable_t's get_merge_info hook has been removed as
implementation is
    'fs' independent and can be availed out of new module libsvn_fs_util's
    svn_fs_util_get_merge_info.

2. Exposing 'txn_mergeinfo' hook out of txn_vtable_t so that new merge_info
    indexer can make use of it to weave the information from the
transaction.

3. libsvn_fs_util exposes the following public functions for libsvn_fs_fs,
    libsvn_fs_base, libsvn_fs modules to consume.
    - svn_fs_util_mtd_create - creates the fresh mergeinfo db with the
schema
      consumed by libsvn_fs repo create hook.
    - svn_fs_util_mtd_update_merge_info_index - updates mergeinfo sqlite db
      consumed by the commit_body of libsvn_fs_fs currently later would
be used
      by libsvn_fs_base.
    - svn_fs_util_get_merge_info - gets a mergeinfo for a committed revision
      for the set of paths, consumed by libsvn_fs.

4. Moving the relevant functions as detailed down against each file from
    libsvn_fs_fs/tree.c and libsvn_fs_fs/fs_fs.c to
    libsvn_fs_util/merge_info_indexer.c

* build.conf
  (libsvn_fs_fs):
   No more depends on sqlite rather depends on libsvn_fs_util.
  (libsvn_fs_util): New module.

* subversion/libsvn_fs/fs-loader.h
  (txn_vtable_t):
   Added 'txn_mergeinfo' member.
  (root_vtable_t):
   Removed 'get_merge_info' member.

* subversion/libsvn_fs/fs-loader.c
  (svn_fs_create):
   Calling 'svn_fs_util_mtd_create' to create the fresh mergeinfo db
with the
   schema.
  (svn_fs_get_merge_info):
   Calling 'svn_fs_util_get_merge_info' rather than root_vtable_t's
   get_merge_info hook.

* subversion/libsvn_fs_fs/fs.h
  Removed the inclusion of sqlite3.h header.
  (fs_fs_data_t):
   Removed the member 'mtd'.
  (fs_txn_data_t): Removed.
  (fs_sqlite_exec): Moved to a new module libsvn_fs_util and made 'static'
   there as it is consumed from the same single 'C' file. It is renamed as
   util_sqlite_exec.
  (SQLITE_ERR): Moved to a new header
   subversion/libsvn_fs_util/merge_info_indexer.h

* subversion/libsvn_fs_fs/tree.c
  (sqlite_tracer): Removed.
  (NEGATIVE_CACHE_RESULT): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (parse_mergeinfo_from_db): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (append_component_to_paths): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (get_merge_info_for_path): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (fs_get_merge_info): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c and renamed as
   'svn_fs_util_get_merge_info'.
  (root_vtable):
   Removed 'get_merge_info' member.

* subversion/libsvn_fs_fs/fs_fs.c
  Removed the inclusion of sqlite3.h header.
  (txn_vtable): populated the 'txn_mergeinfo' member.
  (sqlite_tracer): Removed.
  (svn_fs_fs__create_txn):
   Not populating the 'fs_txn_data_t' of txn vtable.
  (index_path_merge_info): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (index_txn_merge_info): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c
  (update_merge_info_index): Moved to
   subversion/libsvn_fs_util/merge_info_indexer.c and made it a
   public function by name 'svn_fs_util_mtd_update_merge_info_index'.
  (commit_body): Calling 'svn_fs_util_mtd_update_merge_info_index'
   instead of local update_merge_info_index.
  (fs_sqlite_exec): Removed.
  (SVN_MTD_CREATE_SQL): Removed
  (svn_fs_fs__create): not creating the mergeinfo db here rather leave it to
   libsvn_fs.
  (svn_fs_fs__open_txn):
   No more populating the fsap_data member.

* subversion/libsvn_fs_base/tree.c
  (root_vtable):
   Removed 'get_merge_info' member.

* subversion/libsvn_fs_util
  New module.

* subversion/libsvn_fs_util/merge_info_indexer.c
  New file having functions borrowed from subversion/libsvn_fs_fs/tree.c and
  subversion/libsvn_fs_fs/fs_fs.c.
* subversion/libsvn_fs_util/merge_info_indexer.h

]]]

Index: build.conf
===================================================================
--- build.conf (revision 20955)
+++ build.conf (working copy)
@@ -239,7 +239,7 @@
 type = fs-module
 path = subversion/libsvn_fs_fs
 install = fsmod-lib
-libs = libsvn_delta libsvn_subr aprutil apriconv apr sqlite
+libs = libsvn_delta libsvn_subr aprutil apriconv apr libsvn_fs_util
 msvc-static = yes
 
 # General API for accessing repositories
@@ -302,6 +302,15 @@
 msvc-libs = advapi32.lib shfolder.lib
 msvc-static = yes
 
+# Low-level grab bag of utilities
+[libsvn_fs_util]
+type = lib
+install = fsmod-lib
+path = subversion/libsvn_fs_util
+libs = aprutil apriconv apr
+msvc-libs = advapi32.lib shfolder.lib
+msvc-static = yes
+
 # Working copy management lib
 [libsvn_wc]
 type = lib
Index: subversion/libsvn_fs_base/tree.c
===================================================================
--- subversion/libsvn_fs_base/tree.c (revision 20955)
+++ subversion/libsvn_fs_base/tree.c (working copy)
@@ -4373,7 +4373,6 @@
   base_contents_changed,
   base_get_file_delta_stream,
   base_merge,
- NULL,
   NULL
 };
 
Index: subversion/libsvn_fs_util/merge_info_indexer.c
===================================================================
--- subversion/libsvn_fs_util/merge_info_indexer.c (revision 0)
+++ subversion/libsvn_fs_util/merge_info_indexer.c (revision 0)
@@ -0,0 +1,552 @@
+/* merge_info_indexer.c
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <apr_general.h>
+#include <apr_pools.h>
+
+#include <sqlite3.h>
+
+#include "svn_fs.h"
+#include "svn_path.h"
+#include "svn_mergeinfo.h"
+
+#include "merge_info_indexer.h"
+
+#include "../libsvn_fs/fs-loader.h"
+
+#include "svn_private_config.h"
+
+/* Following are defines that specify the textual elements of the
+ native filesystem directories and revision files. */
+
+/* Names of special files in the filesystem. */
+#define PATH_MERGEINFO_DB "mergeinfo.db" /* Contains mergeinfo. */
+
+/* We want to cache that we saw no mergeinfo for a path as well,
+ so we use a -1 converted to a pointer to represent this. */
+#define NEGATIVE_CACHE_RESULT ((void *)(-1))
+
+static const char *
+path_mergeinfo_db(const char *path, apr_pool_t *pool)
+{
+ return svn_path_join(path, PATH_MERGEINFO_DB, pool);
+}
+
+/*#define SQLITE3_DEBUG 1 */
+#ifdef SQLITE3_DEBUG
+static void
+sqlite_tracer (void *data, const char *sql)
+{
+ /* sqlite3 *db = data; */
+ fprintf (stderr, "SQLITE SQL is \"%s\"\n", sql);
+}
+#endif
+
+/* Execute SQL on the sqlite database, and raise an SVN error if the
+ result is not okay. */
+
+static svn_error_t *
+util_sqlite_exec (sqlite3 *db, const char *sql,
+ sqlite3_callback callback,
+ void *callbackdata)
+{
+ char *errmsg;
+ if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ errmsg);
+ return SVN_NO_ERROR;
+}
+
+const char SVN_MTD_CREATE_SQL[] = "pragma auto_vacuum = 1;"
+ APR_EOL_STR
+ "create table mergeinfo (revision integer not null, mergedfrom text not null, mergedto text not null, mergedrevstart integer not null, mergedrevend integer not null);"
+ APR_EOL_STR
+ "create index mi_mergedfrom_idx on mergeinfo (mergedfrom);"
+ APR_EOL_STR
+ "create index mi_mergedto_idx on mergeinfo (mergedto);"
+ APR_EOL_STR
+ "create index mi_revision_idx on mergeinfo (revision);"
+ APR_EOL_STR
+ "create table mergeinfo_changed (revision integer not null, path text not null);"
+ APR_EOL_STR
+ "create unique index mi_c_revpath_idx on mergeinfo_changed (revision, path);"
+ APR_EOL_STR
+ "create index mi_c_path_idx on mergeinfo_changed (path);"
+ APR_EOL_STR
+ "create index mi_c_revision_idx on mergeinfo_changed (revision);"
+ APR_EOL_STR;
+
+svn_error_t *
+svn_fs_util_mtd_create(const char *path,
+ apr_pool_t *pool)
+{
+ sqlite3 *db;
+
+ SQLITE_ERR(sqlite3_open(path_mergeinfo_db(path, pool), &db), db);
+#ifdef SQLITE3_DEBUG
+ sqlite3_trace (db, sqlite_tracer, db);
+#endif
+ SVN_ERR(util_sqlite_exec(db, SVN_MTD_CREATE_SQL, NULL, NULL));
+
+ SQLITE_ERR(sqlite3_close(db), db);
+
+ return SVN_NO_ERROR;
+}
+
+/* Create SQL to insert the necessary indexing data for all the merge
+ info lists of PATH, which is provided (unparsed) in MINFOSTRING. */
+static svn_error_t *
+index_path_merge_info(svn_fs_txn_t *txn, svn_revnum_t new_rev,
+ sqlite3 *db, const char *path,
+ svn_string_t *minfostring, apr_pool_t *pool)
+{
+ apr_hash_t *minfo;
+ apr_hash_index_t *hi;
+ sqlite3_stmt *stmt;
+
+ SVN_ERR(svn_mergeinfo_parse(minfostring->data, &minfo, pool));
+
+ for (hi = apr_hash_first(pool, minfo);
+ hi != NULL;
+ hi = apr_hash_next(hi))
+ {
+ const char *from;
+ apr_array_header_t *revlist;
+ const void *key;
+ void *val;
+
+ apr_hash_this(hi, &key, NULL, &val);
+
+ from = key;
+ revlist = val;
+
+ if (from && revlist)
+ {
+ int i;
+ for (i = 0; i < revlist->nelts; i++)
+ {
+ svn_merge_range_t *range;
+
+ range = APR_ARRAY_IDX(revlist, i, svn_merge_range_t *);
+ SQLITE_ERR(sqlite3_prepare(db,
+ "INSERT INTO mergeinfo (revision, mergedto, mergedfrom, mergedrevstart, mergedrevend) VALUES (?, ?, ?, ?, ?);",
+ -1, &stmt, NULL), db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev), db);
+ SQLITE_ERR(sqlite3_bind_text(stmt, 2, path, -1, SQLITE_TRANSIENT),
+ db);
+ SQLITE_ERR(sqlite3_bind_text(stmt, 3, from, -1, SQLITE_TRANSIENT),
+ db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 4, range->start), db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 5, range->end), db);
+ if (sqlite3_step(stmt) != SQLITE_DONE)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+
+ SQLITE_ERR(sqlite3_finalize(stmt), db);
+ }
+ }
+ }
+ SQLITE_ERR (sqlite3_prepare(db,
+ "INSERT INTO mergeinfo_changed (revision, path) VALUES (?, ?);",
+ -1, &stmt, NULL),
+ db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev), db);
+
+ SQLITE_ERR(sqlite3_bind_text(stmt, 2, path, -1, SQLITE_TRANSIENT),
+ db);
+
+ if (sqlite3_step(stmt) != SQLITE_DONE)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+
+ SQLITE_ERR(sqlite3_finalize(stmt), db);
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Create the index for any merge info in TXN (a no-op if TXN has no
+ associated merge info). */
+static svn_error_t *
+index_txn_merge_info(svn_fs_txn_t *txn, svn_revnum_t new_rev,
+ sqlite3 *db, apr_pool_t *pool)
+{
+ apr_hash_t *minfoprops;
+
+ SVN_ERR(txn->vtable->txn_mergeinfo(&minfoprops, txn, pool));
+ if (minfoprops)
+ {
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, minfoprops);
+ hi != NULL;
+ hi = apr_hash_next(hi))
+ {
+ const char *minfopath;
+ svn_string_t *minfostring;
+ const void *key;
+ void *val;
+
+ apr_hash_this(hi, &key, NULL, &val);
+
+ minfopath = key;
+ minfostring = val;
+
+ SVN_ERR(index_path_merge_info(txn, new_rev, db, minfopath,
+ minfostring, pool));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Clean the merge info index for any previous failed commit with the
+ revision number as NEW_REV, and if the current transaction contains
+ merge info, record it. */
+svn_error_t *
+svn_fs_util_mtd_update_merge_info_index(svn_fs_txn_t *txn, svn_revnum_t new_rev,
+ svn_boolean_t txn_contains_merge_info,
+ apr_pool_t *pool)
+{
+ const char *deletestring;
+
+ sqlite3 *db;
+
+ SQLITE_ERR(sqlite3_open(path_mergeinfo_db(txn->fs->path, pool), &db), db);
+#ifdef SQLITE3_DEBUG
+ sqlite3_trace (db, sqlite_tracer, db);
+#endif
+ SVN_ERR(util_sqlite_exec(db, "begin transaction;", NULL, NULL));
+
+ // Cleanup the leftovers of any previous, failed FSFS transactions
+ // involving NEW_REV.
+ deletestring = apr_psprintf(pool,
+ "delete from mergeinfo_changed where revision = %ld;",
+ new_rev);
+ SVN_ERR(util_sqlite_exec(db, deletestring, NULL, NULL));
+ deletestring = apr_psprintf(pool,
+ "delete from mergeinfo where revision = %ld;",
+ new_rev);
+ SVN_ERR(util_sqlite_exec(db, deletestring, NULL, NULL));
+
+ // Record any merge info from the current transaction.
+ if (txn_contains_merge_info)
+ SVN_ERR(index_txn_merge_info(txn, new_rev, db, pool));
+
+ // This is moved here from commit_txn, because we don't want to
+ // write the final current file if the sqlite commit fails.
+ // On the other hand, if we commit the transaction and end up failing
+ // the current file, we just end up with inaccessible data in the
+ // database, not a real problem.
+ SVN_ERR(util_sqlite_exec(db, "commit transaction;", NULL, NULL));
+ SQLITE_ERR(sqlite3_close(db), db);
+
+ return SVN_NO_ERROR;
+}
+
+/* Helper for get_merge_info that retrieves merge info for a single
+ revision from the database and puts it into a mergeinfo hash. */
+static svn_error_t *
+parse_mergeinfo_from_db(sqlite3 *db,
+ const char *path,
+ svn_revnum_t rev,
+ apr_hash_t **result,
+ apr_pool_t *pool)
+{
+ sqlite3_stmt *stmt;
+ sqlite_int64 lastchanged_rev;
+ int sqlite_result;
+
+ SQLITE_ERR(sqlite3_prepare(db, "SELECT MAX(revision) from mergeinfo_changed"
+ " where path = ? and revision <= ?;",
+ -1, &stmt, NULL), db);
+ SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 2, rev), db);
+ sqlite_result = sqlite3_step(stmt);
+ if (sqlite_result != SQLITE_ROW)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+
+ lastchanged_rev = sqlite3_column_int64(stmt, 0);
+
+ SQLITE_ERR(sqlite3_finalize(stmt), db);
+
+ SQLITE_ERR(sqlite3_prepare(db,
+ "SELECT mergedfrom, mergedrevstart,"
+ "mergedrevend from mergeinfo "
+ "where mergedto = ? and revision = ? "
+ "order by mergedfrom;",
+ -1, &stmt, NULL), db);
+ SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 2, lastchanged_rev), db);
+ sqlite_result = sqlite3_step(stmt);
+
+ /* It is possible the mergeinfo changed because of a delete, and
+ that the mergeinfo is now gone. If this is the case, we want
+ to do nothing but fallthrough into the count == 0 case */
+ if (sqlite_result == SQLITE_DONE)
+ {
+ *result = NULL;
+ return SVN_NO_ERROR;
+ }
+ else if (sqlite_result == SQLITE_ROW)
+ {
+ apr_array_header_t *pathranges;
+ const char *mergedfrom;
+ svn_revnum_t startrev;
+ svn_revnum_t endrev;
+ const char *lastmergedfrom = NULL;
+
+ *result = apr_hash_make(pool);
+ pathranges = apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
+
+ while (sqlite_result == SQLITE_ROW)
+ {
+ svn_merge_range_t *temprange;
+
+ mergedfrom = (char *) sqlite3_column_text(stmt, 0);
+ startrev = sqlite3_column_int64(stmt, 1);
+ endrev = sqlite3_column_int64(stmt, 2);
+ if (lastmergedfrom && strcmp(mergedfrom, lastmergedfrom) != 0)
+ {
+ apr_hash_set(*result, mergedfrom, APR_HASH_KEY_STRING,
+ pathranges);
+ pathranges = apr_array_make(pool, 1,
+ sizeof(svn_merge_range_t *));
+ }
+ temprange = apr_pcalloc(pool, sizeof(*temprange));
+ temprange->start = startrev;
+ temprange->end = endrev;
+ APR_ARRAY_PUSH(pathranges, svn_merge_range_t *) = temprange;
+ sqlite_result = sqlite3_step(stmt);
+ lastmergedfrom = mergedfrom;
+ }
+ apr_hash_set(*result, mergedfrom, APR_HASH_KEY_STRING, pathranges);
+
+ if (sqlite_result != SQLITE_DONE)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+ }
+ else
+ {
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+ }
+ SQLITE_ERR(sqlite3_finalize(stmt), db);
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Helper for get_merge_info_for_path that will append a string to each
+ path that exists in the mergeinfo hash. */
+static svn_error_t *
+append_component_to_paths(apr_hash_t **output,
+ apr_hash_t *input,
+ const char *toappend,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ *output = apr_hash_make(pool);
+
+ for (hi = apr_hash_first(pool, input);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *val;
+ apr_ssize_t klen;
+ char *newpath;
+
+ apr_hash_this(hi, &key, &klen, &val);
+ newpath = svn_path_join((const char *)key, toappend, pool);
+ apr_hash_set(*output, newpath, APR_HASH_KEY_STRING, val);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Helper for get_merge_info that will recursively get merge info for
+ a single path. */
+static svn_error_t *
+get_merge_info_for_path(sqlite3 *db,
+ const char *path,
+ svn_revnum_t rev,
+ apr_hash_t *result,
+ apr_hash_t *cache,
+ svn_boolean_t setresult,
+ svn_boolean_t include_parents,
+ apr_pool_t *pool)
+{
+ apr_hash_t *cacheresult;
+ sqlite3_stmt *stmt;
+ int sqlite_result;
+ sqlite_int64 count;
+ svn_boolean_t has_no_mergeinfo = FALSE;
+
+ cacheresult = apr_hash_get(cache, path, APR_HASH_KEY_STRING);
+ if (cacheresult != 0)
+ {
+ if (cacheresult != NEGATIVE_CACHE_RESULT && setresult)
+ apr_hash_set(result, path, APR_HASH_KEY_STRING, cacheresult);
+ return SVN_NO_ERROR;
+ }
+
+ /* See if we have a mergeinfo_changed record for this path. If not,
+ then it can't have mergeinfo. */
+ SQLITE_ERR(sqlite3_prepare(db, "SELECT COUNT(*) from mergeinfo_changed"
+ " where path = ? and revision <= ?;",
+ -1, &stmt, NULL), db);
+
+ SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
+ SQLITE_ERR(sqlite3_bind_int64(stmt, 2, rev), db);
+ sqlite_result = sqlite3_step(stmt);
+ if (sqlite_result != SQLITE_ROW)
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
+ sqlite3_errmsg(db));
+
+ count = sqlite3_column_int64(stmt, 0);
+ SQLITE_ERR(sqlite3_finalize(stmt), db);
+
+ /* If we've got mergeinfo data, transform it from the db into a
+ mergeinfo hash */
+ if (count > 0)
+ {
+ apr_hash_t *pathresult = NULL;
+
+ SVN_ERR(parse_mergeinfo_from_db(db, path, rev, &pathresult, pool));
+ if (pathresult)
+ {
+ if (setresult)
+ apr_hash_set(result, path, APR_HASH_KEY_STRING, pathresult);
+ apr_hash_set(cache, path, APR_HASH_KEY_STRING, pathresult);
+ }
+ else
+ has_no_mergeinfo = TRUE;
+ }
+
+ /* If this path has no mergeinfo, and we are asked to, check our parent */
+ if ((count == 0 || has_no_mergeinfo) && include_parents)
+ {
+ svn_stringbuf_t *parentpath;
+
+ apr_hash_set(cache, path, APR_HASH_KEY_STRING, NEGATIVE_CACHE_RESULT);
+
+ /* It is possible we are already at the root. */
+ if (strcmp(path, "") == 0)
+ return SVN_NO_ERROR;
+
+ parentpath = svn_stringbuf_create(path, pool);
+ svn_path_remove_component(parentpath);
+
+ /* The repository, and the mergeinfo index, internally refer to
+ "/" as "" */
+ if (strcmp(parentpath->data, "/") == 0)
+ parentpath->data = "";
+
+ SVN_ERR(get_merge_info_for_path(db, parentpath->data, rev,
+ result, cache, FALSE, include_parents,
+ pool));
+ if (setresult)
+ {
+ /* Now translate the result for our parent to our path */
+ cacheresult = apr_hash_get(cache, parentpath->data,
+ APR_HASH_KEY_STRING);
+ if (cacheresult == NEGATIVE_CACHE_RESULT)
+ apr_hash_set(result, path, APR_HASH_KEY_STRING, NULL);
+ else if (cacheresult)
+ {
+ const char *p;
+ int i;
+ apr_hash_t *translatedhash;
+ char *toappend;
+
+ /* We want to append from the part after the / to the end of the
+ path string. */
+ toappend = apr_pcalloc(pool,
+ (strlen(path) - parentpath->len) + 1);
+ for (i = 0, p = &path[parentpath->len + 1]; *p; i++, p++)
+ *(toappend + i) = *p;
+ append_component_to_paths(&translatedhash, cacheresult,
+ toappend, pool);
+ apr_hash_set(result, path, APR_HASH_KEY_STRING,
+ translatedhash);
+ }
+ }
+ }
+ return SVN_NO_ERROR;
+}
+
+
+
+/* Get the merge info for a set of paths. */
+svn_error_t *
+svn_fs_util_get_merge_info(apr_hash_t **mergeinfo,
+ svn_fs_root_t *root,
+ const apr_array_header_t *paths,
+ svn_boolean_t include_parents,
+ apr_pool_t *pool)
+{
+ apr_hash_t *mergeinfo_cache = apr_hash_make (pool);
+ sqlite3 *db;
+ int i;
+ svn_revnum_t rev;
+
+ /* We require a revision root. */
+ if (root->is_txn_root)
+ return svn_error_create(SVN_ERR_FS_NOT_REVISION_ROOT, NULL, NULL);
+ rev = svn_fs_revision_root_revision(root);
+
+ SQLITE_ERR(sqlite3_open(path_mergeinfo_db(root->fs->path, pool), &db), db);
+
+#ifdef SQLITE3_DEBUG
+ sqlite3_trace (db, sqlite_tracer, db);
+#endif
+
+ *mergeinfo = apr_hash_make (pool);
+ for (i = 0; i < paths->nelts; i++)
+ {
+ const char *path = APR_ARRAY_IDX(paths, i, const char *);
+
+ SVN_ERR (get_merge_info_for_path (db, path, rev, *mergeinfo,
+ mergeinfo_cache, TRUE,
+ include_parents, pool));
+ }
+
+ for (i = 0; i < paths->nelts; i++)
+ {
+ svn_stringbuf_t *mergestring;
+ apr_hash_t *currhash;
+ const char *path = APR_ARRAY_IDX(paths, i, const char *);
+
+ currhash = apr_hash_get(*mergeinfo, path, APR_HASH_KEY_STRING);
+ if (currhash)
+ {
+ SVN_ERR (svn_mergeinfo_sort(currhash, pool));
+ SVN_ERR (svn_mergeinfo_to_string(&mergestring, currhash, pool));
+ apr_hash_set(*mergeinfo, path, APR_HASH_KEY_STRING, mergestring->data);
+ }
+ }
+ SQLITE_ERR(sqlite3_close(db), db);
+ return SVN_NO_ERROR;
+}
Index: subversion/libsvn_fs_util/merge_info_indexer.h
===================================================================
--- subversion/libsvn_fs_util/merge_info_indexer.h (revision 0)
+++ subversion/libsvn_fs_util/merge_info_indexer.h (revision 0)
@@ -0,0 +1,47 @@
+/*
+ * merge_info_indexer.h: Declarations for the public functions of
+ * libsvn_fs_util.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+svn_error_t *
+svn_fs_util_mtd_create(const char *path,
+ apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_util_mtd_update_merge_info_index
+ (svn_fs_txn_t *txn, svn_revnum_t new_rev,
+ svn_boolean_t txn_contains_merge_info,
+ apr_pool_t *pool);
+
+/* Get the merge info for a set of paths. */
+svn_error_t *
+svn_fs_util_get_merge_info(apr_hash_t **mergeinfo,
+ svn_fs_root_t *root,
+ const apr_array_header_t *paths,
+ svn_boolean_t include_parents,
+ apr_pool_t *pool);
+
+/* SQLITE->SVN quick error wrap, much like SVN_ERR.
+ XXX: This macro probably belongs elsehwere, like svn_sqlite.h or
+ something. Later. */
+#define SQLITE_ERR(x, db) do \
+{ \
+ if ((x) != SQLITE_OK) \
+ return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL, \
+ sqlite3_errmsg((db))); \
+} while (0)
+
Index: subversion/libsvn_fs/fs-loader.h
===================================================================
--- subversion/libsvn_fs/fs-loader.h (revision 20955)
+++ subversion/libsvn_fs/fs-loader.h (working copy)
@@ -184,6 +184,8 @@
                               const svn_string_t *value, apr_pool_t *pool);
   svn_error_t *(*root)(svn_fs_root_t **root_p, svn_fs_txn_t *txn,
                        apr_pool_t *pool);
+ svn_error_t *(*txn_mergeinfo)(apr_hash_t **minfoprops, svn_fs_txn_t *txn,
+ apr_pool_t *pool);
 } txn_vtable_t;
 
 
@@ -291,11 +293,6 @@
   svn_error_t *(*change_merge_info)(svn_fs_root_t *root, const char *path,
                                     apr_hash_t *info,
                                     apr_pool_t *pool);
- svn_error_t *(*get_merge_info)(apr_hash_t **minfohash,
- svn_fs_root_t *root,
- const apr_array_header_t *paths,
- svn_boolean_t include_parents,
- apr_pool_t *pool);
 } root_vtable_t;
 
 
Index: subversion/libsvn_fs/fs-loader.c
===================================================================
--- subversion/libsvn_fs/fs-loader.c (revision 20955)
+++ subversion/libsvn_fs/fs-loader.c (working copy)
@@ -353,6 +353,7 @@
   /* Perform the actual creation. */
   *fs_p = svn_fs_new(fs_config, pool);
   SVN_ERR(vtable->create(*fs_p, path, pool));
+ SVN_ERR(svn_fs_util_mtd_create(path, pool));
   return serialized_init(*fs_p, pool);
 }
 
@@ -734,8 +735,8 @@
                       svn_boolean_t include_parents,
                       apr_pool_t *pool)
 {
- return root->vtable->get_merge_info(minfohash, root, paths, include_parents,
- pool);
+ return svn_fs_util_get_merge_info(minfohash, root, paths, include_parents,
+ pool);
 }
 
 svn_error_t *
Index: subversion/libsvn_fs_fs/tree.c
===================================================================
--- subversion/libsvn_fs_fs/tree.c (revision 21106)
+++ subversion/libsvn_fs_fs/tree.c (working copy)
@@ -1078,303 +1078,6 @@
   return SVN_NO_ERROR;
 }
 
-/* #define SQLITE3_DEBUG 1 */
-#ifdef SQLITE3_DEBUG
-static void
-sqlite_tracer(void *data, const char *sql)
-{
- /* sqlite3 *db = data; */
- fprintf(stderr, "SQLITE SQL is \"%s\"\n", sql);
-}
-#endif
-
-/* We want to cache that we saw no mergeinfo for a path as well,
- so we use a -1 converted to a pointer to represent this. */
-#define NEGATIVE_CACHE_RESULT ((void *)(-1))
-
-/* Helper for get_merge_info that retrieves merge info for a single
- revision from the database and puts it into a mergeinfo hash. */
-static svn_error_t *
-parse_mergeinfo_from_db(sqlite3 *db,
- const char *path,
- svn_revnum_t rev,
- apr_hash_t **result,
- apr_pool_t *pool)
-{
- sqlite3_stmt *stmt;
- sqlite_int64 lastchanged_rev;
- int sqlite_result;
-
- SQLITE_ERR(sqlite3_prepare(db, "SELECT MAX(revision) from mergeinfo_changed"
- " where path = ? and revision <= ?;",
- -1, &stmt, NULL), db);
- SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 2, rev), db);
- sqlite_result = sqlite3_step(stmt);
- if (sqlite_result != SQLITE_ROW)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(db));
-
- lastchanged_rev = sqlite3_column_int64(stmt, 0);
-
- SQLITE_ERR(sqlite3_finalize(stmt), db);
-
- SQLITE_ERR(sqlite3_prepare(db,
- "SELECT mergedfrom, mergedrevstart,"
- "mergedrevend from mergeinfo "
- "where mergedto = ? and revision = ? "
- "group by mergedfrom;",
- -1, &stmt, NULL), db);
- SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 2, lastchanged_rev), db);
- sqlite_result = sqlite3_step(stmt);
-
- /* It is possible the mergeinfo changed because of a delete, and
- that the mergeinfo is now gone. If this is the case, we want
- to do nothing but fallthrough into the count == 0 case */
- if (sqlite_result == SQLITE_DONE)
- {
- *result = NULL;
- return SVN_NO_ERROR;
- }
- else if (sqlite_result == SQLITE_ROW)
- {
- apr_array_header_t *pathranges;
- const char *mergedfrom;
- svn_revnum_t startrev;
- svn_revnum_t endrev;
- const char *lastmergedfrom = NULL;
-
- *result = apr_hash_make(pool);
- pathranges = apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
-
- while (sqlite_result == SQLITE_ROW)
- {
- svn_merge_range_t *temprange;
-
- mergedfrom = (char *) sqlite3_column_text(stmt, 0);
- startrev = sqlite3_column_int64(stmt, 1);
- endrev = sqlite3_column_int64(stmt, 2);
- if (lastmergedfrom && strcmp(mergedfrom, lastmergedfrom) != 0)
- {
- apr_hash_set(*result, mergedfrom, APR_HASH_KEY_STRING,
- pathranges);
- pathranges = apr_array_make(pool, 1,
- sizeof(svn_merge_range_t *));
- }
- temprange = apr_pcalloc(pool, sizeof(*temprange));
- temprange->start = startrev;
- temprange->end = endrev;
- APR_ARRAY_PUSH(pathranges, svn_merge_range_t *) = temprange;
- sqlite_result = sqlite3_step(stmt);
- lastmergedfrom = mergedfrom;
- }
- apr_hash_set(*result, mergedfrom, APR_HASH_KEY_STRING, pathranges);
-
- if (sqlite_result != SQLITE_DONE)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(db));
- }
- else
- {
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(db));
- }
- SQLITE_ERR(sqlite3_finalize(stmt), db);
-
- return SVN_NO_ERROR;
-}
-
-/* Helper for get_merge_info_for_path that will append a string to each
- path that exists in the mergeinfo hash. */
-static svn_error_t *
-append_component_to_paths(apr_hash_t **output,
- apr_hash_t *input,
- const char *toappend,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
- *output = apr_hash_make(pool);
-
- for (hi = apr_hash_first(pool, input);
- hi;
- hi = apr_hash_next(hi))
- {
- const void *key;
- void *val;
- apr_ssize_t klen;
- char *newpath;
-
- apr_hash_this(hi, &key, &klen, &val);
- newpath = svn_path_join((const char *)key, toappend, pool);
- apr_hash_set(*output, newpath, APR_HASH_KEY_STRING, val);
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Helper for get_merge_info that will recursively get merge info for
- a single path. */
-static svn_error_t *
-get_merge_info_for_path(sqlite3 *db,
- const char *path,
- svn_revnum_t rev,
- apr_hash_t *result,
- apr_hash_t *cache,
- svn_boolean_t setresult,
- svn_boolean_t include_parents,
- apr_pool_t *pool)
-{
- apr_hash_t *cacheresult;
- sqlite3_stmt *stmt;
- int sqlite_result;
- sqlite_int64 count;
- svn_boolean_t has_no_mergeinfo = FALSE;
-
- cacheresult = apr_hash_get(cache, path, APR_HASH_KEY_STRING);
- if (cacheresult != 0)
- {
- if (cacheresult != NEGATIVE_CACHE_RESULT && setresult)
- apr_hash_set(result, path, APR_HASH_KEY_STRING, cacheresult);
- return SVN_NO_ERROR;
- }
-
- /* See if we have a mergeinfo_changed record for this path. If not,
- then it can't have mergeinfo. */
- SQLITE_ERR(sqlite3_prepare(db, "SELECT COUNT(*) from mergeinfo_changed"
- " where path = ? and revision <= ?;",
- -1, &stmt, NULL), db);
-
- SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT), db);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 2, rev), db);
- sqlite_result = sqlite3_step(stmt);
- if (sqlite_result != SQLITE_ROW)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(db));
-
- count = sqlite3_column_int64(stmt, 0);
- SQLITE_ERR(sqlite3_finalize(stmt), db);
-
- /* If we've got mergeinfo data, transform it from the db into a
- mergeinfo hash */
- if (count > 0)
- {
- apr_hash_t *pathresult = NULL;
-
- SVN_ERR(parse_mergeinfo_from_db(db, path, rev, &pathresult, pool));
- if (pathresult)
- {
- if (setresult)
- apr_hash_set(result, path, APR_HASH_KEY_STRING, pathresult);
- apr_hash_set(cache, path, APR_HASH_KEY_STRING, pathresult);
- }
- }
-
- /* If this path has no mergeinfo, and we are asked to, check our parent */
- if ((count == 0 || has_no_mergeinfo) && include_parents)
- {
- svn_stringbuf_t *parentpath;
-
- apr_hash_set(cache, path, APR_HASH_KEY_STRING, NEGATIVE_CACHE_RESULT);
-
- /* It is possible we are already at the root. */
- if (strcmp(path, "") == 0)
- return SVN_NO_ERROR;
-
- parentpath = svn_stringbuf_create(path, pool);
- svn_path_remove_component(parentpath);
-
- /* The repository, and the mergeinfo index, internally refer to
- "/" as "" */
- if (strcmp(parentpath->data, "/") == 0)
- parentpath->data = "";
-
- SVN_ERR(get_merge_info_for_path(db, parentpath->data, rev,
- result, cache, FALSE, include_parents,
- pool));
- if (setresult)
- {
- /* Now translate the result for our parent to our path */
- cacheresult = apr_hash_get(cache, parentpath->data,
- APR_HASH_KEY_STRING);
- if (cacheresult == NEGATIVE_CACHE_RESULT)
- apr_hash_set(result, path, APR_HASH_KEY_STRING, NULL);
- else if (cacheresult)
- {
- const char *p;
- int i;
- apr_hash_t *translatedhash;
- char *toappend;
-
- /* We want to append from the part after the / to the end of the
- path string. */
- toappend = apr_pcalloc(pool,
- (strlen(path) - parentpath->len) + 1);
- for (i = 0, p = &path[parentpath->len + 1]; *p; i++, p++)
- *(toappend + i) = *p;
- append_component_to_paths(&translatedhash, cacheresult,
- toappend, pool);
- apr_hash_set(result, path, APR_HASH_KEY_STRING,
- translatedhash);
- }
- }
- }
- return SVN_NO_ERROR;
-}
-
-
-/* Get the merge info for a set of paths. */
-static svn_error_t *
-fs_get_merge_info(apr_hash_t **mergeinfo,
- svn_fs_root_t *root,
- const apr_array_header_t *paths,
- svn_boolean_t include_parents,
- apr_pool_t *pool)
-{
- apr_hash_t *mergeinfo_cache = apr_hash_make (pool);
- sqlite3 *db;
- int i;
- svn_revnum_t rev;
-
- /* We require a revision root. */
- if (root->is_txn_root)
- return svn_error_create(SVN_ERR_FS_NOT_REVISION_ROOT, NULL, NULL);
- rev = svn_fs_revision_root_revision(root);
-
- SQLITE_ERR(sqlite3_open(svn_path_join(root->fs->path, "mergeinfo.db", pool),
- &db), db);
-#ifdef SQLITE3_DEBUG
- sqlite3_trace (db, sqlite_tracer, db);
-#endif
-
- *mergeinfo = apr_hash_make (pool);
- for (i = 0; i < paths->nelts; i++)
- {
- const char *path = APR_ARRAY_IDX(paths, i, const char *);
-
- SVN_ERR (get_merge_info_for_path (db, path, rev, *mergeinfo,
- mergeinfo_cache, TRUE,
- include_parents, pool));
- }
-
- for (i = 0; i < paths->nelts; i++)
- {
- svn_stringbuf_t *mergestring;
- apr_hash_t *currhash;
- const char *path = APR_ARRAY_IDX(paths, i, const char *);
-
- currhash = apr_hash_get(*mergeinfo, path, APR_HASH_KEY_STRING);
- if (currhash)
- {
- SVN_ERR (svn_mergeinfo_sort(currhash, pool));
- SVN_ERR (svn_mergeinfo_to_string(&mergestring, currhash, pool));
- apr_hash_set(*mergeinfo, path, APR_HASH_KEY_STRING, mergestring->data);
- }
- }
- SQLITE_ERR(sqlite3_close(db), db);
- return SVN_NO_ERROR;
-}
-
 /* Change the merge info for a given path. */
 static svn_error_t *
 fs_change_merge_info(svn_fs_root_t *root,
@@ -3522,8 +3225,7 @@
   fs_contents_changed,
   fs_get_file_delta_stream,
   fs_merge,
- fs_change_merge_info,
- fs_get_merge_info
+ fs_change_merge_info
 };
 
 /* Construct a new root object in FS, allocated from POOL. */
Index: subversion/libsvn_fs_fs/fs_fs.c
===================================================================
--- subversion/libsvn_fs_fs/fs_fs.c (revision 20955)
+++ subversion/libsvn_fs_fs/fs_fs.c (working copy)
@@ -28,8 +28,6 @@
 #include <apr_md5.h>
 #include <apr_thread_mutex.h>
 
-#include <sqlite3.h>
-
 #include "svn_pools.h"
 #include "svn_fs.h"
 #include "svn_path.h"
@@ -130,7 +128,8 @@
   svn_fs_fs__txn_prop,
   svn_fs_fs__txn_proplist,
   svn_fs_fs__change_txn_prop,
- svn_fs_fs__txn_root
+ svn_fs_fs__txn_root,
+ svn_fs_fs__txn_mergeinfo
 };
 
 /* Pathname helper functions */
@@ -303,16 +302,6 @@
   return SVN_NO_ERROR;
 }
 
-/*#define SQLITE3_DEBUG 1 */
-#ifdef SQLITE3_DEBUG
-static void
-sqlite_tracer (void *data, const char *sql)
-{
- /* sqlite3 *db = data; */
- fprintf (stderr, "SQLITE SQL is \"%s\"\n", sql);
-}
-#endif
-
 svn_error_t *
 svn_fs_fs__open(svn_fs_t *fs, const char *path, apr_pool_t *pool)
 {
@@ -2544,7 +2533,6 @@
 {
   svn_fs_txn_t *txn;
   svn_fs_id_t *root_id;
- fs_txn_data_t *ftd;
 
   txn = apr_pcalloc(pool, sizeof(*txn));
 
@@ -2555,8 +2543,6 @@
   txn->base_rev = rev;
 
   txn->vtable = &txn_vtable;
- ftd = apr_pcalloc(pool, sizeof(*ftd));
- txn->fsap_data = ftd;
   *txn_p = txn;
   
   /* Create a new root node for this transaction. */
@@ -3989,118 +3975,6 @@
   return SVN_NO_ERROR;
 }
 
-/* Create SQL to insert the necessary indexing data for all the merge
- info lists of PATH, which is provided (unparsed) in MINFOSTRING. */
-static svn_error_t *
-index_path_merge_info(svn_fs_txn_t *txn, svn_revnum_t new_rev,
- const char *path, svn_string_t *minfostring,
- apr_pool_t *pool)
-{
- apr_hash_t *minfo;
- apr_hash_index_t *hi;
- sqlite3_stmt *stmt;
- fs_txn_data_t *ftd;
-
- ftd = txn->fsap_data;
-
- SVN_ERR(svn_mergeinfo_parse(minfostring->data, &minfo, pool));
-
- for (hi = apr_hash_first(pool, minfo);
- hi != NULL;
- hi = apr_hash_next(hi))
- {
- const char *from;
- apr_array_header_t *revlist;
- const void *key;
- void *val;
-
- apr_hash_this(hi, &key, NULL, &val);
-
- from = key;
- revlist = val;
-
- if (from && revlist)
- {
- int i;
- for (i = 0; i < revlist->nelts; i++)
- {
- svn_merge_range_t *range;
-
- range = APR_ARRAY_IDX(revlist, i, svn_merge_range_t *);
- SQLITE_ERR(sqlite3_prepare(ftd->mtd,
- "INSERT INTO mergeinfo (revision, mergedto, mergedfrom, mergedrevstart, mergedrevend) VALUES (?, ?, ?, ?, ?);",
- -1, &stmt, NULL), ftd->mtd);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev),
- ftd->mtd);
- SQLITE_ERR(sqlite3_bind_text(stmt, 2, path, -1, SQLITE_TRANSIENT),
- ftd->mtd);
- SQLITE_ERR(sqlite3_bind_text(stmt, 3, from, -1, SQLITE_TRANSIENT),
- ftd->mtd);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 4, range->start),
- ftd->mtd);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 5, range->end),
- ftd->mtd);
- if (sqlite3_step(stmt) != SQLITE_DONE)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(ftd->mtd));
-
- SQLITE_ERR(sqlite3_finalize(stmt), ftd->mtd);
- }
- }
- }
- SQLITE_ERR (sqlite3_prepare(ftd->mtd,
- "INSERT INTO mergeinfo_changed (revision, path) VALUES (?, ?);",
- -1, &stmt, NULL),
- ftd->mtd);
- SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev), ftd->mtd);
-
- SQLITE_ERR(sqlite3_bind_text(stmt, 2, path, -1, SQLITE_TRANSIENT),
- ftd->mtd);
-
- if (sqlite3_step(stmt) != SQLITE_DONE)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- sqlite3_errmsg(ftd->mtd));
-
- SQLITE_ERR(sqlite3_finalize(stmt), ftd->mtd);
-
- return SVN_NO_ERROR;
-}
-
-/* Create the index for any merge info in TXN (a no-op if TXN has no
- associated merge info). */
-static svn_error_t *
-index_txn_merge_info(svn_fs_txn_t *txn, svn_revnum_t new_rev,
- apr_pool_t *pool)
-{
- apr_hash_t *minfoprops;
-
- SVN_ERR(svn_fs_fs__txn_mergeinfo(&minfoprops, txn, pool));
- if (minfoprops)
- {
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first(pool, minfoprops);
- hi != NULL;
- hi = apr_hash_next(hi))
- {
- const char *minfopath;
- svn_string_t *minfostring;
- const void *key;
- void *val;
-
- apr_hash_this(hi, &key, NULL, &val);
-
- minfopath = key;
- minfostring = val;
-
- SVN_ERR(index_path_merge_info(txn, new_rev, minfopath, minfostring,
- pool));
- }
- }
-
- return SVN_NO_ERROR;
-}
-
 /* Baton used for commit_body below. */
 struct commit_baton {
   svn_revnum_t *new_rev_p;
@@ -4108,50 +3982,6 @@
   svn_fs_txn_t *txn;
 };
 
-/* Clean the merge info index for any previous failed commit with the
- revision number as NEW_REV, and if the current transaction contains
- merge info, record it. */
-static svn_error_t *
-update_merge_info_index(struct commit_baton *cb, svn_revnum_t new_rev,
- svn_boolean_t txn_contains_merge_info,
- apr_pool_t *pool)
-{
- const char *deletestring;
- fs_txn_data_t *ftd = cb->txn->fsap_data;
-
- SQLITE_ERR(sqlite3_open(path_mergeinfo_db(cb->fs, pool),
- &ftd->mtd), ftd->mtd);
-#ifdef SQLITE3_DEBUG
- sqlite3_trace (ftd->mtd, sqlite_tracer, ftd->mtd);
-#endif
- SVN_ERR(fs_sqlite_exec(ftd->mtd, "begin transaction;", NULL, NULL));
-
- /* Cleanup the leftovers of any previous, failed FSFS transactions
- involving NEW_REV. */
- deletestring = apr_psprintf(pool,
- "delete from mergeinfo_changed where revision = %ld;",
- new_rev);
- SVN_ERR(fs_sqlite_exec(ftd->mtd, deletestring, NULL, NULL));
- deletestring = apr_psprintf(pool,
- "delete from mergeinfo where revision = %ld;",
- new_rev);
- SVN_ERR(fs_sqlite_exec(ftd->mtd, deletestring, NULL, NULL));
-
- /* Record any merge info from the current transaction. */
- if (txn_contains_merge_info)
- SVN_ERR(index_txn_merge_info(cb->txn, new_rev, pool));
-
- /* This is moved here from commit_txn, because we don't want to
- write the final current file if the sqlite commit fails.
- On the other hand, if we commit the transaction and end up failing
- the current file, we just end up with inaccessible data in the
- database, not a real problem. */
- SVN_ERR(fs_sqlite_exec(ftd->mtd, "commit transaction;", NULL, NULL));
- SQLITE_ERR(sqlite3_close(ftd->mtd), ftd->mtd);
-
- return SVN_NO_ERROR;
-}
-
 /* The work-horse for svn_fs_fs__commit, called with the FS write lock.
    This implements the svn_fs_fs__with_write_lock() 'body' callback
    type. BATON is a 'struct commit_baton *'. */
@@ -4269,8 +4099,8 @@
   SVN_ERR(svn_fs_fs__move_into_place(revprop_filename, final_revprop,
                                      old_rev_filename, pool));
   
- SVN_ERR(update_merge_info_index(cb, new_rev, txn_contains_merge_info, pool));
-
+ svn_fs_util_mtd_update_merge_info_index(cb->txn, new_rev,
+ txn_contains_merge_info, pool);
   /* Update the 'current' file. */
   SVN_ERR(write_final_current(cb->fs, cb->txn->id, new_rev, start_node_id,
                               start_copy_id, pool));
@@ -4348,41 +4178,7 @@
   return svn_fs_fs__set_revision_proplist(fs, 0, proplist, fs->pool);
 }
 
-/* Execute SQL on the sqlite database, and raise an SVN error if the
- result is not okay. */
-
 svn_error_t *
-fs_sqlite_exec (sqlite3 *db, const char *sql,
- sqlite3_callback callback,
- void *callbackdata)
-{
- char *errmsg;
- if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
- errmsg);
- return SVN_NO_ERROR;
-}
-
-const char SVN_MTD_CREATE_SQL[] = "pragma auto_vacuum = 1;"
- APR_EOL_STR
- "create table mergeinfo (revision integer not null, mergedfrom text not null, mergedto text not null, mergedrevstart integer not null, mergedrevend integer not null);"
- APR_EOL_STR
- "create index mi_mergedfrom_idx on mergeinfo (mergedfrom);"
- APR_EOL_STR
- "create index mi_mergedto_idx on mergeinfo (mergedto);"
- APR_EOL_STR
- "create index mi_revision_idx on mergeinfo (revision);"
- APR_EOL_STR
- "create table mergeinfo_changed (revision integer not null, path text not null);"
- APR_EOL_STR
- "create unique index mi_c_revpath_idx on mergeinfo_changed (revision, path);"
- APR_EOL_STR
- "create index mi_c_path_idx on mergeinfo_changed (path);"
- APR_EOL_STR
- "create index mi_c_revision_idx on mergeinfo_changed (revision);"
- APR_EOL_STR;
-
-svn_error_t *
 svn_fs_fs__create(svn_fs_t *fs,
                   const char *path,
                   apr_pool_t *pool)
@@ -4392,13 +4188,6 @@
 
   fs->path = apr_pstrdup(pool, path);
 
- SQLITE_ERR(sqlite3_open(path_mergeinfo_db(fs, pool), &ffd->mtd),
- ffd->mtd);
-#ifdef SQLITE3_DEBUG
- sqlite3_trace (ffd->mtd, sqlite_tracer, ffd->mtd);
-#endif
- SVN_ERR(fs_sqlite_exec(ffd->mtd, SVN_MTD_CREATE_SQL, NULL, NULL));
-
   SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_REVS_DIR,
                                                     pool),
                                       pool));
@@ -4425,10 +4214,6 @@
           (path_format(fs, pool), format, pool));
   ((fs_fs_data_t *) fs->fsap_data)->format = format;
   
- SQLITE_ERR(sqlite3_close(ffd->mtd), ffd->mtd);
-
- ffd->mtd = NULL;
-
   return SVN_NO_ERROR;
 }
 
@@ -4525,7 +4310,6 @@
   svn_fs_txn_t *txn;
   svn_node_kind_t kind;
   transaction_t *local_txn;
- fs_txn_data_t *ftd;
 
   /* First check to see if the directory exists. */
   SVN_ERR(svn_io_check_path(path_txn_dir(fs, name, pool), &kind, pool));
@@ -4546,8 +4330,6 @@
   txn->base_rev = svn_fs_fs__id_rev(local_txn->base_id);
 
   txn->vtable = &txn_vtable;
- ftd = apr_pcalloc(pool, sizeof(*ftd));
- txn->fsap_data = ftd;
   *txn_p = txn;
 
   return SVN_NO_ERROR;
Index: subversion/libsvn_fs_fs/fs.h
===================================================================
--- subversion/libsvn_fs_fs/fs.h (revision 20955)
+++ subversion/libsvn_fs_fs/fs.h (working copy)
@@ -22,7 +22,6 @@
 #include <apr_hash.h>
 #include <apr_md5.h>
 #include <apr_thread_mutex.h>
-#include <sqlite3.h>
 
 #include "svn_fs.h"
 
@@ -54,9 +53,6 @@
   apr_hash_t *dir_cache[NUM_DIR_CACHE_ENTRIES];
   apr_pool_t *dir_cache_pool[NUM_DIR_CACHE_ENTRIES];
 
- /* Merge tracking database. */
- sqlite3 *mtd;
-
   /* The format number of this FS. */
   int format;
 
@@ -71,14 +67,6 @@
 #endif
 } fs_fs_data_t;
 
-/* Transactions need their own private opened copy of the mergeinfo
- database so that their sql commands are not shared between each other. */
-typedef struct
-{
- /* Merge tracking database. */
- sqlite3 *mtd;
-} fs_txn_data_t;
-
 /* Return a canonicalized version of a filesystem PATH, allocated in
    POOL. While the filesystem API is pretty flexible about the
    incoming paths (they must be UTF-8 with '/' as separators, but they
@@ -205,23 +193,6 @@
 
 } change_t;
 
-/* Wrapper for sqlite_exec that returns an SVN error on errors.
- Parameters match those of sqlite_exec, meaning that DB is the
- database to operate on, SQL is the string of sql to submit, CB is
- the callback to call with the results, and DATA is the first
- argument given to callback. */
-svn_error_t *fs_sqlite_exec(sqlite3 *db , const char *sql,
- sqlite3_callback cb, void *data);
-
-/* SQLITE->SVN quick error wrap, much like SVN_ERR.
- XXX: This macro probably belongs elsehwere, like svn_sqlite.h or
- something. Later. */
-#define SQLITE_ERR(x, db) do \
-{ \
- if ((x) != SQLITE_OK) \
- return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL, \
- sqlite3_errmsg((db))); \
- } while (0)
 
 #ifdef __cplusplus
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Aug 17 15:54:58 2006

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.