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