]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_fs_base/bdb/env.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_fs_base / bdb / env.c
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. */
80 typedef 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. */
87 struct 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. */
182 static bdb_error_info_t *
183 get_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. */
200 static svn_error_t *
201 convert_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 \f
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! */
220 static void
221 bdb_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. */
242 static apr_status_t
243 cleanup_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. */
268 static void
269 cleanup_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. */
281 static svn_error_t *
282 create_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 \f
354 /* The environment descriptor cache. */
355
356 /* The global pool used for this cache. */
357 static apr_pool_t *bdb_cache_pool = NULL;
358
359 /* The cache.  The items are bdb_env_t structures. */
360 static apr_hash_t *bdb_cache = NULL;
361
362 /* The mutex that protects bdb_cache. */
363 static 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. */
367 static apr_status_t
368 clear_cache(void *data)
369 {
370   bdb_cache = NULL;
371   bdb_cache_lock = NULL;
372   return APR_SUCCESS;
373 }
374
375 static volatile svn_atomic_t bdb_cache_state = 0;
376
377 static svn_error_t *
378 bdb_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
390 svn_error_t *
391 svn_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. */
399 static svn_error_t *
400 bdb_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 */
437 static bdb_env_t *
438 bdb_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 \f
468 /* Close and destroy a BDB environment descriptor. */
469 static svn_error_t *
470 bdb_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
493 static svn_error_t *
494 svn_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
521 svn_error_t *
522 svn_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 \f
554 /* Open and initialize a BDB environment. */
555 static svn_error_t *
556 bdb_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. */
579 static apr_status_t
580 cleanup_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
591 static svn_error_t *
592 svn_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
669 svn_error_t *
670 svn_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 \f
685 svn_boolean_t
686 svn_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
697 void
698 svn_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 \f
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. */
711 svn_error_t *
712 svn_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 }