2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
12 #include "dbinc/lock.h"
13 #include "dbinc/log.h"
15 static int __lock_sort_cmp __P((const void *, const void *));
19 * The list is composed of a 32-bit count of locks followed by
20 * each lock. A lock is represented by a 16-bit page-count, a lock
21 * object and a page list. A lock object consists of a 16-bit size
22 * and the object itself. In a pseudo BNF notation, you get:
24 * LIST = COUNT32 LOCK*
25 * LOCK = COUNT16 LOCKOBJ PAGELIST
26 * LOCKOBJ = COUNT16 OBJ
29 * (Recall that X* means "0 or more X's")
31 * In most cases, the OBJ is a struct __db_ilock and the page list is
32 * a series of (32-bit) page numbers that should get written into the
33 * pgno field of the __db_ilock. So, the actual number of pages locked
34 * is the number of items in the PAGELIST plus 1. If this is an application-
35 * specific lock, then we cannot interpret obj and the pagelist must
38 * Consider a lock list for: File A, pages 1&2, File B pages 3-5, Applock
39 * This would be represented as:
40 * 5 1 [fid=A;page=1] 2 2 [fid=B;page=3] 4 5 0 APPLOCK
41 * ------------------ -------------------- ---------
42 * LOCK for file A LOCK for file B application-specific lock
45 #define MAX_PGNOS 0xffff
48 * These macros are bigger than one might expect because some compilers say a
49 * cast does not return an lvalue, so constructs like *(u_int32_t*)dp = count;
52 #define RET_SIZE(size, count) ((size) + \
53 sizeof(u_int32_t) + (count) * 2 * sizeof(u_int16_t))
55 #define PUT_COUNT(dp, count) do { u_int32_t __c = (count); \
56 LOGCOPY_32(env, dp, &__c); \
57 dp = (u_int8_t *)dp + \
60 #define PUT_PCOUNT(dp, count) do { u_int16_t __c = (count); \
61 LOGCOPY_16(env, dp, &__c); \
62 dp = (u_int8_t *)dp + \
65 #define PUT_SIZE(dp, size) do { u_int16_t __s = (size); \
66 LOGCOPY_16(env, dp, &__s); \
67 dp = (u_int8_t *)dp + \
70 #define PUT_PGNO(dp, pgno) do { db_pgno_t __pg = (pgno); \
71 LOGCOPY_32(env, dp, &__pg); \
72 dp = (u_int8_t *)dp + \
75 #define COPY_OBJ(dp, obj) do { \
77 (obj)->data, (obj)->size); \
78 dp = (u_int8_t *)dp + \
79 DB_ALIGN((obj)->size, \
82 #define GET_COUNT(dp, count) do { LOGCOPY_32(env, &count, dp); \
83 dp = (u_int8_t *)dp + \
86 #define GET_PCOUNT(dp, count) do { LOGCOPY_16(env, &count, dp); \
87 dp = (u_int8_t *)dp + \
90 #define GET_SIZE(dp, size) do { LOGCOPY_16(env, &size, dp); \
91 dp = (u_int8_t *)dp + \
94 #define GET_PGNO(dp, pgno) do { LOGCOPY_32(env, &pgno, dp); \
95 dp = (u_int8_t *)dp + \
102 * PUBLIC: int __lock_fix_list __P((ENV *, DBT *, u_int32_t));
105 __lock_fix_list(env, list_dbt, nlocks)
111 DB_LOCK_ILOCK *lock, *plock;
112 u_int32_t i, j, nfid, npgno, size;
116 if ((size = list_dbt->size) == 0)
119 obj = (DBT *)list_dbt->data;
122 * If necessary sort the list of locks so that locks on the same fileid
123 * are together. We do not sort 1 or 2 locks because by definition if
124 * there are locks on the same fileid they will be together. The sort
125 * will also move any locks that do not look like page locks to the end
126 * of the list so we can stop looking for locks we can combine when we
131 size = RET_SIZE(obj->size, 1);
132 if ((ret = __os_malloc(env, size, &data)) != 0)
138 PUT_SIZE(dp, obj->size);
142 /* Sort so that all locks with same fileid are together. */
143 qsort(list_dbt->data, nlocks, sizeof(DBT), __lock_sort_cmp);
148 if (obj->size != sizeof(DB_LOCK_ILOCK))
152 plock = (DB_LOCK_ILOCK *)obj->data;
154 /* We use ulen to keep track of the number of pages. */
157 for (i = 1; i < nlocks; i++) {
158 if (obj[i].size != sizeof(DB_LOCK_ILOCK))
160 lock = (DB_LOCK_ILOCK *)obj[i].data;
161 if (obj[j].ulen < MAX_PGNOS &&
162 lock->type == plock->type &&
164 plock->fileid, DB_FILE_ID_LEN) == 0) {
175 not_ilock: size = nfid * sizeof(DB_LOCK_ILOCK);
176 size += npgno * sizeof(db_pgno_t);
177 /* Add the number of nonstandard locks and get their size. */
179 for (; i < nlocks; i++) {
184 size = RET_SIZE(size, nfid);
185 if ((ret = __os_malloc(env, size, &data)) != 0)
191 for (i = 0; i < nlocks; i = j) {
192 PUT_PCOUNT(dp, obj[i].ulen);
193 PUT_SIZE(dp, obj[i].size);
194 COPY_OBJ(dp, &obj[i]);
195 lock = (DB_LOCK_ILOCK *)obj[i].data;
196 for (j = i + 1; j <= i + obj[i].ulen; j++) {
197 lock = (DB_LOCK_ILOCK *)obj[j].data;
198 PUT_PGNO(dp, lock->pgno);
203 __os_free(env, list_dbt->data);
205 list_dbt->data = data;
206 list_dbt->size = size;
212 * PUBLIC: int __lock_get_list __P((ENV *, DB_LOCKER *, u_int32_t,
213 * PUBLIC: db_lockmode_t, DBT *));
216 __lock_get_list(env, locker, flags, lock_mode, list)
220 db_lockmode_t lock_mode;
225 DB_LOCKREGION *region;
229 u_int16_t npgno, size;
243 * There is no assurance log records will be aligned. If not, then
244 * copy the data to an aligned region so the rest of the code does
245 * not have to worry about it.
247 if ((uintptr_t)dp != DB_ALIGN((uintptr_t)dp, sizeof(u_int32_t))) {
248 if ((ret = __os_malloc(env, list->size, &data)) != 0)
250 memcpy(data, list->data, list->size);
254 region = lt->reginfo.primary;
255 LOCK_SYSTEM_LOCK(lt, region);
256 GET_COUNT(dp, nlocks);
258 for (i = 0; i < nlocks; i++) {
259 GET_PCOUNT(dp, npgno);
261 lock = (DB_LOCK_ILOCK *) dp;
262 save_pgno = lock->pgno;
265 dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
267 if ((ret = __lock_get_internal(lt, locker,
268 flags, &obj_dbt, lock_mode, 0, &ret_lock)) != 0) {
269 lock->pgno = save_pgno;
273 GET_PGNO(dp, lock->pgno);
274 } while (npgno-- != 0);
275 lock->pgno = save_pgno;
278 err: LOCK_SYSTEM_UNLOCK(lt, region);
280 __os_free(env, data);
284 #define UINT32_CMP(A, B) ((A) == (B) ? 0 : ((A) > (B) ? 1 : -1))
286 __lock_sort_cmp(a, b)
290 DB_LOCK_ILOCK *l1, *l2;
295 /* Force all non-standard locks to sort at end. */
296 if (d1->size != sizeof(DB_LOCK_ILOCK)) {
297 if (d2->size != sizeof(DB_LOCK_ILOCK))
298 return (UINT32_CMP(d1->size, d2->size));
301 } else if (d2->size != sizeof(DB_LOCK_ILOCK))
306 if (l1->type != l2->type)
307 return (UINT32_CMP(l1->type, l2->type));
308 return (memcmp(l1->fileid, l2->fileid, DB_FILE_ID_LEN));
312 * PUBLIC: void __lock_list_print __P((ENV *, DBT *));
315 __lock_list_print(env, list)
321 u_int16_t npgno, size;
324 char *fname, *dname, *p, namebuf[26];
331 GET_COUNT(dp, nlocks);
333 for (i = 0; i < nlocks; i++) {
334 GET_PCOUNT(dp, npgno);
336 lock = (DB_LOCK_ILOCK *) dp;
338 (void)__dbreg_get_name(env, fidp, &fname, &dname);
340 if (fname == NULL && dname == NULL)
341 printf("(%lx %lx %lx %lx %lx)",
342 (u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2],
343 (u_long)fidp[3], (u_long)fidp[4]);
345 if (fname != NULL && dname != NULL) {
346 (void)snprintf(namebuf, sizeof(namebuf),
347 "%14s.%-10s", fname, dname);
349 } else if (fname != NULL)
355 dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
356 LOGCOPY_32(env, &pgno, &lock->pgno);
361 } while (npgno-- != 0);