1/* env.h : managing the BDB environment 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 */ 22 23#include <assert.h> 24 25#include <apr.h> 26#if APR_HAS_THREADS 27#include <apr_thread_proc.h> 28#include <apr_time.h> 29#endif 30 31#include <apr_strings.h> 32#include <apr_hash.h> 33 34#include "svn_hash.h" 35#include "svn_path.h" 36#include "svn_pools.h" 37#include "svn_utf.h" 38#include "private/svn_atomic.h" 39#include "private/svn_mutex.h" 40 41#include "bdb-err.h" 42#include "bdb_compat.h" 43 44#include "env.h" 45 46/* A note about the BDB environment descriptor cache. 47 48 With the advent of DB_REGISTER in BDB-4.4, a process may only open 49 an environment handle once. This means that we must maintain a 50 cache of open environment handles, with reference counts. We 51 allocate each environment descriptor (a bdb_env_t) from its own 52 pool. The cache itself (and the cache pool) are shared between 53 threads, so all direct or indirect access to the pool is serialized 54 with a global mutex. 55 56 Because several threads can now use the same DB_ENV handle, we must 57 use the DB_THREAD flag when opening the environments, otherwise the 58 env handles (and all of libsvn_fs_base) won't be thread-safe. 59 60 If we use DB_THREAD, however, all of the code that reads data from 61 the database without a cursor must use either DB_DBT_MALLOC, 62 DB_DBT_REALLOC, or DB_DBT_USERMEM, as described in the BDB 63 documentation. 64 65 (Oh, yes -- using DB_THREAD might not work on some systems. But 66 then, it's quite probable that threading is seriously broken on 67 those systems anyway, so we'll rely on APR_HAS_THREADS.) 68*/ 69 70 71/* The cache key for a Berkeley DB environment descriptor. This is a 72 combination of the device ID and INODE number of the Berkeley DB 73 config file. 74 75 XXX FIXME: Although the dev+inode combination is supposed do be 76 unique, apparently that's not always the case with some remote 77 filesystems. We /should/ be safe using this as a unique hash key, 78 because the database must be on a local filesystem. We can hope, 79 anyway. */ 80typedef struct bdb_env_key_t 81{ 82 apr_dev_t device; 83 apr_ino_t inode; 84} bdb_env_key_t; 85 86/* The cached Berkeley DB environment descriptor. */ 87struct bdb_env_t 88{ 89 /**************************************************************************/ 90 /* Error Reporting */ 91 92 /* A (char *) casted pointer to this structure is passed to BDB's 93 set_errpfx(), which treats it as a NUL-terminated character 94 string to prefix all BDB error messages. However, svn also 95 registers bdb_error_gatherer() as an error handler with 96 set_errcall() which turns off BDB's default printing of errors to 97 stderr and anytime thereafter when BDB reports an error and 98 before the BDB function returns, it calls bdb_error_gatherer() 99 and passes the same error prefix (char *) pointer given to 100 set_errpfx(). The bdb_error_gatherer() callback casts the 101 (char *) it back to a (bdb_env_t *). 102 103 To avoid problems should BDB ever try to interpret our baton as a 104 string, the first field in the structure is a char 105 errpfx_string[]. Initializers of this structure must strcpy the 106 value of BDB_ERRPFX_STRING into this array. */ 107 char errpfx_string[sizeof(BDB_ERRPFX_STRING)]; 108 109 /* Extended error information. */ 110#if APR_HAS_THREADS 111 apr_threadkey_t *error_info; /* Points to a bdb_error_info_t. */ 112#else 113 bdb_error_info_t error_info; 114#endif 115 116 /**************************************************************************/ 117 /* BDB Environment Cache */ 118 119 /* The Berkeley DB environment. */ 120 DB_ENV *env; 121 122 /* The flags with which this environment was opened. Reopening the 123 environment with a different set of flags is not allowed. Trying 124 to change the state of the DB_PRIVATE flag is an especially bad 125 idea, so svn_fs_bdb__open() forbids any flag changes. */ 126 u_int32_t flags; 127 128 /* The home path of this environment; a canonical SVN path encoded in 129 UTF-8 and allocated from this decriptor's pool. */ 130 const char *path; 131 132 /* The home path of this environment, in the form expected by BDB. */ 133 const char *path_bdb; 134 135 /* The reference count for this environment handle; this is 136 essentially the difference between the number of calls to 137 svn_fs_bdb__open and svn_fs_bdb__close. */ 138 unsigned refcount; 139 140 /* If this flag is TRUE, someone has detected that the environment 141 descriptor is in a panicked state and should be removed from the 142 cache. 143 144 Note 1: Once this flag is set, it must not be cleared again. 145 146 Note 2: Unlike other fields in this structure, this field is not 147 protected by the cache mutex on threaded platforms, and 148 should only be accesses via the svn_atomic functions. */ 149 volatile svn_atomic_t panic; 150 151 /* The key for the environment descriptor cache. */ 152 bdb_env_key_t key; 153 154 /* The handle of the open DB_CONFIG file. 155 156 We keep the DB_CONFIG file open in this process as long as the 157 environment handle itself is open. On Windows, this guarantees 158 that the cache key remains unique; here's what the Windows SDK 159 docs have to say about the file index (interpreted as the INODE 160 number by APR): 161 162 "This value is useful only while the file is open by at least 163 one process. If no processes have it open, the index may 164 change the next time the file is opened." 165 166 Now, we certainly don't want a unique key to change while it's 167 being used, do we... */ 168 apr_file_t *dbconfig_file; 169 170 /* The pool associated with this environment descriptor. 171 172 Because the descriptor has a life of its own, the structure and 173 any data associated with it are allocated from their own global 174 pool. */ 175 apr_pool_t *pool; 176 177}; 178 179 180#if APR_HAS_THREADS 181/* Get the thread-specific error info from a bdb_env_t. */ 182static bdb_error_info_t * 183get_error_info(const bdb_env_t *bdb) 184{ 185 void *priv; 186 apr_threadkey_private_get(&priv, bdb->error_info); 187 if (!priv) 188 { 189 priv = calloc(1, sizeof(bdb_error_info_t)); 190 apr_threadkey_private_set(priv, bdb->error_info); 191 } 192 return priv; 193} 194#else 195#define get_error_info(bdb) (&(bdb)->error_info) 196#endif /* APR_HAS_THREADS */ 197 198 199/* Convert a BDB error to a Subversion error. */ 200static svn_error_t * 201convert_bdb_error(bdb_env_t *bdb, int db_err) 202{ 203 if (db_err) 204 { 205 bdb_env_baton_t bdb_baton; 206 bdb_baton.env = bdb->env; 207 bdb_baton.bdb = bdb; 208 bdb_baton.error_info = get_error_info(bdb); 209 SVN_BDB_ERR(&bdb_baton, db_err); 210 } 211 return SVN_NO_ERROR; 212} 213 214 215/* Allocating an appropriate Berkeley DB environment object. */ 216 217/* BDB error callback. See bdb_error_info_t in env.h for more info. 218 Note: bdb_error_gatherer is a macro with BDB < 4.3, so be careful how 219 you use it! */ 220static void 221bdb_error_gatherer(const DB_ENV *dbenv, const char *baton, const char *msg) 222{ 223 /* See the documentation at bdb_env_t's definition why the 224 (bdb_env_t *) cast is safe and why it is done. */ 225 bdb_error_info_t *error_info = get_error_info((const bdb_env_t *) baton); 226 svn_error_t *new_err; 227 228 SVN_BDB_ERROR_GATHERER_IGNORE(dbenv); 229 230 new_err = svn_error_createf(SVN_ERR_FS_BERKELEY_DB, NULL, "bdb: %s", msg); 231 if (error_info->pending_errors) 232 svn_error_compose(error_info->pending_errors, new_err); 233 else 234 error_info->pending_errors = new_err; 235 236 if (error_info->user_callback) 237 error_info->user_callback(NULL, (char *)msg); /* ### I hate this cast... */ 238} 239 240 241/* Pool cleanup for the cached environment descriptor. */ 242static apr_status_t 243cleanup_env(void *data) 244{ 245 bdb_env_t *bdb = data; 246 bdb->pool = NULL; 247 bdb->dbconfig_file = NULL; /* will be closed during pool destruction */ 248#if APR_HAS_THREADS 249 apr_threadkey_private_delete(bdb->error_info); 250#endif /* APR_HAS_THREADS */ 251 252 /* If there are no references to this descriptor, free its memory here, 253 so that we don't leak it if create_env returns an error. 254 See bdb_close, which takes care of freeing this memory if the 255 environment is still open when the cache is destroyed. */ 256 if (!bdb->refcount) 257 free(data); 258 259 return APR_SUCCESS; 260} 261 262#if APR_HAS_THREADS 263/* This cleanup is the fall back plan. If the thread exits and the 264 environment hasn't been closed it's responsible for cleanup of the 265 thread local error info variable, which would otherwise be leaked. 266 Normally it will not be called, because svn_fs_bdb__close will 267 set the thread's error info to NULL after cleaning it up. */ 268static void 269cleanup_error_info(void *baton) 270{ 271 bdb_error_info_t *error_info = baton; 272 273 if (error_info) 274 svn_error_clear(error_info->pending_errors); 275 276 free(error_info); 277} 278#endif /* APR_HAS_THREADS */ 279 280/* Create a Berkeley DB environment. */ 281static svn_error_t * 282create_env(bdb_env_t **bdbp, const char *path, apr_pool_t *pool) 283{ 284 int db_err; 285 bdb_env_t *bdb; 286 const char *path_bdb; 287 char *tmp_path, *tmp_path_bdb; 288 apr_size_t path_size, path_bdb_size; 289 290#if SVN_BDB_PATH_UTF8 291 path_bdb = svn_dirent_local_style(path, pool); 292#else 293 SVN_ERR(svn_utf_cstring_from_utf8(&path_bdb, 294 svn_dirent_local_style(path, pool), 295 pool)); 296#endif 297 298 /* Allocate the whole structure, including strings, from the heap, 299 because it must survive the cache pool cleanup. */ 300 path_size = strlen(path) + 1; 301 path_bdb_size = strlen(path_bdb) + 1; 302 /* Using calloc() to ensure the padding bytes in bdb->key (which is used as 303 * a hash key) are zeroed. */ 304 bdb = calloc(1, sizeof(*bdb) + path_size + path_bdb_size); 305 306 /* We must initialize this now, as our callers may assume their bdb 307 pointer is valid when checking for errors. */ 308 apr_pool_cleanup_register(pool, bdb, cleanup_env, apr_pool_cleanup_null); 309 apr_cpystrn(bdb->errpfx_string, BDB_ERRPFX_STRING, 310 sizeof(bdb->errpfx_string)); 311 bdb->path = tmp_path = (char*)(bdb + 1); 312 bdb->path_bdb = tmp_path_bdb = tmp_path + path_size; 313 apr_cpystrn(tmp_path, path, path_size); 314 apr_cpystrn(tmp_path_bdb, path_bdb, path_bdb_size); 315 bdb->pool = pool; 316 *bdbp = bdb; 317 318#if APR_HAS_THREADS 319 { 320 apr_status_t apr_err = apr_threadkey_private_create(&bdb->error_info, 321 cleanup_error_info, 322 pool); 323 if (apr_err) 324 return svn_error_create(apr_err, NULL, 325 "Can't allocate thread-specific storage" 326 " for the Berkeley DB environment descriptor"); 327 } 328#endif /* APR_HAS_THREADS */ 329 330 db_err = db_env_create(&(bdb->env), 0); 331 if (!db_err) 332 { 333 /* See the documentation at bdb_env_t's definition why the 334 (char *) cast is safe and why it is done. */ 335 bdb->env->set_errpfx(bdb->env, (char *) bdb); 336 337 /* bdb_error_gatherer is in parens to stop macro expansion. */ 338 bdb->env->set_errcall(bdb->env, (bdb_error_gatherer)); 339 340 /* Needed on Windows in case Subversion and Berkeley DB are using 341 different C runtime libraries */ 342 db_err = bdb->env->set_alloc(bdb->env, malloc, realloc, free); 343 344 /* If we detect a deadlock, select a transaction to abort at 345 random from those participating in the deadlock. */ 346 if (!db_err) 347 db_err = bdb->env->set_lk_detect(bdb->env, DB_LOCK_RANDOM); 348 } 349 return convert_bdb_error(bdb, db_err); 350} 351 352 353 354/* The environment descriptor cache. */ 355 356/* The global pool used for this cache. */ 357static apr_pool_t *bdb_cache_pool = NULL; 358 359/* The cache. The items are bdb_env_t structures. */ 360static apr_hash_t *bdb_cache = NULL; 361 362/* The mutex that protects bdb_cache. */ 363static svn_mutex__t *bdb_cache_lock = NULL; 364 365/* Cleanup callback to NULL out the cache, so we don't try to use it after 366 the pool has been cleared during global shutdown. */ 367static apr_status_t 368clear_cache(void *data) 369{ 370 bdb_cache = NULL; 371 bdb_cache_lock = NULL; 372 return APR_SUCCESS; 373} 374 375static volatile svn_atomic_t bdb_cache_state = 0; 376 377static svn_error_t * 378bdb_init_cb(void *baton, apr_pool_t *pool) 379{ 380 bdb_cache_pool = svn_pool_create(pool); 381 bdb_cache = apr_hash_make(bdb_cache_pool); 382 383 SVN_ERR(svn_mutex__init(&bdb_cache_lock, TRUE, bdb_cache_pool)); 384 apr_pool_cleanup_register(bdb_cache_pool, NULL, clear_cache, 385 apr_pool_cleanup_null); 386 387 return SVN_NO_ERROR; 388} 389 390svn_error_t * 391svn_fs_bdb__init(apr_pool_t* pool) 392{ 393 return svn_atomic__init_once(&bdb_cache_state, bdb_init_cb, NULL, pool); 394} 395 396/* Construct a cache key for the BDB environment at PATH in *KEYP. 397 if DBCONFIG_FILE is not NULL, return the opened file handle. 398 Allocate from POOL. */ 399static svn_error_t * 400bdb_cache_key(bdb_env_key_t *keyp, apr_file_t **dbconfig_file, 401 const char *path, apr_pool_t *pool) 402{ 403 const char *dbcfg_file_name = svn_dirent_join(path, BDB_CONFIG_FILE, pool); 404 apr_file_t *dbcfg_file; 405 apr_status_t apr_err; 406 apr_finfo_t finfo; 407 408 SVN_ERR(svn_io_file_open(&dbcfg_file, dbcfg_file_name, 409 APR_READ, APR_OS_DEFAULT, pool)); 410 411 apr_err = apr_file_info_get(&finfo, APR_FINFO_DEV | APR_FINFO_INODE, 412 dbcfg_file); 413 if (apr_err) 414 return svn_error_wrap_apr 415 (apr_err, "Can't create BDB environment cache key"); 416 417 /* Make sure that any padding in the key is always cleared, so that 418 the key's hash deterministic. */ 419 memset(keyp, 0, sizeof *keyp); 420 keyp->device = finfo.device; 421 keyp->inode = finfo.inode; 422 423 if (dbconfig_file) 424 *dbconfig_file = dbcfg_file; 425 else 426 apr_file_close(dbcfg_file); 427 428 return SVN_NO_ERROR; 429} 430 431 432/* Find a BDB environment in the cache. 433 Return the environment's panic state in *PANICP. 434 435 Note: You MUST acquire the cache mutex before calling this function. 436*/ 437static bdb_env_t * 438bdb_cache_get(const bdb_env_key_t *keyp, svn_boolean_t *panicp) 439{ 440 bdb_env_t *bdb = apr_hash_get(bdb_cache, keyp, sizeof *keyp); 441 if (bdb && bdb->env) 442 { 443 *panicp = !!svn_atomic_read(&bdb->panic); 444#if SVN_BDB_VERSION_AT_LEAST(4,2) 445 if (!*panicp) 446 { 447 u_int32_t flags; 448 if (bdb->env->get_flags(bdb->env, &flags) 449 || (flags & DB_PANIC_ENVIRONMENT)) 450 { 451 /* Something is wrong with the environment. */ 452 svn_atomic_set(&bdb->panic, TRUE); 453 *panicp = TRUE; 454 bdb = NULL; 455 } 456 } 457#endif /* at least bdb-4.2 */ 458 } 459 else 460 { 461 *panicp = FALSE; 462 } 463 return bdb; 464} 465 466 467 468/* Close and destroy a BDB environment descriptor. */ 469static svn_error_t * 470bdb_close(bdb_env_t *bdb) 471{ 472 svn_error_t *err = SVN_NO_ERROR; 473 474 /* This bit is delcate; we must propagate the error from 475 DB_ENV->close to the caller, and always destroy the pool. */ 476 int db_err = bdb->env->close(bdb->env, 0); 477 478 /* If automatic database recovery is enabled, ignore DB_RUNRECOVERY 479 errors, since they're dealt with eventually by BDB itself. */ 480 if (db_err && (!SVN_BDB_AUTO_RECOVER || db_err != DB_RUNRECOVERY)) 481 err = convert_bdb_error(bdb, db_err); 482 483 /* Free the environment descriptor. The pool cleanup will do this unless 484 the cache has already been destroyed. */ 485 if (bdb->pool) 486 svn_pool_destroy(bdb->pool); 487 else 488 free(bdb); 489 return svn_error_trace(err); 490} 491 492 493static svn_error_t * 494svn_fs_bdb__close_internal(bdb_env_t *bdb) 495{ 496 svn_error_t *err = SVN_NO_ERROR; 497 498 if (--bdb->refcount != 0) 499 { 500 /* If the environment is panicked and automatic recovery is not 501 enabled, return an appropriate error. */ 502#if !SVN_BDB_AUTO_RECOVER 503 if (svn_atomic_read(&bdb->panic)) 504 err = svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, 505 db_strerror(DB_RUNRECOVERY)); 506#endif 507 } 508 else 509 { 510 /* If the bdb cache has been set to NULL that means we are 511 shutting down, and the pool that holds the bdb cache has 512 already been destroyed, so accessing it here would be a Bad 513 Thing (tm) */ 514 if (bdb_cache) 515 apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, NULL); 516 err = bdb_close(bdb); 517 } 518 return svn_error_trace(err); 519} 520 521svn_error_t * 522svn_fs_bdb__close(bdb_env_baton_t *bdb_baton) 523{ 524 bdb_env_t *bdb = bdb_baton->bdb; 525 526 SVN_ERR_ASSERT(bdb_baton->env == bdb_baton->bdb->env); 527 SVN_ERR_ASSERT(bdb_baton->error_info->refcount > 0); 528 529 /* Neutralize bdb_baton's pool cleanup to prevent double-close. See 530 cleanup_env_baton(). */ 531 bdb_baton->bdb = NULL; 532 533 /* Note that we only bother with this cleanup if the pool is non-NULL, to 534 guard against potential races between this and the cleanup_env cleanup 535 callback. It's not clear if that can actually happen, but better safe 536 than sorry. */ 537 if (0 == --bdb_baton->error_info->refcount && bdb->pool) 538 { 539 svn_error_clear(bdb_baton->error_info->pending_errors); 540#if APR_HAS_THREADS 541 free(bdb_baton->error_info); 542 apr_threadkey_private_set(NULL, bdb->error_info); 543#endif 544 } 545 546 /* This may run during final pool cleanup when the lock is NULL. */ 547 SVN_MUTEX__WITH_LOCK(bdb_cache_lock, svn_fs_bdb__close_internal(bdb)); 548 549 return SVN_NO_ERROR; 550} 551 552 553 554/* Open and initialize a BDB environment. */ 555static svn_error_t * 556bdb_open(bdb_env_t *bdb, u_int32_t flags, int mode) 557{ 558#if APR_HAS_THREADS 559 flags |= DB_THREAD; 560#endif 561 SVN_ERR(convert_bdb_error 562 (bdb, (bdb->env->open)(bdb->env, bdb->path_bdb, flags, mode))); 563 564#if SVN_BDB_AUTO_COMMIT 565 /* Assert the BDB_AUTO_COMMIT flag on the opened environment. This 566 will force all operations on the environment (and handles that 567 are opened within the environment) to be transactional. */ 568 569 SVN_ERR(convert_bdb_error 570 (bdb, bdb->env->set_flags(bdb->env, SVN_BDB_AUTO_COMMIT, 1))); 571#endif 572 573 return bdb_cache_key(&bdb->key, &bdb->dbconfig_file, 574 bdb->path, bdb->pool); 575} 576 577 578/* Pool cleanup for the environment baton. */ 579static apr_status_t 580cleanup_env_baton(void *data) 581{ 582 bdb_env_baton_t *bdb_baton = data; 583 584 if (bdb_baton->bdb) 585 svn_error_clear(svn_fs_bdb__close(bdb_baton)); 586 587 return APR_SUCCESS; 588} 589 590 591static svn_error_t * 592svn_fs_bdb__open_internal(bdb_env_baton_t **bdb_batonp, 593 const char *path, 594 u_int32_t flags, int mode, 595 apr_pool_t *pool) 596{ 597 bdb_env_key_t key; 598 bdb_env_t *bdb; 599 svn_boolean_t panic; 600 601 /* We can safely discard the open DB_CONFIG file handle. If the 602 environment descriptor is in the cache, the key's immutability is 603 guaranteed. If it's not, we don't care if the key changes, 604 between here and the actual insertion of the newly-created 605 environment into the cache, because no other thread can touch the 606 cache in the meantime. */ 607 SVN_ERR(bdb_cache_key(&key, NULL, path, pool)); 608 609 bdb = bdb_cache_get(&key, &panic); 610 if (panic) 611 return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, 612 db_strerror(DB_RUNRECOVERY)); 613 614 /* Make sure that the environment's open flags haven't changed. */ 615 if (bdb && bdb->flags != flags) 616 { 617 /* Handle changes to the DB_PRIVATE flag specially */ 618 if ((flags ^ bdb->flags) & DB_PRIVATE) 619 { 620 if (flags & DB_PRIVATE) 621 return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, 622 "Reopening a public Berkeley DB" 623 " environment with private attributes"); 624 else 625 return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, 626 "Reopening a private Berkeley DB" 627 " environment with public attributes"); 628 } 629 630 /* Otherwise return a generic "flags-mismatch" error. */ 631 return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL, 632 "Reopening a Berkeley DB environment" 633 " with different attributes"); 634 } 635 636 if (!bdb) 637 { 638 svn_error_t *err; 639 640 SVN_ERR(create_env(&bdb, path, svn_pool_create(bdb_cache_pool))); 641 err = bdb_open(bdb, flags, mode); 642 if (err) 643 { 644 /* Clean up, and we can't do anything about returned errors. */ 645 svn_error_clear(bdb_close(bdb)); 646 return svn_error_trace(err); 647 } 648 649 apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, bdb); 650 bdb->flags = flags; 651 bdb->refcount = 1; 652 } 653 else 654 { 655 ++bdb->refcount; 656 } 657 658 *bdb_batonp = apr_palloc(pool, sizeof **bdb_batonp); 659 (*bdb_batonp)->env = bdb->env; 660 (*bdb_batonp)->bdb = bdb; 661 (*bdb_batonp)->error_info = get_error_info(bdb); 662 ++(*bdb_batonp)->error_info->refcount; 663 apr_pool_cleanup_register(pool, *bdb_batonp, cleanup_env_baton, 664 apr_pool_cleanup_null); 665 666 return SVN_NO_ERROR; 667} 668 669svn_error_t * 670svn_fs_bdb__open(bdb_env_baton_t **bdb_batonp, const char *path, 671 u_int32_t flags, int mode, 672 apr_pool_t *pool) 673{ 674 SVN_MUTEX__WITH_LOCK(bdb_cache_lock, 675 svn_fs_bdb__open_internal(bdb_batonp, 676 path, 677 flags, 678 mode, 679 pool)); 680 681 return SVN_NO_ERROR; 682} 683 684 685svn_boolean_t 686svn_fs_bdb__get_panic(bdb_env_baton_t *bdb_baton) 687{ 688 /* An invalid baton is equivalent to a panicked environment; in both 689 cases, database cleanups should be skipped. */ 690 if (!bdb_baton->bdb) 691 return TRUE; 692 693 assert(bdb_baton->env == bdb_baton->bdb->env); 694 return !!svn_atomic_read(&bdb_baton->bdb->panic); 695} 696 697void 698svn_fs_bdb__set_panic(bdb_env_baton_t *bdb_baton) 699{ 700 if (!bdb_baton->bdb) 701 return; 702 703 assert(bdb_baton->env == bdb_baton->bdb->env); 704 svn_atomic_set(&bdb_baton->bdb->panic, TRUE); 705} 706 707 708/* This function doesn't actually open the environment, so it doesn't 709 have to look in the cache. Callers are supposed to own an 710 exclusive lock on the filesystem anyway. */ 711svn_error_t * 712svn_fs_bdb__remove(const char *path, apr_pool_t *pool) 713{ 714 bdb_env_t *bdb; 715 716 SVN_ERR(create_env(&bdb, path, pool)); 717 return convert_bdb_error 718 (bdb, bdb->env->remove(bdb->env, bdb->path_bdb, DB_FORCE)); 719} 720