00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <eyedbconfig.h>
00025
00026 #include <stdlib.h>
00027 #include <stdarg.h>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #include <fcntl.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <errno.h>
00034 #include <sys/mman.h>
00035 #include <pthread.h>
00036 #include <lock.h>
00037
00038 #include <eyedbsm_p.h>
00039 #include <eyedblib/iassert.h>
00040 #include <eyedblib/rpc_be.h>
00041 #include <eyedblib/log.h>
00042 #include <lib/m_mem_p.h>
00043
00044 #define TRACE(X)
00045
00046 #define DBLOCK_LOCK(VD, XID) MUTEX_LOCK_VOID(DBLOCK_MTX(VD), XID)
00047 #define DBLOCK_UNLOCK(VD, XID) MUTEX_UNLOCK(DBLOCK_MTX(VD), XID)
00048 #define DBLOCK_COND_WAIT_R(VD, XID, TM) COND_WAIT_R(DBLOCK_COND(VD), DBLOCK_MTX(VD), XID, TM)
00049 #define DBLOCK_COND_SIGNAL(VD) COND_SIGNAL(DBLOCK_COND(VD))
00050
00051 #define MKXID(X, XID) XID
00052
00053 #define SX_MODE
00054
00055 #define CHECK_CONN(X) \
00056 if (rpc_checkConn() < 0) \
00057 { \
00058 X; \
00059 return statusMake(CONN_RESET_BY_PEER, ""); \
00060 }
00061
00062 #define TIMEOUT 10
00063
00064 #define WAIT_CHECK(MAXTIME, NS, X, FMT, MSG) \
00065 do { \
00066 IDB_LOG(IDB_LOG_MTX, ("object locked. Waiting for maxtime=%d\n", MAXTIME)); \
00067 if (backend_interrupt) { \
00068 backend_interrupt = False; \
00069 X; \
00070 fprintf(stderr, "backend interrupt!\n"); \
00071 return statusMake(BACKEND_INTERRUPTED, FMT, MSG); \
00072 } \
00073 else if (NS < 0) { \
00074 MAXTIME += NS; \
00075 if ((int)(MAXTIME) <= 0) { \
00076 X; \
00077 return statusMake(LOCK_TIMEOUT, FMT, MSG); \
00078 } \
00079 } \
00080 else if (NS > 0) { \
00081 X; \
00082 if (errno != 0) \
00083 perror("lock"); \
00084 return statusMake(INTERNAL_ERROR, FMT ": cannot acquire lock", MSG); \
00085 } \
00086 } \
00087 while(0)
00088
00089 namespace eyedbsm {
00090
00091 static Status addXid(DbLock *dblock, Mutex *mp, unsigned int xid)
00092 {
00093 int i;
00094 unsigned int *pxid = dblock->xidS;
00095
00096 for (i = 0; i < MAXCLIENTS_PERDB; i++, pxid++)
00097 if (!*pxid) {
00098 *pxid = xid;
00099 return Success;
00100 }
00101
00102 ESM_ASSERT(0, mp, xid);
00103 }
00104
00105 static Status
00106 rmXid(DbLock *dblock, Mutex *mp, unsigned int xid)
00107 {
00108 int i;
00109 unsigned int *pxid = dblock->xidS;
00110
00111 for (i = 0; i < MAXCLIENTS_PERDB; i++, pxid++)
00112 if (*pxid == xid) {
00113 *pxid = 0;
00114 return Success;
00115 }
00116
00117 ESM_ASSERT(0, mp, xid);
00118 }
00119
00120 void lockInit(DbDescription *vd, DbLock *dblock, const char *name)
00121 {
00122 mutexInit(vd, DBLOCK_MTX(vd), &dblock->mp, name);
00123 condInit(vd, DBLOCK_COND(vd), &dblock->cond_wait);
00124 dblock->X = 0;
00125 dblock->S = 0;
00126 dblock->wt_cnt = 0;
00127 dblock->xidX = 0;
00128 memset(dblock->xidS, 0, MAXCLIENTS_PERDB * sizeof(unsigned int));
00129 }
00130
00131 void lockLightInit(DbDescription *vd, DbLock *dblock)
00132 {
00133 mutexLightInit(vd, DBLOCK_MTX(vd), &dblock->mp);
00134 condLightInit(vd, DBLOCK_COND(vd), &dblock->cond_wait);
00135 }
00136
00137 bool findDbLockXID(DbDescription *vd, DbLock *dblock, unsigned int xid,
00138 bool *lockX, Boolean mustLock)
00139 {
00140 int i;
00141 unsigned int *pxid;
00142
00143 if (mustLock)
00144 DBLOCK_LOCK(vd, xid);
00145 if (xid == dblock->xidX) {
00146 if (mustLock)
00147 DBLOCK_UNLOCK(vd, xid);
00148 if (lockX)
00149 *lockX = true;
00150 return true;
00151 }
00152
00153 pxid = dblock->xidS;
00154
00155 for (i = 0; i < MAXCLIENTS_PERDB; i++, pxid++)
00156 if (*pxid == xid) {
00157 if (mustLock)
00158 DBLOCK_UNLOCK(vd, xid);
00159 if (lockX)
00160 *lockX = false;
00161 return true;
00162 }
00163
00164 if (mustLock)
00165 DBLOCK_UNLOCK(vd, xid);
00166 return false;
00167 }
00168
00169 Status
00170 lockS(DbDescription *vd, DbLock *dblock, unsigned int xid,
00171 unsigned int timeout)
00172 {
00173 int x;
00174 unsigned int maxtime = timeout;
00175 Status se;
00176
00177 TRACE(printf("\n------LOCK_S------ thread = %d, timeout = %d\n\n",
00178 thr_self(), timeout));
00179
00180 for (x = 0; ; x++) {
00181 if (!x)
00182 DBLOCK_LOCK(vd, xid);
00183
00184 if (!dblock->X) {
00185 dblock->S++;
00186 se = addXid(dblock, &vd->mp[MTX_CNT], xid);
00187 DBLOCK_UNLOCK(vd, MKXID(x, xid));
00188 TRACE(printf("\n------LOCK_S DONE------ thread = %d\n\n", thr_self()));
00189 if (se)
00190 return se;
00191 break;
00192 }
00193 else if (!timeout) {
00194 WAIT_CHECK(maxtime, -1, DBLOCK_UNLOCK(vd, MKXID(x, xid)),
00195 "beginning transaction", "");
00196 }
00197 else {
00198 NS ns;
00199
00200 CHECK_CONN(DBLOCK_UNLOCK(vd, MKXID(x, xid)));
00201
00202 dblock->wt_cnt++;
00203 ns = DBLOCK_COND_WAIT_R(vd, xid, (timeout < TIMEOUT ? timeout : TIMEOUT));
00204 dblock->wt_cnt--;
00205
00206 WAIT_CHECK(maxtime, ns, DBLOCK_UNLOCK(vd, MKXID(x, xid)),
00207 "beginning transaction", "");
00208 }
00209 }
00210 return Success;
00211 }
00212
00213 Status
00214 unlockS(DbDescription *vd, DbLock *dblock, unsigned int xid)
00215 {
00216 Status se;
00217 DBLOCK_LOCK(vd, xid);
00218
00219 if (dblock->S <= 0) {
00220 fprintf(stderr, "error dblockS == %d\n", dblock->S);
00221 DBLOCK_UNLOCK(vd, xid);
00222 return Success;
00223 }
00224
00225 dblock->S--;
00226 se = rmXid(dblock, DBLOCK_MTX(vd), xid);
00227
00228 if (dblock->wt_cnt) {
00229 TRACE(printf("cond_signal!!\n"));
00230 DBLOCK_COND_SIGNAL(vd);
00231 }
00232 DBLOCK_UNLOCK(vd, xid);
00233 TRACE(printf("\n------UNLOCK_S DONE------ thread = %d\n\n", thr_self()));
00234 return se;
00235 }
00236
00237 Status
00238 lockX(DbDescription *vd, DbLock *dblock, unsigned int xid,
00239 unsigned int timeout)
00240 {
00241 int x;
00242 unsigned int maxtime = timeout;
00243 TRACE(printf("\n------LOCK_X------ thread = %d, timeout = %d\n\n",
00244 thr_self(), timeout));
00245
00246 for (x = 0; ; x++) {
00247 if (!x)
00248 DBLOCK_LOCK(vd, xid);
00249
00250 if (!dblock->X && !dblock->S) {
00251 dblock->X = 1;
00252 dblock->xidX = xid;
00253 DBLOCK_UNLOCK(vd, MKXID(x, xid));
00254 TRACE(printf("\n------LOCK_X DONE------ thread = %d\n\n", thr_self()));
00255 TRACE(printf("LOCX done after %d times\n", x));
00256 break;
00257 }
00258 else if (!timeout) {
00259 WAIT_CHECK(maxtime, -1, DBLOCK_UNLOCK(vd, MKXID(x, xid)),
00260 "beginning transaction", "");
00261 }
00262 else {
00263 NS ns;
00264
00265 CHECK_CONN(DBLOCK_UNLOCK(vd, MKXID(x, xid)));
00266
00267 dblock->wt_cnt++;
00268 ns = DBLOCK_COND_WAIT_R(vd, xid, (timeout < TIMEOUT ? timeout : TIMEOUT));
00269 dblock->wt_cnt--;
00270 TRACE(printf("awaken!!!\n"));
00271 WAIT_CHECK(maxtime, ns, DBLOCK_UNLOCK(vd, MKXID(x, xid)),
00272 "beginning transaction", "");
00273 }
00274 }
00275 return Success;
00276 }
00277
00278 Status
00279 unlockX(DbDescription *vd, DbLock *dblock, unsigned int xid)
00280 {
00281 DBLOCK_LOCK(vd, xid);
00282
00283 ESM_ASSERT(dblock->X == 1, &dblock->mp, xid);
00284 dblock->X = 0;
00285
00286 ESM_ASSERT(dblock->xidX == xid, &dblock->mp, xid);
00287
00288 dblock->xidX = 0;
00289 if (dblock->wt_cnt) {
00290 TRACE(printf("cond_signal!!\n"));
00291 DBLOCK_COND_SIGNAL(vd);
00292 }
00293 DBLOCK_UNLOCK(vd, xid);
00294 TRACE(printf("\n------UNLOCK_X DONE------ thread = %d\n\n", thr_self()));
00295 return Success;
00296 }
00297
00298 Status
00299 checkLock(DbDescription *vd, DbLock *dblock)
00300 {
00301 assert(dblock);
00302 TRACE(printf("checkLOCK = 0x%x\n", *(unsigned long *)((char *)dblock + sizeof(DbLock))));
00303 return Success;
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 Status
00315 pobjLock(DbHandle const *dbh, XMHandle *xmh,
00316 const TransactionContext *trctx,
00317 Transaction *trs, XMOffset tro_off,
00318 LockMode lockMode, PObject *po,
00319 Mutex *mp, unsigned int xid, unsigned int timeout)
00320 {
00321 unsigned int maxtime = timeout;
00322 TRACE(printf("\n------POBJLOCK_S------ thread = %d\n\n", thr_self()));
00323
00324 for (;;) {
00325 if (lockMode == LockX) {
00326 if (!po->lockX && !po->lockS && !po->lockSX) {
00327 po->lockX = 1;
00328 break;
00329 }
00330 }
00331 else if (lockMode == LockS) {
00332 if (!po->lockX)
00333 {
00334 po->lockS++;
00335 break;
00336 }
00337 }
00338 else if (lockMode == LockSX) {
00339 if (!po->lockX && !po->lockSX)
00340 {
00341 po->lockSX = 1;
00342 break;
00343 }
00344 }
00345
00346 if (!timeout)
00347 WAIT_CHECK(maxtime, 1, 0, "locking object %s", getOidString(&po->oid));
00348 else {
00349 CondWait cond;
00350 Status se;
00351 NS ns;
00352
00353 CHECK_CONN(0);
00354
00355 se = deadLockCheck(xmh, trs, po, LockS);
00356
00357 if (se)
00358 return se;
00359
00360 if (po->cond)
00361 condMake(dbh->vd, xmh, po->cond, &cond);
00362 else
00363 po->cond = condNew(dbh->vd, xmh, &cond);
00364
00365 trs->trobj_wait = tro_off;
00366 trs->lock_wait = LockS;
00367
00368 se = ESM_transactionsGarbage(dbh, False);
00369
00370 if (se)
00371 return se;
00372
00373 po->wait_cnt++;
00374 ns = COND_WAIT_R(&cond, mp, xid, (timeout < TIMEOUT ? timeout : TIMEOUT));
00375 trs->trobj_wait = XM_NULLOFFSET;
00376 trs->lock_wait = (LockMode)0;
00377 po->wait_cnt--;
00378
00379 WAIT_CHECK(maxtime, ns, 0, "locking object %s", getOidString(&po->oid));
00380 }
00381 }
00382 return Success;
00383 }
00384
00385 Status
00386 pobjUnlock(DbDescription *vd, XMHandle *xmh, PObject *po,
00387 LockMode lockMode, Mutex *mp, unsigned int xid)
00388 {
00389 if (lockMode == LockX) {
00390 ESM_ASSERT(po->lockX == 1, mp, xid);
00391 po->lockX = 0;
00392 }
00393 else if (lockMode == LockSX) {
00394 ESM_ASSERT(po->lockSX == 1, mp, xid);
00395 po->lockSX = 0;
00396 }
00397 else if (lockMode == LockS) {
00398 ESM_ASSERT(po->lockS > 0, mp, xid);
00399 po->lockS--;
00400 }
00401
00402 if (po->wait_cnt) {
00403 CondWait cond;
00404 COND_SIGNAL(condMake(vd, xmh, po->cond, &cond));
00405 }
00406
00407 return Success;
00408 }
00409 }