svn_error_t * svn_fs_bdb__close(bdb_env_baton_t *bdb_baton) { bdb_env_t *bdb = bdb_baton->bdb; SVN_ERR_ASSERT(bdb_baton->env == bdb_baton->bdb->env); SVN_ERR_ASSERT(bdb_baton->error_info->refcount > 0); /* Neutralize bdb_baton's pool cleanup to prevent double-close. See cleanup_env_baton(). */ bdb_baton->bdb = NULL; /* Note that we only bother with this cleanup if the pool is non-NULL, to guard against potential races between this and the cleanup_env cleanup callback. It's not clear if that can actually happen, but better safe than sorry. */ if (0 == --bdb_baton->error_info->refcount && bdb->pool) { svn_error_clear(bdb_baton->error_info->pending_errors); #if APR_HAS_THREADS free(bdb_baton->error_info); apr_threadkey_private_set(NULL, bdb->error_info); #endif } /* This may run during final pool cleanup when the lock is NULL. */ SVN_MUTEX__WITH_LOCK(bdb_cache_lock, svn_fs_bdb__close_internal(bdb)); return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_get_partial(void **value_p, svn_boolean_t *found, void *cache_void, const void *key, svn_cache__partial_getter_func_t func, void *baton, apr_pool_t *result_pool) { inprocess_cache_t *cache = cache_void; if (key) SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_get_partial_internal(value_p, found, cache, key, func, baton, result_pool)); else *found = FALSE; return SVN_NO_ERROR; }
svn_error_t * logger__write(logger_t *logger, const char *errstr, apr_size_t len) { SVN_MUTEX__WITH_LOCK(logger->mutex, svn_stream_write(logger->stream, errstr, &len)); return SVN_NO_ERROR; }
svn_error_t * svn_dso_load(apr_dso_handle_t **dso, const char *fname) { SVN_ERR(svn_dso_initialize2()); SVN_MUTEX__WITH_LOCK(dso_mutex, svn_dso_load_internal(dso, fname)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_open_berkeley(svn_fs_t *fs, const char *path) { fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, fs->pool)); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->open_fs(fs, path, fs->pool, common_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__initialize_shared_data(svn_fs_t *fs, svn_mutex__t *common_pool_lock, apr_pool_t *scratch_pool, apr_pool_t *common_pool) { SVN_MUTEX__WITH_LOCK(common_pool_lock, x_serialized_init(fs, common_pool, scratch_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, apr_pool_t *pool) { fs_library_vtable_t *vtable; SVN_ERR(fs_library_vtable(&vtable, path, pool)); *fs_p = fs_new(fs_config, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->open_fs(*fs_p, path, pool, common_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_upgrade(const char *path, apr_pool_t *pool) { fs_library_vtable_t *vtable; svn_fs_t *fs; SVN_ERR(fs_library_vtable(&vtable, path, pool)); fs = fs_new(NULL, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->upgrade_fs(fs, path, pool, common_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__open(bdb_env_baton_t **bdb_batonp, const char *path, u_int32_t flags, int mode, apr_pool_t *pool) { SVN_MUTEX__WITH_LOCK(bdb_cache_lock, svn_fs_bdb__open_internal(bdb_batonp, path, flags, mode, pool)); return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_get_info(void *cache_void, svn_cache__info_t *info, svn_boolean_t reset, apr_pool_t *result_pool) { inprocess_cache_t *cache = cache_void; SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_get_info_internal(cache, info, result_pool)); return SVN_NO_ERROR; }
/* Fetch a library vtable by FS type. */ static svn_error_t * get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type, apr_pool_t *pool) { struct fs_type_defn **fst = &fs_modules; svn_boolean_t known = FALSE; /* There are two FS module definitions known at compile time. We want to check these without any locking overhead even when dynamic third party modules are enabled. The third party modules cannot be checked until the lock is held. */ if (strcmp(fs_type, (*fst)->fs_type) == 0) known = TRUE; else { fst = &(*fst)->next; if (strcmp(fs_type, (*fst)->fs_type) == 0) known = TRUE; } #if defined(SVN_USE_DSO) && APR_HAS_DSO /* Third party FS modules that are unknown at compile time. A third party FS is identified by the file fs-type containing a third party name, say "foo". The loader will load the DSO with the name "libsvn_fs_foo" and use the entry point with the name "svn_fs_foo__init". Note: the BDB and FSFS modules don't follow this naming scheme and this allows them to be used to test the third party loader. Change the content of fs-type to "base" in a BDB filesystem or to "fs" in an FSFS filesystem and they will be loaded as third party modules. */ if (!known) { fst = &(*fst)->next; if (!common_pool) /* Best-effort init, see get_library_vtable_direct. */ SVN_ERR(svn_fs_initialize(NULL)); SVN_MUTEX__WITH_LOCK(common_pool_lock, get_or_allocate_third(fst, fs_type)); known = TRUE; } #endif if (!known) return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, _("Unknown FS type '%s'"), fs_type); return get_library_vtable_direct(vtable, *fst, pool); }
svn_error_t * svn_fs_create_berkeley(svn_fs_t *fs, const char *path) { fs_library_vtable_t *vtable; SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool)); /* Create the FS directory and write out the fsap-name file. */ SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool)); SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool)); /* Perform the actual creation. */ SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->create(fs, path, fs->pool, common_pool)); return SVN_NO_ERROR; }
/* Fetch a library vtable by a pointer into the library definitions array. */ static svn_error_t * get_library_vtable_direct(fs_library_vtable_t **vtable, const struct fs_type_defn *fst, apr_pool_t *pool) { fs_init_func_t initfunc = NULL; const svn_version_t *my_version = svn_fs_version(); const svn_version_t *fs_version; initfunc = fst->initfunc; if (! initfunc) SVN_ERR(load_module(&initfunc, fst->fsap_name, pool)); if (! initfunc) return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL, _("Failed to load module for FS type '%s'"), fst->fs_type); { /* Per our API compatibility rules, we cannot ensure that svn_fs_initialize is called by the application. If not, we cannot create the common pool and lock in a thread-safe fashion, nor can we clean up the common pool if libsvn_fs is dynamically unloaded. This function makes a best effort by creating the common pool as a child of the global pool; the window of failure due to thread collision is small. */ if (!common_pool) SVN_ERR(svn_fs_initialize(NULL)); /* Invoke the FS module's initfunc function with the common pool protected by a lock. */ SVN_MUTEX__WITH_LOCK(common_pool_lock, initfunc(my_version, vtable, common_pool)); } fs_version = (*vtable)->get_version(); if (!svn_ver_equal(my_version, fs_version)) return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, _("Mismatched FS module version for '%s':" " found %d.%d.%d%s," " expected %d.%d.%d%s"), fst->fs_type, my_version->major, my_version->minor, my_version->patch, my_version->tag, fs_version->major, fs_version->minor, fs_version->patch, fs_version->tag); return SVN_NO_ERROR; }
svn_error_t * svn_fs_recover(const char *path, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { fs_library_vtable_t *vtable; svn_fs_t *fs; SVN_ERR(fs_library_vtable(&vtable, path, pool)); fs = fs_new(NULL, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->open_fs_for_recovery(fs, path, pool, common_pool)); return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton, pool)); }
static svn_error_t * inprocess_cache_set(void *cache_void, const void *key, void *value, apr_pool_t *scratch_pool) { inprocess_cache_t *cache = cache_void; if (key) SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_set_internal(cache, key, value, scratch_pool)); return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_iter(svn_boolean_t *completed, void *cache_void, svn_iter_apr_hash_cb_t user_cb, void *user_baton, apr_pool_t *scratch_pool) { inprocess_cache_t *cache = cache_void; struct cache_iter_baton b; b.user_cb = user_cb; b.user_baton = user_baton; SVN_MUTEX__WITH_LOCK(cache->mutex, svn_iter_apr_hash(completed, cache->hash, iter_cb, &b, scratch_pool)); return SVN_NO_ERROR; }
/* This implements the fs_library_vtable_t.create() API. Create a new fsfs-backed Subversion filesystem at path PATH and link it into *FS. Perform temporary allocations in POOL, and fs-global allocations in COMMON_POOL. The latter must be serialized using COMMON_POOL_LOCK. */ static svn_error_t * fs_create(svn_fs_t *fs, const char *path, svn_mutex__t *common_pool_lock, apr_pool_t *pool, apr_pool_t *common_pool) { SVN_ERR(svn_fs__check_fs(fs, FALSE)); SVN_ERR(initialize_fs_struct(fs)); SVN_ERR(svn_fs_fs__create(fs, path, pool)); SVN_ERR(svn_fs_fs__initialize_caches(fs, pool)); SVN_MUTEX__WITH_LOCK(common_pool_lock, fs_serialized_init(fs, common_pool, pool)); return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_has_key(svn_boolean_t *found, void *cache_void, const void *key, apr_pool_t *scratch_pool) { inprocess_cache_t *cache = cache_void; if (key) SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_has_key_internal(found, cache, key, scratch_pool)); else *found = FALSE; return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_set_partial(void *cache_void, const void *key, svn_cache__partial_setter_func_t func, void *baton, apr_pool_t *scratch_pool) { inprocess_cache_t *cache = cache_void; if (key) SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_set_partial_internal(cache, key, func, baton, scratch_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_verify(const char *path, svn_cancel_func_t cancel_func, void *cancel_baton, svn_revnum_t start, svn_revnum_t end, apr_pool_t *pool) { fs_library_vtable_t *vtable; svn_fs_t *fs; SVN_ERR(fs_library_vtable(&vtable, path, pool)); fs = fs_new(NULL, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->verify_fs(fs, path, cancel_func, cancel_baton, start, end, pool, common_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_pack(const char *path, svn_fs_pack_notify_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { fs_library_vtable_t *vtable; svn_fs_t *fs; SVN_ERR(fs_library_vtable(&vtable, path, pool)); fs = fs_new(NULL, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->pack_fs(fs, path, notify_func, notify_baton, cancel_func, cancel_baton, pool, common_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config, apr_pool_t *pool) { fs_library_vtable_t *vtable; const char *fs_type = svn_hash__get_cstring(fs_config, SVN_FS_CONFIG_FS_TYPE, DEFAULT_FS_TYPE); SVN_ERR(get_library_vtable(&vtable, fs_type, pool)); /* Create the FS directory and write out the fsap-name file. */ SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool)); SVN_ERR(write_fs_type(path, fs_type, pool)); /* Perform the actual creation. */ *fs_p = fs_new(fs_config, pool); SVN_MUTEX__WITH_LOCK(common_pool_lock, vtable->create(*fs_p, path, pool, common_pool)); return SVN_NO_ERROR; }
/* This implements the fs_library_vtable_t.open() API. Open an FSX Subversion filesystem located at PATH, set *FS to point to the correct vtable for the filesystem. Use SCRATCH_POOL for any temporary allocations, and COMMON_POOL for fs-global allocations. The latter must be serialized using COMMON_POOL_LOCK. */ static svn_error_t * x_open(svn_fs_t *fs, const char *path, svn_mutex__t *common_pool_lock, apr_pool_t *scratch_pool, apr_pool_t *common_pool) { apr_pool_t *subpool = svn_pool_create(scratch_pool); SVN_ERR(svn_fs__check_fs(fs, FALSE)); SVN_ERR(initialize_fs_struct(fs)); SVN_ERR(svn_fs_x__open(fs, path, subpool)); SVN_ERR(svn_fs_x__initialize_caches(fs, subpool)); SVN_MUTEX__WITH_LOCK(common_pool_lock, x_serialized_init(fs, common_pool, subpool)); svn_pool_destroy(subpool); return SVN_NO_ERROR; }
static svn_error_t * inprocess_cache_get(void **value_p, svn_boolean_t *found, void *cache_void, const void *key, apr_pool_t *result_pool) { inprocess_cache_t *cache = cache_void; if (key) { char* buffer; apr_size_t size; SVN_MUTEX__WITH_LOCK(cache->mutex, inprocess_cache_get_internal(&buffer, &size, cache, key, result_pool)); /* deserialize the buffer content. Usually, this will directly modify the buffer content directly. */ *found = (buffer != NULL); if (!buffer || !size) *value_p = NULL; else return cache->deserialize_func(value_p, buffer, size, result_pool); } else { *value_p = NULL; *found = FALSE; } return SVN_NO_ERROR; }