1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

r21303: As discussed on samba-technical: Change the static array for the in-memory

mirrors of the hash chain locks to a dynamically allocated one.

Jeremy, I count on you to revert it if the build farm freaks out, it's after
midnight here :-)

Volker
This commit is contained in:
Volker Lendecke 2007-02-12 23:16:02 +00:00 committed by Gerald (Jerry) Carter
parent 5c3edad860
commit c50f099be1
4 changed files with 97 additions and 37 deletions

View File

@ -107,6 +107,9 @@ int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
/* lock a list in the database. list -1 is the alloc list */
int tdb_lock(struct tdb_context *tdb, int list, int ltype)
{
struct tdb_lock_type *new_lck;
int i;
/* a global lock allows us to avoid per chain locks */
if (tdb->global_lock.count &&
(ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
@ -125,18 +128,50 @@ int tdb_lock(struct tdb_context *tdb, int list, int ltype)
if (tdb->flags & TDB_NOLOCK)
return 0;
for (i=0; i<tdb->num_lockrecs; i++) {
if (tdb->lockrecs[i].list == list) {
if (tdb->lockrecs[i].count == 0) {
/*
* Can't happen, see tdb_unlock(). It should
* be an assert.
*/
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: "
"lck->count == 0 for list %d", list));
}
/*
* Just increment the in-memory struct, posix locks
* don't stack.
*/
tdb->lockrecs[i].count++;
return 0;
}
}
new_lck = (struct tdb_lock_type *)realloc(
tdb->lockrecs,
sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
if (new_lck == NULL) {
errno = ENOMEM;
return -1;
}
tdb->lockrecs = new_lck;
/* Since fcntl locks don't nest, we do a lock for the first one,
and simply bump the count for future ones */
if (tdb->locked[list+1].count == 0) {
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0, 1)) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d ltype=%d (%s)\n",
list, ltype, strerror(errno)));
return -1;
}
tdb->locked[list+1].ltype = ltype;
tdb->num_locks++;
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW,
0, 1)) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
"ltype=%d (%s)\n", list, ltype, strerror(errno)));
return -1;
}
tdb->locked[list+1].count++;
tdb->num_locks++;
tdb->lockrecs[tdb->num_lockrecs].list = list;
tdb->lockrecs[tdb->num_lockrecs].count = 1;
tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
tdb->num_lockrecs += 1;
return 0;
}
@ -146,6 +181,8 @@ int tdb_lock(struct tdb_context *tdb, int list, int ltype)
int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
{
int ret = -1;
int i;
struct tdb_lock_type *lck = NULL;
/* a global lock allows us to avoid per chain locks */
if (tdb->global_lock.count &&
@ -166,19 +203,52 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
return ret;
}
if (tdb->locked[list+1].count==0) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
return ret;
for (i=0; i<tdb->num_lockrecs; i++) {
if (tdb->lockrecs[i].list == list) {
lck = &tdb->lockrecs[i];
break;
}
}
if (tdb->locked[list+1].count == 1) {
/* Down to last nested lock: unlock underneath */
ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0, 1);
tdb->num_locks--;
} else {
ret = 0;
if ((lck == NULL) || (lck->count == 0)) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
return -1;
}
if (lck->count > 1) {
lck->count--;
return 0;
}
/*
* This lock has count==1 left, so we need to unlock it in the
* kernel. We don't bother with decrementing the in-memory array
* element, we're about to overwrite it with the last array element
* anyway.
*/
ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK,
F_SETLKW, 0, 1);
tdb->num_locks--;
/*
* Shrink the array by overwriting the element just unlocked with the
* last array element.
*/
if (tdb->num_lockrecs > 1) {
*lck = tdb->lockrecs[tdb->num_lockrecs-1];
}
tdb->num_lockrecs -= 1;
/*
* We don't bother with realloc when the array shrinks, but if we have
* a completely idle tdb we should get rid of the locked array.
*/
if (tdb->num_lockrecs == 0) {
SAFE_FREE(tdb->lockrecs);
}
tdb->locked[list+1].count--;
if (ret)
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));

View File

@ -263,15 +263,6 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
tdb->map_size = st.st_size;
tdb->device = st.st_dev;
tdb->inode = st.st_ino;
tdb->locked = (struct tdb_lock_type *)calloc(tdb->header.hash_size+1,
sizeof(tdb->locked[0]));
if (!tdb->locked) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
"failed to allocate lock structure for %s\n",
name));
errno = ENOMEM;
goto fail;
}
tdb_mmap(tdb);
if (locked) {
if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
@ -324,7 +315,6 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
if (tdb->fd != -1)
if (close(tdb->fd) != 0)
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
SAFE_FREE(tdb->locked);
SAFE_FREE(tdb);
errno = save_errno;
return NULL;
@ -354,7 +344,7 @@ int tdb_close(struct tdb_context *tdb)
SAFE_FREE(tdb->name);
if (tdb->fd != -1)
ret = close(tdb->fd);
SAFE_FREE(tdb->locked);
SAFE_FREE(tdb->lockrecs);
/* Remove from contexts list */
for (i = &tdbs; *i; i = &(*i)->next) {

View File

@ -123,6 +123,7 @@ struct tdb_header {
};
struct tdb_lock_type {
int list;
u32 count;
u32 ltype;
};
@ -152,7 +153,8 @@ struct tdb_context {
int read_only; /* opened read-only */
int traverse_read; /* read-only traversal */
struct tdb_lock_type global_lock;
struct tdb_lock_type *locked; /* array of chain locks */
int num_lockrecs;
struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
enum TDB_ERROR ecode; /* error code for last tdb error */
struct tdb_header header; /* a cached copy of the header */
u32 flags; /* the flags passed to tdb_open */

View File

@ -520,12 +520,10 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
/* remove any locks created during the transaction */
if (tdb->num_locks != 0) {
int h;
for (h=0;h<tdb->header.hash_size+1;h++) {
if (tdb->locked[h].count != 0) {
tdb_brlock(tdb,FREELIST_TOP+4*h,F_UNLCK,F_SETLKW, 0, 1);
tdb->locked[h].count = 0;
}
int i;
for (i=0;i<tdb->num_lockrecs;i++) {
tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list,
F_UNLCK,F_SETLKW, 0, 1);
}
tdb->num_locks = 0;
}