#include "db_config.h"
#include "db_int.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
static int __lock_sort_cmp __P((const void *, const void *));
#define MAX_PGNOS 0xffff
#define RET_SIZE(size, count) ((size) + \
sizeof(u_int32_t) + (count) * 2 * sizeof(u_int16_t))
#define PUT_COUNT(dp, count) do { u_int32_t __c = (count); \
LOGCOPY_32(env, dp, &__c); \
dp = (u_int8_t *)dp + \
sizeof(u_int32_t); \
} while (0)
#define PUT_PCOUNT(dp, count) do { u_int16_t __c = (count); \
LOGCOPY_16(env, dp, &__c); \
dp = (u_int8_t *)dp + \
sizeof(u_int16_t); \
} while (0)
#define PUT_SIZE(dp, size) do { u_int16_t __s = (size); \
LOGCOPY_16(env, dp, &__s); \
dp = (u_int8_t *)dp + \
sizeof(u_int16_t); \
} while (0)
#define PUT_PGNO(dp, pgno) do { db_pgno_t __pg = (pgno); \
LOGCOPY_32(env, dp, &__pg); \
dp = (u_int8_t *)dp + \
sizeof(db_pgno_t); \
} while (0)
#define COPY_OBJ(dp, obj) do { \
memcpy(dp, \
(obj)->data, (obj)->size); \
dp = (u_int8_t *)dp + \
DB_ALIGN((obj)->size, \
sizeof(u_int32_t)); \
} while (0)
#define GET_COUNT(dp, count) do { LOGCOPY_32(env, &count, dp); \
dp = (u_int8_t *)dp + \
sizeof(u_int32_t); \
} while (0)
#define GET_PCOUNT(dp, count) do { LOGCOPY_16(env, &count, dp); \
dp = (u_int8_t *)dp + \
sizeof(u_int16_t); \
} while (0)
#define GET_SIZE(dp, size) do { LOGCOPY_16(env, &size, dp); \
dp = (u_int8_t *)dp + \
sizeof(u_int16_t); \
} while (0)
#define GET_PGNO(dp, pgno) do { LOGCOPY_32(env, &pgno, dp); \
dp = (u_int8_t *)dp + \
sizeof(db_pgno_t); \
} while (0)
int
__lock_fix_list(env, list_dbt, nlocks)
ENV *env;
DBT *list_dbt;
u_int32_t nlocks;
{
DBT *obj;
DB_LOCK_ILOCK *lock, *plock;
u_int32_t i, j, nfid, npgno, size;
u_int8_t *data, *dp;
int ret;
if ((size = list_dbt->size) == 0)
return (0);
obj = (DBT *)list_dbt->data;
switch (nlocks) {
case 1:
size = RET_SIZE(obj->size, 1);
if ((ret = __os_malloc(env, size, &data)) != 0)
return (ret);
dp = data;
PUT_COUNT(dp, 1);
PUT_PCOUNT(dp, 0);
PUT_SIZE(dp, obj->size);
COPY_OBJ(dp, obj);
break;
default:
qsort(list_dbt->data, nlocks, sizeof(DBT), __lock_sort_cmp);
case 2:
nfid = npgno = 0;
i = 0;
if (obj->size != sizeof(DB_LOCK_ILOCK))
goto not_ilock;
nfid = 1;
plock = (DB_LOCK_ILOCK *)obj->data;
j = 0;
obj[0].ulen = 0;
for (i = 1; i < nlocks; i++) {
if (obj[i].size != sizeof(DB_LOCK_ILOCK))
break;
lock = (DB_LOCK_ILOCK *)obj[i].data;
if (obj[j].ulen < MAX_PGNOS &&
lock->type == plock->type &&
memcmp(lock->fileid,
plock->fileid, DB_FILE_ID_LEN) == 0) {
obj[j].ulen++;
npgno++;
} else {
nfid++;
plock = lock;
j = i;
obj[j].ulen = 0;
}
}
not_ilock: size = nfid * sizeof(DB_LOCK_ILOCK);
size += npgno * sizeof(db_pgno_t);
nfid += nlocks - i;
for (; i < nlocks; i++) {
size += obj[i].size;
obj[i].ulen = 0;
}
size = RET_SIZE(size, nfid);
if ((ret = __os_malloc(env, size, &data)) != 0)
return (ret);
dp = data;
PUT_COUNT(dp, nfid);
for (i = 0; i < nlocks; i = j) {
PUT_PCOUNT(dp, obj[i].ulen);
PUT_SIZE(dp, obj[i].size);
COPY_OBJ(dp, &obj[i]);
lock = (DB_LOCK_ILOCK *)obj[i].data;
for (j = i + 1; j <= i + obj[i].ulen; j++) {
lock = (DB_LOCK_ILOCK *)obj[j].data;
PUT_PGNO(dp, lock->pgno);
}
}
}
__os_free(env, list_dbt->data);
list_dbt->data = data;
list_dbt->size = size;
return (0);
}
int
__lock_get_list(env, locker, flags, lock_mode, list)
ENV *env;
DB_LOCKER *locker;
u_int32_t flags;
db_lockmode_t lock_mode;
DBT *list;
{
DBT obj_dbt;
DB_LOCK ret_lock;
DB_LOCKREGION *region;
DB_LOCKTAB *lt;
DB_LOCK_ILOCK *lock;
db_pgno_t save_pgno;
u_int16_t npgno, size;
u_int32_t i, nlocks;
int ret;
void *data, *dp;
if (list->size == 0)
return (0);
ret = 0;
data = NULL;
lt = env->lk_handle;
dp = list->data;
if ((uintptr_t)dp != DB_ALIGN((uintptr_t)dp, sizeof(u_int32_t))) {
if ((ret = __os_malloc(env, list->size, &data)) != 0)
return (ret);
memcpy(data, list->data, list->size);
dp = data;
}
region = lt->reginfo.primary;
LOCK_SYSTEM_LOCK(lt, region);
GET_COUNT(dp, nlocks);
for (i = 0; i < nlocks; i++) {
GET_PCOUNT(dp, npgno);
GET_SIZE(dp, size);
lock = (DB_LOCK_ILOCK *) dp;
save_pgno = lock->pgno;
obj_dbt.data = dp;
obj_dbt.size = size;
dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
do {
if ((ret = __lock_get_internal(lt, locker,
flags, &obj_dbt, lock_mode, 0, &ret_lock)) != 0) {
lock->pgno = save_pgno;
goto err;
}
if (npgno != 0)
GET_PGNO(dp, lock->pgno);
} while (npgno-- != 0);
lock->pgno = save_pgno;
}
err: LOCK_SYSTEM_UNLOCK(lt, region);
if (data != NULL)
__os_free(env, data);
return (ret);
}
#define UINT32_CMP(A, B) ((A) == (B) ? 0 : ((A) > (B) ? 1 : -1))
static int
__lock_sort_cmp(a, b)
const void *a, *b;
{
const DBT *d1, *d2;
DB_LOCK_ILOCK *l1, *l2;
d1 = a;
d2 = b;
if (d1->size != sizeof(DB_LOCK_ILOCK)) {
if (d2->size != sizeof(DB_LOCK_ILOCK))
return (UINT32_CMP(d1->size, d2->size));
else
return (1);
} else if (d2->size != sizeof(DB_LOCK_ILOCK))
return (-1);
l1 = d1->data;
l2 = d2->data;
if (l1->type != l2->type)
return (UINT32_CMP(l1->type, l2->type));
return (memcmp(l1->fileid, l2->fileid, DB_FILE_ID_LEN));
}
void
__lock_list_print(env, list)
ENV *env;
DBT *list;
{
DB_LOCK_ILOCK *lock;
db_pgno_t pgno;
u_int16_t npgno, size;
u_int32_t i, nlocks;
u_int8_t *fidp;
char *fname, *dname, *p, namebuf[26];
void *dp;
if (list->size == 0)
return;
dp = list->data;
GET_COUNT(dp, nlocks);
for (i = 0; i < nlocks; i++) {
GET_PCOUNT(dp, npgno);
GET_SIZE(dp, size);
lock = (DB_LOCK_ILOCK *) dp;
fidp = lock->fileid;
(void)__dbreg_get_name(env, fidp, &fname, &dname);
printf("\t");
if (fname == NULL && dname == NULL)
printf("(%lx %lx %lx %lx %lx)",
(u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2],
(u_long)fidp[3], (u_long)fidp[4]);
else {
if (fname != NULL && dname != NULL) {
(void)snprintf(namebuf, sizeof(namebuf),
"%14s.%-10s", fname, dname);
p = namebuf;
} else if (fname != NULL)
p = fname;
else
p = dname;
printf("%-25s", p);
}
dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
LOGCOPY_32(env, &pgno, &lock->pgno);
do {
printf(" %d", pgno);
if (npgno != 0)
GET_PGNO(dp, pgno);
} while (npgno-- != 0);
printf("\n");
}
}