From 272e1ce71111510cca5415c1c510b4b21638a0c3 Mon Sep 17 00:00:00 2001 From: glasser Date: Fri, 25 Jan 2008 01:34:11 +0000 Subject: [PATCH] Use a single directory for the FSFS node origin cache instead of a sqlite database. Perhaps this should be sharded. (However, my only concern here is "too many files in one directory", not "too many small files": there'll only be one file here per file ever made in the repository, so it'll take up no more space than a checkout of one branch of all projects.) (Technically, the node_origins table is still created in sqlite-util.c, but that whole file is getting the wrecking ball soon.) * subversion/include/private/svn_fs_node_origins.h * subversion/libsvn_fs_util/node-origins-sqlite-index.c Delete. * subversion/libsvn_fs_fs/fs.h (PATH_NODE_ORIGINS_DIR): New. * subversion/libsvn_fs_fs/fs_fs.c (): Don't include svn_fs_node_origins.h (path_node_origins): New. (svn_fs_fs_hotcopy): Copy cache. (svn_fs_fs__commit): Call FSFS function instead of sqlite function. (svn_fs_fs__ensure_dir_exists): Moved from ensure_dir_exists in lock.c. (svn_fs_fs__get_node_origin, set_node_origin, svn_fs_fs__set_node_origins, svn_fs_fs__set_node_origin): New. * subversion/libsvn_fs_fs/fs_fs.h (svn_fs_fs__get_node_origin, svn_fs_fs__set_node_origins, svn_fs_fs__set_node_origin): Declare. * subversion/libsvn_fs_fs/lock.c (ensure_dir_exists): Move to fs_fs.c and make libsvn_fs_fs-global. (write_digest_file): Adjust. * subversion/libsvn_fs_fs/structure Document node-origins cache. * subversion/libsvn_fs_fs/tree.c (): Don't include svn_fs_node_origins.h. (fs_node_origin_rev): Call FSFS functions instead of sqlite functions. git-svn-id: http://svn.collab.net/repos/svn/trunk@29018 612f8ebc-c883-4be0-9ee0-a4e9ef946e3a --- subversion/include/private/svn_fs_node_origins.h | 75 -------- subversion/libsvn_fs_fs/fs.h | 1 + subversion/libsvn_fs_fs/fs_fs.c | 158 ++++++++++++++++- subversion/libsvn_fs_fs/fs_fs.h | 42 +++++ subversion/libsvn_fs_fs/lock.c | 30 +--- subversion/libsvn_fs_fs/structure | 7 + subversion/libsvn_fs_fs/tree.c | 22 +-- .../libsvn_fs_util/node-origins-sqlite-index.c | 194 --------------------- 8 files changed, 219 insertions(+), 310 deletions(-) delete mode 100644 subversion/include/private/svn_fs_node_origins.h delete mode 100644 subversion/libsvn_fs_util/node-origins-sqlite-index.c diff --git a/subversion/include/private/svn_fs_node_origins.h b/subversion/include/private/svn_fs_node_origins.h deleted file mode 100644 index f13181b45..000000000 --- a/subversion/include/private/svn_fs_node_origins.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * svn_fs_node_origins.h: Declarations for APIs of libsvn_fs_util to - * be consumed by only fs_* libs; access to the node origin index. - * - * ==================================================================== - * Copyright (c) 2007 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/. - * ==================================================================== - */ - -#ifndef SVN_FS_NODE_ORIGINS_H -#define SVN_FS_NODE_ORIGINS_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* The node origin table is a cache of immutable data to assist - * svn_fs_node_origin_rev. Because both FS backends implement - * svn_fs_id_t as a structure where objects on the same line of - * history have a "Node ID" in common, we can cache responses to - * svn_fs_node_origin_rev based on the "Node ID". */ - - -/* Update the node origin index for FS based on the hash - NODE_ORIGIN_FOR_PATHS, which maps from const char * "Node IDs" to - const svn_fs_id_t * node-rev-ids. Returns an error if any cache - entry exists with a different value; pre-existing entries with the - same value are ignored. Use POOL for any temporary allocations. - - Because this is just an "optional" cache, this function does not - return an error if the underlying storage is readonly; it still - returns an error for other error conditions. - */ -svn_error_t * -svn_fs__set_node_origins(svn_fs_t *fs, - apr_hash_t *node_origins, - apr_pool_t *pool); - -/* Shorthand for calling svn_fs__set_node_origins with just one pair. - */ -svn_error_t * -svn_fs__set_node_origin(svn_fs_t *fs, - const char *node_id, - const svn_fs_id_t *node_rev_id, - apr_pool_t *pool); - -/* Set *ORIGIN_ID to the node revision ID from which the history of - all nodes in FS whose "Node ID" is NODE_ID springs, as determined - by a look in the index. ORIGIN_ID needs to be parsed in an - FS-backend-specific way. Use POOL for allocations. - - If there is no entry for NODE_ID in the cache, return NULL - in *ORIGIN_ID. - SVN_ERR_FS_NO_SUCH_NODE_ORIGIN. */ -svn_error_t * -svn_fs__get_node_origin(const char **origin_id, - svn_fs_t *fs, - const char *node_id, - apr_pool_t *pool); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* SVN_FS_NODE_ORIGINS_H */ diff --git a/subversion/libsvn_fs_fs/fs.h b/subversion/libsvn_fs_fs/fs.h index 1a4c78fa0..d8c8e1885 100644 --- a/subversion/libsvn_fs_fs/fs.h +++ b/subversion/libsvn_fs_fs/fs.h @@ -45,6 +45,7 @@ extern "C" { #define PATH_REVS_DIR "revs" /* Directory of revisions */ #define PATH_REVPROPS_DIR "revprops" /* Directory of revprops */ #define PATH_TXNS_DIR "transactions" /* Directory of transactions */ +#define PATH_NODE_ORIGINS_DIR "node-origins" /* Lazy node-origin cache */ #define PATH_TXN_PROTOS_DIR "txn-protorevs" /* Directory of proto-revs */ #define PATH_TXN_CURRENT "txn-current" /* File with next txn key */ #define PATH_TXN_CURRENT_LOCK "txn-current-lock" /* Lock for txn-current */ diff --git a/subversion/libsvn_fs_fs/fs_fs.c b/subversion/libsvn_fs_fs/fs_fs.c index f80a8eade..3f57c82a0 100644 --- a/subversion/libsvn_fs_fs/fs_fs.c +++ b/subversion/libsvn_fs_fs/fs_fs.c @@ -50,7 +50,6 @@ #include "private/svn_fs_sqlite.h" #include "private/svn_fs_mergeinfo.h" -#include "private/svn_fs_node_origins.h" #include "private/svn_fs_util.h" #include "../libsvn_fs/fs-loader.h" @@ -306,6 +305,12 @@ path_txn_node_children(svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool) PATH_EXT_CHILDREN, NULL); } +static APR_INLINE const char * +path_node_origin(svn_fs_t *fs, const char *node_id, apr_pool_t *pool) +{ + return svn_path_join_many(pool, fs->path, PATH_NODE_ORIGINS_DIR, + node_id, NULL); +} /* Functions for working with shared transaction data. */ @@ -1207,6 +1212,14 @@ svn_fs_fs__hotcopy(const char *src_path, PATH_LOCKS_DIR, TRUE, NULL, NULL, pool)); + /* Now copy the node-origins cache tree. */ + src_subdir = svn_path_join(src_path, PATH_NODE_ORIGINS_DIR, pool); + SVN_ERR(svn_io_check_path(src_subdir, &kind, pool)); + if (kind == svn_node_dir) + SVN_ERR(svn_io_copy_dir_recursively(src_subdir, dst_path, + PATH_NODE_ORIGINS_DIR, TRUE, NULL, + NULL, pool)); + /* Copy the txn-current file. */ if (format >= SVN_FS_FS__MIN_TXN_CURRENT_FORMAT) SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_TXN_CURRENT, pool)); @@ -5163,7 +5176,7 @@ svn_fs_fs__commit(svn_revnum_t *new_rev_p, /* Now that we're no longer locked, we can update the node-origins cache without blocking writers. */ if (apr_hash_count(node_origins) > 0) - SVN_ERR(svn_fs__set_node_origins(fs, node_origins, pool)); + SVN_ERR(svn_fs_fs__set_node_origins(fs, node_origins, pool)); return SVN_NO_ERROR; } @@ -5646,6 +5659,147 @@ svn_fs_fs__set_uuid(svn_fs_t *fs, return SVN_NO_ERROR; } +/** Node origin lazy cache. */ + +/* If directory PATH does not exist, create it and give it the same + permissions as FS->path.*/ +svn_error_t * +svn_fs_fs__ensure_dir_exists(const char *path, + svn_fs_t *fs, + apr_pool_t *pool) +{ + svn_error_t *err = svn_io_dir_make(path, APR_OS_DEFAULT, pool); + if (err && APR_STATUS_IS_EEXIST(err->apr_err)) + { + svn_error_clear(err); + return SVN_NO_ERROR; + } + SVN_ERR(err); + + /* We successfully created a new directory. Dup the permissions + from FS->path. */ + SVN_ERR(svn_fs_fs__dup_perms(path, fs->path, pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__get_node_origin(const svn_fs_id_t **origin_id, + svn_fs_t *fs, + const char *node_id, + apr_pool_t *pool) +{ + apr_file_t *fd; + svn_stringbuf_t *origin_stringbuf; + svn_error_t *err; + + err = svn_io_file_open(&fd, path_node_origin(fs, node_id, pool), + APR_READ, APR_OS_DEFAULT, pool); + if (err && APR_STATUS_IS_ENOENT(err->apr_err)) + { + svn_error_clear(err); + return SVN_NO_ERROR; + } + SVN_ERR(err); + + SVN_ERR(svn_stringbuf_from_aprfile(&origin_stringbuf, fd, pool)); + + *origin_id = svn_fs_fs__id_parse(origin_stringbuf->data, + origin_stringbuf->len, pool); + + SVN_ERR(svn_io_file_close(fd, pool)); + + return SVN_NO_ERROR; +} + +/* Helper for svn_fs_fs__set_node_origin[s]. Exactly like + svn_fs_fs__set_node_origin, except that it throws an error if the + file can't be written. */ +static svn_error_t * +set_node_origin(svn_fs_t *fs, + const char *node_id, + const svn_fs_id_t *node_rev_id, + apr_pool_t *pool) +{ + apr_file_t *file; + svn_string_t *node_rev_id_string; + + SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_path_join(fs->path, + PATH_NODE_ORIGINS_DIR, + pool), + fs, pool)); + + node_rev_id_string = svn_fs_fs__id_unparse(node_rev_id, pool); + + SVN_ERR(svn_io_file_open(&file, path_node_origin(fs, node_id, pool), + APR_WRITE | APR_CREATE | APR_TRUNCATE + | APR_BUFFERED, APR_OS_DEFAULT, pool)); + SVN_ERR(svn_io_file_write_full(file, + node_rev_id_string->data, + node_rev_id_string->len, NULL, pool)); + SVN_ERR(svn_io_file_close(file, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_fs_fs__set_node_origins(svn_fs_t *fs, + apr_hash_t *node_origins, + apr_pool_t *pool) +{ + apr_hash_index_t *hi; + apr_pool_t *iterpool = svn_pool_create(pool); + + for (hi = apr_hash_first(pool, node_origins); + hi != NULL; + hi = apr_hash_next(hi)) + { + const void *key; + void *val; + const char *node_id; + const svn_fs_id_t *node_rev_id; + svn_error_t *err; + + svn_pool_clear(iterpool); + + apr_hash_this(hi, &key, NULL, &val); + node_id = key; + node_rev_id = val; + + err = set_node_origin(fs, node_id, node_rev_id, iterpool); + if (err && APR_STATUS_IS_EACCES(err->apr_err)) + { + /* It's just a cache; stop trying if I can't write. */ + svn_error_clear(err); + err = NULL; + goto cleanup; + } + SVN_ERR(err); + } + + cleanup: + svn_pool_destroy(iterpool); + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__set_node_origin(svn_fs_t *fs, + const char *node_id, + const svn_fs_id_t *node_rev_id, + apr_pool_t *pool) +{ + svn_error_t *err = set_node_origin(fs, node_id, node_rev_id, pool); + if (err && APR_STATUS_IS_EACCES(err->apr_err)) + { + /* It's just a cache; stop trying if I can't write. */ + svn_error_clear(err); + err = NULL; + } + return err; +} + + svn_error_t * svn_fs_fs__list_transactions(apr_array_header_t **names_p, svn_fs_t *fs, diff --git a/subversion/libsvn_fs_fs/fs_fs.h b/subversion/libsvn_fs_fs/fs_fs.h index 68161ed05..4d308be47 100644 --- a/subversion/libsvn_fs_fs/fs_fs.h +++ b/subversion/libsvn_fs_fs/fs_fs.h @@ -445,5 +445,47 @@ svn_error_t *svn_fs_fs__begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_error_t *svn_fs_fs__txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn, const char *propname, apr_pool_t *pool); +/* If directory PATH does not exist, create it and give it the same + permissions as FS->path.*/ +svn_error_t *svn_fs_fs__ensure_dir_exists(const char *path, + svn_fs_t *fs, + apr_pool_t *pool); + +/* Update the node origin index for FS based on the hash + NODE_ORIGIN_FOR_PATHS, which maps from const char * "Node IDs" to + const svn_fs_id_t * node-rev-ids. Returns an error if any cache + entry exists with a different value; pre-existing entries with the + same value are ignored. Use POOL for any temporary allocations. + + Because this is just an "optional" cache, this function does not + return an error if the underlying storage is readonly; it still + returns an error for other error conditions. + */ +svn_error_t * +svn_fs_fs__set_node_origins(svn_fs_t *fs, + apr_hash_t *node_origins, + apr_pool_t *pool); + +/* Shorthand for calling svn_fs_fs__set_node_origins with just one pair. + */ +svn_error_t * +svn_fs_fs__set_node_origin(svn_fs_t *fs, + const char *node_id, + const svn_fs_id_t *node_rev_id, + apr_pool_t *pool); + +/* Set *ORIGIN_ID to the node revision ID from which the history of + all nodes in FS whose "Node ID" is NODE_ID springs, as determined + by a look in the index. ORIGIN_ID needs to be parsed in an + FS-backend-specific way. Use POOL for allocations. + + If there is no entry for NODE_ID in the cache, return NULL + in *ORIGIN_ID. */ +svn_error_t * +svn_fs_fs__get_node_origin(const svn_fs_id_t **origin_id, + svn_fs_t *fs, + const char *node_id, + apr_pool_t *pool); + #endif diff --git a/subversion/libsvn_fs_fs/lock.c b/subversion/libsvn_fs_fs/lock.c index 9b621b942..2a9913ffe 100644 --- a/subversion/libsvn_fs_fs/lock.c +++ b/subversion/libsvn_fs_fs/lock.c @@ -135,29 +135,6 @@ digest_path_from_path(svn_fs_t *fs, } -/* If directory PATH does not exist, create it and give it the same - permissions as FS->path.*/ -static svn_error_t * -ensure_dir_exists(const char *path, - svn_fs_t *fs, - apr_pool_t *pool) -{ - svn_error_t *err = svn_io_dir_make(path, APR_OS_DEFAULT, pool); - if (err && APR_STATUS_IS_EEXIST(err->apr_err)) - { - svn_error_clear(err); - return SVN_NO_ERROR; - } - SVN_ERR(err); - - /* We successfully created a new directory. Dup the permissions - from FS->path. */ - SVN_ERR(svn_fs_fs__dup_perms(path, fs->path, pool)); - - return SVN_NO_ERROR; -} - - /* Write to DIGEST_PATH a representation of CHILDREN (which may be empty, if the versioned path in FS represented by DIGEST_PATH has no children) and LOCK (which may be NULL if that versioned path is @@ -175,9 +152,10 @@ write_digest_file(apr_hash_t *children, apr_hash_t *hash = apr_hash_make(pool); const char *tmp_path; - SVN_ERR(ensure_dir_exists(svn_path_join(fs->path, PATH_LOCKS_DIR, pool), - fs, pool)); - SVN_ERR(ensure_dir_exists(svn_path_dirname(digest_path, pool), fs, pool)); + SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_path_join(fs->path, PATH_LOCKS_DIR, + pool), fs, pool)); + SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_path_dirname(digest_path, pool), fs, + pool)); SVN_ERR(svn_io_open_unique_file2 (&fd, &tmp_path, digest_path, ".tmp", svn_io_file_del_none, pool)); diff --git a/subversion/libsvn_fs_fs/structure b/subversion/libsvn_fs_fs/structure index 4600d1949..1be55e4ca 100644 --- a/subversion/libsvn_fs_fs/structure +++ b/subversion/libsvn_fs_fs/structure @@ -47,6 +47,8 @@ repository) is: locks/ Subdirectory containing locks / Subdirectory named for first 3 letters of an MD5 digest File containing locks/children for path with + node-origins/ Lazy cache of origin noderevs for nodes + File containing noderev ID of origin of node current File specifying current revision and next node/copy id fs-type File identifying this filesystem as an FSFS filesystem write-lock Empty file, locked to serialise writers @@ -183,6 +185,11 @@ _1.0.t1 is not related to the ID _1.0.t2 even though they have the same node-ID, because temporary node-IDs are restricted in scope to the transactions they belong to. +There is a lazily created cache mapping from node-IDs to the full +node-revision ID where they are created. This is in the node-origins +directory; the file name is the node-ID and the contents is the +node-revision ID. + Copy-IDs and copy roots ----------------------- diff --git a/subversion/libsvn_fs_fs/tree.c b/subversion/libsvn_fs_fs/tree.c index 5667d62ec..e41cfc67b 100644 --- a/subversion/libsvn_fs_fs/tree.c +++ b/subversion/libsvn_fs_fs/tree.c @@ -53,7 +53,6 @@ #include "id.h" #include "private/svn_fs_mergeinfo.h" -#include "private/svn_fs_node_origins.h" #include "private/svn_mergeinfo_private.h" #include "private/svn_fs_util.h" #include "../libsvn_fs/fs-loader.h" @@ -3013,17 +3012,14 @@ fs_node_origin_rev(svn_revnum_t *revision, if (node_id[0] != '_') { - const char *cached_origin_id_str; - SVN_ERR(svn_fs__get_node_origin(&cached_origin_id_str, - fs, - node_id, - pool)); - if (cached_origin_id_str != NULL) + const svn_fs_id_t *cached_origin_id; + SVN_ERR(svn_fs_fs__get_node_origin(&cached_origin_id, + fs, + node_id, + pool)); + if (cached_origin_id != NULL) { - *revision = - svn_fs_fs__id_rev(svn_fs_fs__id_parse(cached_origin_id_str, - strlen(cached_origin_id_str), - pool)); + *revision = svn_fs_fs__id_rev(cached_origin_id); return SVN_NO_ERROR; } } @@ -3087,8 +3083,8 @@ fs_node_origin_rev(svn_revnum_t *revision, /* Wow, I don't want to have to do all that again. Let's cache the result. */ if (node_id[0] != '_') - SVN_ERR(svn_fs__set_node_origin(fs, node_id, - svn_fs_fs__dag_get_id(node), pool)); + SVN_ERR(svn_fs_fs__set_node_origin(fs, node_id, + svn_fs_fs__dag_get_id(node), pool)); svn_pool_destroy(subpool); svn_pool_destroy(predidpool); diff --git a/subversion/libsvn_fs_util/node-origins-sqlite-index.c b/subversion/libsvn_fs_util/node-origins-sqlite-index.c deleted file mode 100644 index aa275a0b5..000000000 --- a/subversion/libsvn_fs_util/node-origins-sqlite-index.c +++ /dev/null @@ -1,194 +0,0 @@ -/* node-origins-sqlite-index.c - * - * ==================================================================== - * Copyright (c) 2006-2007 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 -#include -#include -#include -#include - -#include -#include - -#include - -#include "svn_fs.h" -#include "svn_path.h" -#include "svn_pools.h" - -#include "private/svn_fs_sqlite.h" -#include "private/svn_fs_node_origins.h" -#include "../libsvn_fs/fs-loader.h" -#include "svn_private_config.h" - -#include "sqlite-util.h" - - -/* A flow-control helper macro for sending processing to the 'cleanup' - label when the local variable 'err' is not SVN_NO_ERROR. */ -#define MAYBE_CLEANUP if (err) goto cleanup - -static svn_error_t * -get_origin(const char **node_rev_id, - sqlite3 *db, - const char *node_id, - apr_pool_t *pool) -{ - svn_fs__sqlite_stmt_t *stmt; - svn_boolean_t got_row; - - SVN_ERR(svn_fs__sqlite_prepare(&stmt, db, - "SELECT node_rev_id FROM node_origins " - "WHERE node_id = ?", pool)); - SVN_ERR(svn_fs__sqlite_bind_text(stmt, 1, node_id)); - SVN_ERR(svn_fs__sqlite_step(&got_row, stmt)); - - *node_rev_id = got_row - ? apr_pstrdup(pool, svn_fs__sqlite_column_text(stmt, 0)) - : NULL; - - SVN_ERR(svn_fs__sqlite_finalize(stmt)); - - return SVN_NO_ERROR; -} - -static svn_error_t * -set_origin(sqlite3 *db, - const char *node_id, - const svn_string_t *node_rev_id, - apr_pool_t *pool) -{ - svn_fs__sqlite_stmt_t *stmt; - const char *old_node_rev_id; - - /* First figure out if it's already there. (Don't worry, we're in a - transaction.) */ - SVN_ERR(get_origin(&old_node_rev_id, db, node_id, pool)); - if (old_node_rev_id != NULL) - { - if (!strcmp(node_rev_id->data, old_node_rev_id)) - return SVN_NO_ERROR; - else - return svn_error_createf - (SVN_ERR_FS_CORRUPT, NULL, - _("Node origin for '%s' exists with a different " - "value (%s) than what we were about to store (%s)"), - node_id, old_node_rev_id, node_rev_id->data); - } - - SVN_ERR(svn_fs__sqlite_prepare(&stmt, db, - "INSERT INTO node_origins (node_id, " - "node_rev_id) VALUES (?, ?);", pool)); - SVN_ERR(svn_fs__sqlite_bind_text(stmt, 1, node_id)); - SVN_ERR(svn_fs__sqlite_bind_text(stmt, 2, node_rev_id->data)); - - SVN_ERR(svn_fs__sqlite_step_done(stmt)); - - SVN_ERR(svn_fs__sqlite_finalize(stmt)); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_fs__set_node_origins(svn_fs_t *fs, - apr_hash_t *node_origins, - apr_pool_t *pool) -{ - sqlite3 *db; - apr_hash_index_t *hi; - svn_error_t *err; - apr_pool_t *subpool = svn_pool_create(pool); - apr_pool_t *iterpool = svn_pool_create(subpool); - - SVN_ERR(svn_fs__sqlite_open(&db, fs->path, subpool)); - err = svn_fs__sqlite_exec(db, "BEGIN TRANSACTION;"); - MAYBE_CLEANUP; - - for (hi = apr_hash_first(subpool, node_origins); - hi != NULL; - hi = apr_hash_next(hi)) - { - const void *key; - void *val; - const char *node_id; - const svn_fs_id_t *node_rev_id; - - svn_pool_clear(iterpool); - - apr_hash_this(hi, &key, NULL, &val); - node_id = key; - node_rev_id = val; - - err = set_origin(db, node_id, - svn_fs_unparse_id(node_rev_id, iterpool), - iterpool); - MAYBE_CLEANUP; - } - - err = svn_fs__sqlite_exec(db, "COMMIT TRANSACTION;"); - MAYBE_CLEANUP; - - cleanup: - /* It's just an "optional" cache, so it's OK if the database is - readonly. */ - /* ### Instead of checking twice here, maybe add an IGNORE_READONLY - ### argument to svn_fs__sqlite_close? */ - if (err && err->apr_err == SVN_ERR_FS_SQLITE_READONLY) - { - svn_error_clear(err); - err = NULL; - } - err = svn_fs__sqlite_close(db, err); - if (err && err->apr_err == SVN_ERR_FS_SQLITE_READONLY) - { - svn_error_clear(err); - err = NULL; - } - svn_pool_destroy(iterpool); - svn_pool_destroy(subpool); - return err; -} - -svn_error_t * -svn_fs__set_node_origin(svn_fs_t *fs, - const char *node_id, - const svn_fs_id_t *node_rev_id, - apr_pool_t *pool) -{ - apr_hash_t *origins = apr_hash_make(pool); - - apr_hash_set(origins, node_id, APR_HASH_KEY_STRING, node_rev_id); - - return svn_fs__set_node_origins(fs, origins, pool); -} - -svn_error_t * -svn_fs__get_node_origin(const char **origin_id, - svn_fs_t *fs, - const char *node_id, - apr_pool_t *pool) -{ - sqlite3 *db; - svn_error_t *err; - - SVN_ERR(svn_fs__sqlite_open(&db, fs->path, pool)); - - err = get_origin(origin_id, db, node_id, pool); - - return svn_fs__sqlite_close(db, err); -} -- 2.11.4.GIT