/* The transaction code uses this to remove all locks. */ void tdb_release_transaction_locks(struct tdb_context *tdb) { unsigned int i, active = 0; if (tdb->allrecord_lock.count != 0) { tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false); tdb->allrecord_lock.count = 0; } for (i=0;i<tdb->num_lockrecs;i++) { struct tdb_lock_type *lck = &tdb->lockrecs[i]; /* Don't release the active lock! Copy it to first entry. */ if (lck->off == ACTIVE_LOCK) { tdb->lockrecs[active++] = *lck; } else { tdb_brunlock(tdb, lck->ltype, lck->off, 1); } } tdb->num_lockrecs = active; }
enum TDB_ERROR tdb_wipe_all(struct tdb_context *tdb) { enum TDB_ERROR ecode; int64_t count; if (tdb->flags & TDB_VERSION1) { if (tdb1_wipe_all(tdb) == -1) return tdb->last_error; return TDB_SUCCESS; } ecode = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false); if (ecode != TDB_SUCCESS) return tdb->last_error = ecode; /* FIXME: Be smarter. */ count = tdb_traverse(tdb, wipe_one, &ecode); if (count < 0) ecode = TDB_OFF_TO_ERR(count); tdb_allrecord_unlock(tdb, F_WRLCK); return tdb->last_error = ecode; }
/* unlock entire database with read lock */ _PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb) { tdb_trace(tdb, "tdb_unlockall_read"); return tdb_allrecord_unlock(tdb, F_RDLCK, false); }
/* unlock entire database with write lock - unmark only */ _PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb) { tdb_trace(tdb, "tdb_lockall_unmark"); return tdb_allrecord_unlock(tdb, F_WRLCK, true); }
/* lock/unlock entire database. It can only be upgradable if you have some * other way of guaranteeing exclusivity (ie. transaction write lock). * We do the locking gradually to avoid being starved by smaller locks. */ int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, enum tdb_lock_flags flags, bool upgradable) { int ret; switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) { case -1: return -1; case 0: return 0; } /* We cover two kinds of locks: * 1) Normal chain locks. Taken for almost all operations. * 2) Individual records locks. Taken after normal or free * chain locks. * * It is (1) which cause the starvation problem, so we're only * gradual for that. */ if (tdb_have_mutexes(tdb)) { ret = tdb_mutex_allrecord_lock(tdb, ltype, flags); } else { ret = tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP, tdb->hash_size * 4); } if (ret == -1) { return -1; } /* Grab individual record locks. */ if (tdb_brlock(tdb, ltype, lock_offset(tdb->hash_size), 0, flags) == -1) { if (tdb_have_mutexes(tdb)) { tdb_mutex_allrecord_unlock(tdb); } else { tdb_brunlock(tdb, ltype, FREELIST_TOP, tdb->hash_size * 4); } return -1; } tdb->allrecord_lock.count = 1; /* If it's upgradable, it's actually exclusive so we can treat * it as a write lock. */ tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype; tdb->allrecord_lock.off = upgradable; if (tdb_needs_recovery(tdb)) { bool mark = flags & TDB_LOCK_MARK_ONLY; tdb_allrecord_unlock(tdb, ltype, mark); if (mark) { tdb->ecode = TDB_ERR_LOCK; TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall_mark cannot do recovery\n")); return -1; } if (tdb_lock_and_recover(tdb) == -1) { return -1; } return tdb_allrecord_lock(tdb, ltype, flags, upgradable); } return 0; }