tdb_io_init(tdb);
tdb->fd = -1;
+#ifdef TDB_TRACE
+ tdb->tracefd = -1;
+#endif
tdb->name = NULL;
tdb->map_ptr = NULL;
tdb->flags = tdb_flags;
tdb->flags &= ~TDB_CLEAR_IF_FIRST;
}
+ if ((tdb->flags & TDB_ALLOW_NESTING) &&
+ (tdb->flags & TDB_DISALLOW_NESTING)) {
+ tdb->ecode = TDB_ERR_NESTING;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "allow_nesting and disallow_nesting are not allowed together!"));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /*
+ * TDB_ALLOW_NESTING is the default behavior.
+ * Note: this may change in future versions!
+ */
+ if (!(tdb->flags & TDB_DISALLOW_NESTING)) {
+ tdb->flags |= TDB_ALLOW_NESTING;
+ }
+
/* internal databases don't mmap or lock, and start off cleared */
if (tdb->flags & TDB_INTERNAL) {
tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
goto fail;
}
-#ifdef TDB_TRACE
- /* All tracing will fail. That's ok. */
- tdb->tracefd = -1;
-#endif
goto internal;
}
fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
/* ensure there is only one process initialising at once */
- if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+ if (tdb->methods->brlock(tdb, F_WRLCK, GLOBAL_LOCK, 1, TDB_LOCK_WAIT) == -1) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
name, strerror(errno)));
goto fail; /* errno set by tdb_brlock */
/* we need to zero database if we are the only one with it open */
if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
(!tdb->read_only) &&
- (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {
+ (locked = (tdb->methods->brlock(tdb, F_WRLCK, ACTIVE_LOCK, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
open_flags |= O_CREAT;
if (ftruncate(tdb->fd, 0) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
tdb->inode = st.st_ino;
tdb_mmap(tdb);
if (locked) {
- if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
+ if (tdb->methods->brunlock(tdb, F_WRLCK, ACTIVE_LOCK, 1) == -1) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
"failed to take ACTIVE_LOCK on %s: %s\n",
name, strerror(errno)));
if (tdb_flags & TDB_CLEAR_IF_FIRST) {
/* leave this lock in place to indicate it's in use */
- if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
+ if (tdb->methods->brlock(tdb, F_RDLCK, ACTIVE_LOCK, 1, TDB_LOCK_WAIT) == -1)
goto fail;
}
/* Internal (memory-only) databases skip all the code above to
* do with disk files, and resume here by releasing their
* global lock and hooking into the active list. */
- if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
+ if (tdb->methods->brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1) == -1)
goto fail;
tdb->next = tdbs;
tdbs = tdb;
struct tdb_context **i;
int ret = 0;
- tdb_trace(tdb, "tdb_close");
if (tdb->transaction) {
- _tdb_transaction_cancel(tdb);
+ tdb_transaction_cancel(tdb);
}
+ tdb_trace(tdb, "tdb_close");
if (tdb->map_ptr) {
if (tdb->flags & TDB_INTERNAL)
tdb_munmap(tdb);
}
SAFE_FREE(tdb->name);
- if (tdb->fd != -1)
+ if (tdb->fd != -1) {
ret = close(tdb->fd);
+ tdb->fd = -1;
+ }
SAFE_FREE(tdb->lockrecs);
/* Remove from contexts list */
goto fail;
}
if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
- (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
+ (tdb->methods->brlock(tdb, F_RDLCK, ACTIVE_LOCK, 1, TDB_LOCK_WAIT) == -1)) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
goto fail;
}