Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

lock_list.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: lock_list.c,v 12.5 2005/10/20 18:26:04 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #endif
00018 
00019 #include "db_int.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/lock.h"
00022 #include "dbinc/log.h"
00023 
00024 static int __lock_sort_cmp __P((const void *, const void *));
00025 
00026 /*
00027  * Lock list routines.
00028  *      The list is composed of a 32-bit count of locks followed by
00029  * each lock.  A lock is represented by a 16-bit page-count, a lock
00030  * object and a page list.  A lock object consists of a 16-bit size
00031  * and the object itself.   In a pseudo BNF notation, you get:
00032  *
00033  * LIST = COUNT32 LOCK*
00034  * LOCK = COUNT16 LOCKOBJ PAGELIST
00035  * LOCKOBJ = COUNT16 OBJ
00036  * PAGELIST = COUNT32*
00037  *
00038  * (Recall that X* means "0 or more X's")
00039  *
00040  * In most cases, the OBJ is a struct __db_ilock and the page list is
00041  * a series of (32-bit) page numbers that should get written into the
00042  * pgno field of the __db_ilock.  So, the actual number of pages locked
00043  * is the number of items in the PAGELIST plus 1. If this is an application-
00044  * specific lock, then we cannot interpret obj and the pagelist must
00045  * be empty.
00046  *
00047  * Consider a lock list for: File A, pages 1&2, File B pages 3-5, Applock
00048  * This would be represented as:
00049  *      5 1 [fid=A;page=1] 2 2 [fid=B;page=3] 4 5 0 APPLOCK
00050  *        ------------------ -------------------- ---------
00051  *         LOCK for file A    LOCK for file B     application-specific lock
00052  */
00053 
00054 #define MAX_PGNOS       0xffff
00055 
00056 /*
00057  * These macros are bigger than one might expect because some compilers say a
00058  * cast does not return an lvalue, so constructs like *(u_int32_t*)dp = count;
00059  * generate warnings.
00060  */
00061 #define RET_SIZE(size, count)  ((size) +                                \
00062      sizeof(u_int32_t) + (count) * 2 * sizeof(u_int16_t))
00063 
00064 #define PUT_COUNT(dp, count)    do {    u_int32_t *ip = (u_int32_t *)dp;\
00065                                         *ip = count;                    \
00066                                         dp = (u_int8_t *)dp +           \
00067                                              sizeof(u_int32_t);         \
00068                                 } while (0)
00069 #define PUT_PCOUNT(dp, count)   do {    u_int16_t *ip = (u_int16_t *)dp;\
00070                                         *ip = count;                    \
00071                                         dp = (u_int8_t *)dp +           \
00072                                             sizeof(u_int16_t);          \
00073                                 } while (0)
00074 #define PUT_SIZE(dp, size)      do {    u_int16_t *ip = (u_int16_t *)dp;\
00075                                         *ip = size;                     \
00076                                         dp = (u_int8_t *)dp +           \
00077                                             sizeof(u_int16_t);          \
00078                                 } while (0)
00079 #define PUT_PGNO(dp, pgno)      do {    db_pgno_t *ip = (db_pgno_t *)dp;\
00080                                         *ip = pgno;                     \
00081                                         dp = (u_int8_t *)dp +           \
00082                                             sizeof(db_pgno_t);          \
00083                                 } while (0)
00084 #define COPY_OBJ(dp, obj)       do {                                    \
00085                                         memcpy(dp,                      \
00086                                             (obj)->data, (obj)->size);  \
00087                                         dp = (u_int8_t *)dp +           \
00088                                              DB_ALIGN((obj)->size,      \
00089                                              sizeof(u_int32_t));        \
00090                                 } while (0)
00091 #define GET_COUNT(dp, count)    do {                                    \
00092                                         (count) = *(u_int32_t *)dp;     \
00093                                         dp = (u_int8_t *)dp +           \
00094                                              sizeof(u_int32_t); \
00095                                 } while (0)
00096 #define GET_PCOUNT(dp, count)   do {                                    \
00097                                         (count) = *(u_int16_t *)dp;     \
00098                                         dp = (u_int8_t *)dp +           \
00099                                              sizeof(u_int16_t); \
00100                                 } while (0)
00101 #define GET_SIZE(dp, size)      do {                                    \
00102                                         (size) = *(u_int16_t *)dp;      \
00103                                         dp = (u_int8_t *)dp +           \
00104                                              sizeof(u_int16_t); \
00105                                 } while (0)
00106 #define GET_PGNO(dp, pgno)      do {                                    \
00107                                         (pgno) = *(db_pgno_t *)dp;      \
00108                                         dp = (u_int8_t *)dp +           \
00109                                              sizeof(db_pgno_t); \
00110                                 } while (0)
00111 
00112 /*
00113  * __lock_fix_list --
00114  *
00115  * PUBLIC: int __lock_fix_list __P((DB_ENV *, DBT *, u_int32_t));
00116  */
00117 int
00118 __lock_fix_list(dbenv, list_dbt, nlocks)
00119         DB_ENV *dbenv;
00120         DBT *list_dbt;
00121         u_int32_t nlocks;
00122 {
00123         DBT *obj;
00124         DB_LOCK_ILOCK *lock, *plock;
00125         u_int32_t i, j, nfid, npgno, size;
00126         u_int8_t *data, *dp;
00127         int ret;
00128 
00129         if ((size = list_dbt->size) == 0)
00130                 return (0);
00131 
00132         obj = (DBT *)list_dbt->data;
00133 
00134         /*
00135          * If necessary sort the list of locks so that locks on the same fileid
00136          * are together.  We do not sort 1 or 2 locks because by definition if
00137          * there are locks on the same fileid they will be together.  The sort
00138          * will also move any locks that do not look like page locks to the end
00139          * of the list so we can stop looking for locks we can combine when we
00140          * hit one.
00141          */
00142         switch (nlocks) {
00143         case 1:
00144                 size = RET_SIZE(obj->size, 1);
00145                 if ((ret = __os_malloc(dbenv, size, &data)) != 0)
00146                         return (ret);
00147 
00148                 dp = data;
00149                 PUT_COUNT(dp, 1);
00150                 PUT_PCOUNT(dp, 0);
00151                 PUT_SIZE(dp, obj->size);
00152                 COPY_OBJ(dp, obj);
00153                 break;
00154         default:
00155                 /* Sort so that all locks with same fileid are together. */
00156                 qsort(list_dbt->data, nlocks, sizeof(DBT), __lock_sort_cmp);
00157                 /* FALLTHROUGH */
00158         case 2:
00159                 nfid = npgno = 0;
00160                 i = 0;
00161                 if (obj->size != sizeof(DB_LOCK_ILOCK))
00162                         goto not_ilock;
00163 
00164                 nfid = 1;
00165                 plock = (DB_LOCK_ILOCK *)obj->data;
00166 
00167                 /* We use ulen to keep track of the number of pages. */
00168                 j = 0;
00169                 obj[0].ulen = 0;
00170                 for (i = 1; i < nlocks; i++) {
00171                         if (obj[i].size != sizeof(DB_LOCK_ILOCK))
00172                                 break;
00173                         lock = (DB_LOCK_ILOCK *)obj[i].data;
00174                         if (obj[j].ulen < MAX_PGNOS &&
00175                              lock->type == plock->type &&
00176                              memcmp(lock->fileid,
00177                              plock->fileid, DB_FILE_ID_LEN) == 0) {
00178                                 obj[j].ulen++;
00179                                 npgno++;
00180                         } else {
00181                                 nfid++;
00182                                 plock = lock;
00183                                 j = i;
00184                                 obj[j].ulen = 0;
00185                         }
00186                 }
00187 
00188 not_ilock:      size = nfid * sizeof(DB_LOCK_ILOCK);
00189                 size += npgno * sizeof(db_pgno_t);
00190                 /* Add the number of nonstandard locks and get their size. */
00191                 nfid += nlocks - i;
00192                 for (; i < nlocks; i++) {
00193                         size += obj[i].size;
00194                         obj[i].ulen = 0;
00195                 }
00196 
00197                 size = RET_SIZE(size, nfid);
00198                 if ((ret = __os_malloc(dbenv, size, &data)) != 0)
00199                         return (ret);
00200 
00201                 dp = data;
00202                 PUT_COUNT(dp, nfid);
00203 
00204                 for (i = 0; i < nlocks; i = j) {
00205                         PUT_PCOUNT(dp, obj[i].ulen);
00206                         PUT_SIZE(dp, obj[i].size);
00207                         COPY_OBJ(dp, &obj[i]);
00208                         lock = (DB_LOCK_ILOCK *)obj[i].data;
00209                         for (j = i + 1; j <= i + obj[i].ulen; j++) {
00210                                 lock = (DB_LOCK_ILOCK *)obj[j].data;
00211                                 PUT_PGNO(dp, lock->pgno);
00212                         }
00213                 }
00214         }
00215 
00216         __os_free(dbenv, list_dbt->data);
00217 
00218         list_dbt->data = data;
00219         list_dbt->size = size;
00220 
00221         return (0);
00222 }
00223 
00224 /*
00225  * PUBLIC: int __lock_get_list __P((DB_ENV *, u_int32_t, u_int32_t,
00226  * PUBLIC:            db_lockmode_t, DBT *));
00227  */
00228 int
00229 __lock_get_list(dbenv, locker, flags, lock_mode, list)
00230         DB_ENV *dbenv;
00231         u_int32_t locker, flags;
00232         db_lockmode_t lock_mode;
00233         DBT *list;
00234 {
00235         DBT obj_dbt;
00236         DB_LOCK ret_lock;
00237         DB_LOCK_ILOCK *lock;
00238         DB_LOCKTAB *lt;
00239         db_pgno_t save_pgno;
00240         u_int16_t npgno, size;
00241         u_int32_t i, nlocks;
00242         int ret;
00243         void *data, *dp;
00244 
00245         if (list->size == 0)
00246                 return (0);
00247         ret = 0;
00248         data = NULL;
00249 
00250         lt = dbenv->lk_handle;
00251         dp = list->data;
00252 
00253         /*
00254          * There is no assurance log records will be aligned.  If not, then
00255          * copy the data to an aligned region so the rest of the code does
00256          * not have to worry about it.
00257          */
00258         if ((uintptr_t)dp != DB_ALIGN((uintptr_t)dp, sizeof(u_int32_t))) {
00259                 if ((ret = __os_malloc(dbenv, list->size, &data)) != 0)
00260                         return (ret);
00261                 memcpy(data, list->data, list->size);
00262                 dp = data;
00263         }
00264 
00265         GET_COUNT(dp, nlocks);
00266         LOCK_SYSTEM_LOCK(dbenv);
00267 
00268         for (i = 0; i < nlocks; i++) {
00269                 GET_PCOUNT(dp, npgno);
00270                 GET_SIZE(dp, size);
00271                 lock = (DB_LOCK_ILOCK *) dp;
00272                 save_pgno = lock->pgno;
00273                 obj_dbt.data = dp;
00274                 obj_dbt.size = size;
00275                 dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
00276                 do {
00277                         if ((ret = __lock_get_internal(lt, locker,
00278                              flags, &obj_dbt, lock_mode, 0, &ret_lock)) != 0) {
00279                              lock->pgno = save_pgno;
00280                              goto err;
00281                         }
00282                         if (npgno != 0)
00283                                 GET_PGNO(dp, lock->pgno);
00284                 } while (npgno-- != 0);
00285                 lock->pgno = save_pgno;
00286         }
00287 
00288 err:    LOCK_SYSTEM_UNLOCK(dbenv);
00289         if (data != NULL)
00290                 __os_free(dbenv, data);
00291         return (ret);
00292 }
00293 
00294 #define UINT32_CMP(A, B)        ((A) == (B) ? 0 : ((A) > (B) ? 1 : -1))
00295 static int
00296 __lock_sort_cmp(a, b)
00297         const void *a, *b;
00298 {
00299         const DBT *d1, *d2;
00300         DB_LOCK_ILOCK *l1, *l2;
00301 
00302         d1 = a;
00303         d2 = b;
00304 
00305         /* Force all non-standard locks to sort at end. */
00306         if (d1->size != sizeof(DB_LOCK_ILOCK)) {
00307                 if (d2->size != sizeof(DB_LOCK_ILOCK))
00308                         return (UINT32_CMP(d1->size, d2->size));
00309                 else
00310                         return (1);
00311         } else if (d2->size != sizeof(DB_LOCK_ILOCK))
00312                 return (-1);
00313 
00314         l1 = d1->data;
00315         l2 = d2->data;
00316         if (l1->type != l2->type)
00317                 return (UINT32_CMP(l1->type, l2->type));
00318         return (memcmp(l1->fileid, l2->fileid, DB_FILE_ID_LEN));
00319 }
00320 
00321 /*
00322  * PUBLIC: void __lock_list_print __P((DB_ENV *, DBT *));
00323  */
00324 void
00325 __lock_list_print(dbenv, list)
00326         DB_ENV *dbenv;
00327         DBT *list;
00328 {
00329         DB_LOCK_ILOCK *lock;
00330         db_pgno_t pgno;
00331         u_int16_t npgno, size;
00332         u_int32_t i, nlocks;
00333         u_int8_t *fidp;
00334         char *namep;
00335         void *dp;
00336 
00337         if (list->size == 0)
00338                 return;
00339         dp = list->data;
00340 
00341         GET_COUNT(dp, nlocks);
00342 
00343         for (i = 0; i < nlocks; i++) {
00344                 GET_PCOUNT(dp, npgno);
00345                 GET_SIZE(dp, size);
00346                 lock = (DB_LOCK_ILOCK *) dp;
00347                 fidp = lock->fileid;
00348                 if (__dbreg_get_name(dbenv, fidp, &namep) != 0)
00349                         namep = NULL;
00350                 printf("\t");
00351                 if (namep == NULL)
00352                         printf("(%lx %lx %lx %lx %lx)",
00353                         (u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2],
00354                         (u_long)fidp[3], (u_long)fidp[4]);
00355                 else
00356                         printf("%-25s", namep);
00357                 dp = ((u_int8_t *)dp) + DB_ALIGN(size, sizeof(u_int32_t));
00358                 pgno = lock->pgno;
00359                 do {
00360                         printf(" %d", pgno);
00361                         if (npgno != 0)
00362                                 GET_PGNO(dp, pgno);
00363                 } while (npgno-- != 0);
00364                 printf("\n");
00365         }
00366 }

Generated on Sun Dec 25 12:14:40 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2