📄 env.c
字号:
#endif /* APR_HAS_THREADS */#if APR_HAS_THREADS if (cache_state == BDB_CACHE_UNINITIALIZED)#else if (!bdb_cache_pool)#endif /* APR_HAS_THREADS */ { bdb_cache_pool = svn_pool_create(NULL); bdb_cache = apr_hash_make(bdb_cache_pool);#if APR_HAS_THREADS apr_err = apr_thread_mutex_create(&bdb_cache_lock, APR_THREAD_MUTEX_DEFAULT, bdb_cache_pool); if (apr_err) { /* Tell other threads that the initialisation failed. */ svn__atomic_cas(&bdb_cache_state, BDB_CACHE_INIT_FAILED, BDB_CACHE_START_INIT); return svn_error_create(apr_err, NULL, "Couldn't initialize the cache of" " Berkeley DB environment descriptors"); } apr_pool_cleanup_register(bdb_cache_pool, NULL, clear_cache, apr_pool_cleanup_null); svn__atomic_cas(&bdb_cache_state, BDB_CACHE_INITIALIZED, BDB_CACHE_START_INIT);#endif /* APR_HAS_THREADS */ }#if APR_HAS_THREADS /* Wait for whichever thread is initializing the cache to finish. */ /* XXX FIXME: Should we have a maximum wait here, like we have in the Windows file IO spinner? */ else while (cache_state != BDB_CACHE_INITIALIZED) { if (cache_state == BDB_CACHE_INIT_FAILED) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "Couldn't initialize the cache of" " Berkeley DB environment descriptors"); apr_sleep(APR_USEC_PER_SEC / 1000); cache_state = svn__atomic_cas(&bdb_cache_state, BDB_CACHE_UNINITIALIZED, BDB_CACHE_UNINITIALIZED); }#endif /* APR_HAS_THREADS */ return SVN_NO_ERROR;}static APR_INLINE voidacquire_cache_mutex(void){#if APR_HAS_THREADS if (bdb_cache_lock) apr_thread_mutex_lock(bdb_cache_lock);#endif}static APR_INLINE voidrelease_cache_mutex(void){#if APR_HAS_THREADS if (bdb_cache_lock) apr_thread_mutex_unlock(bdb_cache_lock);#endif}/* Construct a cache key for the BDB environment at PATH in *KEYP. if DBCONFIG_FILE is not NULL, return the opened file handle. Allocate from POOL. */static svn_error_t *bdb_cache_key(bdb_env_key_t *keyp, apr_file_t **dbconfig_file, const char *path, apr_pool_t *pool){ const char *dbcfg_file_name = svn_path_join(path, BDB_CONFIG_FILE, pool); apr_file_t *dbcfg_file; apr_status_t apr_err; apr_finfo_t finfo; SVN_ERR(svn_io_file_open(&dbcfg_file, dbcfg_file_name, APR_READ, APR_OS_DEFAULT, pool)); apr_err = apr_file_info_get(&finfo, APR_FINFO_DEV | APR_FINFO_INODE, dbcfg_file); if (apr_err) return svn_error_wrap_apr (apr_err, "Can't create BDB environment cache key"); /* Make sure that any padding in the key is always cleared, so that the key's hash deterministic. */ memset(keyp, 0, sizeof *keyp); keyp->device = finfo.device; keyp->inode = finfo.inode; if (dbconfig_file) *dbconfig_file = dbcfg_file; else apr_file_close(dbcfg_file); return SVN_NO_ERROR;}/* Find a BDB environment in the cache. Return the environment's panic state in *PANICP. Note: You MUST acquire the cache mutex before calling this function.*/static bdb_env_t *bdb_cache_get(const bdb_env_key_t *keyp, svn_boolean_t *panicp){ bdb_env_t *bdb = apr_hash_get(bdb_cache, keyp, sizeof *keyp); if (bdb && bdb->env) { *panicp = !!svn__atomic_read(&bdb->panic);#if SVN_BDB_VERSION_AT_LEAST(4,2) if (!*panicp) { u_int32_t flags; if (bdb->env->get_flags(bdb->env, &flags) || (flags & DB_PANIC_ENVIRONMENT)) { /* Something is wrong with the environment. */ svn__atomic_set(&bdb->panic, TRUE); *panicp = TRUE; bdb = NULL; } }#endif /* at least bdb-4.2 */ } else { *panicp = FALSE; } return bdb;}/* Close and destroy a BDB environment descriptor. */static svn_error_t *bdb_close(bdb_env_t *bdb){ svn_error_t *err = SVN_NO_ERROR; /* This bit is delcate; we must propagate the error from DB_ENV->close to the caller, and always destroy the pool. */ int db_err = bdb->env->close(bdb->env, 0); /* If automatic database recovery is enabled, ignore DB_RUNRECOVERY errors, since they're dealt with eventually by BDB itself. */ if (db_err && (!SVN_BDB_AUTO_RECOVER || db_err != DB_RUNRECOVERY)) err = convert_bdb_error(bdb, db_err); /* Free the environment descriptor. The pool cleanup will do this unless the cache has already been destroyed. */ if (bdb->pool) apr_pool_destroy(bdb->pool); else free(bdb); return err;}svn_error_t *svn_fs_bdb__close(bdb_env_baton_t *bdb_baton){ svn_error_t *err = SVN_NO_ERROR; bdb_env_t *bdb = bdb_baton->bdb; assert(bdb_baton->env == bdb_baton->bdb->env); /* 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 } acquire_cache_mutex(); if (--bdb->refcount != 0) { release_cache_mutex(); /* If the environment is panicked and automatic recovery is not enabled, return an appropriate error. */ if (!SVN_BDB_AUTO_RECOVER && svn__atomic_read(&bdb->panic)) err = svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, db_strerror(DB_RUNRECOVERY)); } else { /* If the bdb cache has been set to NULL that means we are shutting down, and the pool that holds the bdb cache has already been destroyed, so accessing it here would be a Bad Thing (tm) */ if (bdb_cache) apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, NULL); err = bdb_close(bdb); release_cache_mutex(); } return err;}/* Open and initialize a BDB environment. */static svn_error_t *bdb_open(bdb_env_t *bdb, u_int32_t flags, int mode){#if APR_HAS_THREADS flags |= DB_THREAD;#endif SVN_ERR(convert_bdb_error (bdb, bdb->env->open(bdb->env, bdb->path_bdb, flags, mode)));#if SVN_BDB_AUTO_COMMIT /* Assert the BDB_AUTO_COMMIT flag on the opened environment. This will force all operations on the environment (and handles that are opened within the environment) to be transactional. */ SVN_ERR(convert_bdb_error (bdb, bdb->env->set_flags(bdb->env, SVN_BDB_AUTO_COMMIT, 1)));#endif SVN_ERR(bdb_cache_key(&bdb->key, &bdb->dbconfig_file, bdb->path, bdb->pool)); return SVN_NO_ERROR;}/* Pool cleanup for the environment baton. */static apr_status_tcleanup_env_baton(void *data){ bdb_env_baton_t *bdb_baton = data; if (bdb_baton->bdb) svn_error_clear(svn_fs_bdb__close(bdb_baton)); return APR_SUCCESS;}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_error_t *err = SVN_NO_ERROR; bdb_env_key_t key; bdb_env_t *bdb; svn_boolean_t panic; acquire_cache_mutex(); /* We can safely discard the open DB_CONFIG file handle. If the environment descriptor is in the cache, the key's immutability is guaranteed. If it's not, we don't care if the key changes, between here and the actual insertion of the newly-created environment into the cache, because no other thread can touch the cache in the meantime. */ err = bdb_cache_key(&key, NULL, path, pool); if (err) { release_cache_mutex(); return err; } bdb = bdb_cache_get(&key, &panic); if (panic) { release_cache_mutex(); return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, db_strerror(DB_RUNRECOVERY)); } /* Make sure that the environment's open flags haven't changed. */ if (bdb && bdb->flags != flags) { release_cache_mutex(); /* Handle changes to the DB_PRIVATE flag specially */ if ((flags ^ bdb->flags) & DB_PRIVATE) { if (flags & DB_PRIVATE) return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, "Reopening a public Berkeley DB" " environment with private attributes"); else return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, "Reopening a private Berkeley DB" " environment with public attributes"); } /* Otherwise return a generic "flags-mismatch" error. */ return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, "Reopening a Berkeley DB environment" " with different attributes"); } if (!bdb) { err = create_env(&bdb, path, svn_pool_create(bdb_cache_pool)); if (!err) { err = bdb_open(bdb, flags, mode); if (!err) { apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, bdb); bdb->flags = flags; bdb->refcount = 1; } else { /* Clean up, and we can't do anything about returned errors. */ svn_error_clear(bdb_close(bdb)); } } } else { ++bdb->refcount; } if (!err) { *bdb_batonp = apr_palloc(pool, sizeof **bdb_batonp); (*bdb_batonp)->env = bdb->env; (*bdb_batonp)->bdb = bdb; (*bdb_batonp)->error_info = get_error_info(bdb); ++(*bdb_batonp)->error_info->refcount; apr_pool_cleanup_register(pool, *bdb_batonp, cleanup_env_baton, apr_pool_cleanup_null); } release_cache_mutex(); return err;}svn_boolean_tsvn_fs_bdb__get_panic(bdb_env_baton_t *bdb_baton){ /* An invalid baton is equivalent to a panicked environment; in both cases, database cleanups should be skipped. */ if (!bdb_baton->bdb) return TRUE; assert(bdb_baton->env == bdb_baton->bdb->env); return !!svn__atomic_read(&bdb_baton->bdb->panic);}voidsvn_fs_bdb__set_panic(bdb_env_baton_t *bdb_baton){ if (!bdb_baton->bdb) return; assert(bdb_baton->env == bdb_baton->bdb->env); svn__atomic_set(&bdb_baton->bdb->panic, TRUE);}/* This function doesn't actually open the environment, so it doesn't have to look in the cache. Callers are supposed to own an exclusive lock on the filesystem anyway. */svn_error_t *svn_fs_bdb__remove(const char *path, apr_pool_t *pool){ bdb_env_t *bdb; SVN_ERR(create_env(&bdb, path, pool)); return convert_bdb_error (bdb, bdb->env->remove(bdb->env, bdb->path_bdb, DB_FORCE));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -