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
00027
00028
00029 #define CRASH(X) if (getenv(#X)) {printf(#X ## "\n"); exit(1);}
00030
00031 #ifdef TRS_DBG
00032 #define TT(X) X
00033 #else
00034 #define TT(X)
00035 #endif
00036
00037
00038
00039 static const char trTooLarge[] =
00040 "no shmspace left in transaction file: transaction too large";
00041
00042 #ifdef NEW_TR_CNT
00043 #define TR_CNT(DBH) ((DBH)->vd->shm_addr->trs_hdr.tr_cnt)
00044 #else
00045 #define TR_CNT(DBH) ((DBH)->vd->tr_cnt)
00046 #endif
00047
00048 #include <stdlib.h>
00049 #include <stdarg.h>
00050 #include <eyedblib/machtypes.h>
00051 #include <eyedblib/rpc_lib.h>
00052 #include <eyedbsm_p.h>
00053 #include <transaction.h>
00054 #include <hashtable.h>
00055 #include <lock.h>
00056 #include <sys/types.h>
00057 #include <sys/stat.h>
00058 #include <fcntl.h>
00059 #include <string.h>
00060 #include <unistd.h>
00061 #include <errno.h>
00062 #include <sys/mman.h>
00063 #include <pthread.h>
00064
00065 #include <eyedblib/iassert.h>
00066 #include <eyedblib/log.h>
00067 #include <eyedblib/butils.h>
00068
00069 #define _ESM_C_
00070 #include <eyedblib/rpc_be.h>
00071 #include <kern.h>
00072 #include <kern_p.h>
00073 #include <eyedblib/semlib.h>
00074
00075
00076
00077 #ifdef TRS_INTER_MUT
00078 #define MUTEX_LOCKER eyedbsm::MutexLocker
00079 #else
00080 #define MUTEX_LOCKER eyedblib::MutexLocker
00081 #endif
00082
00083
00084 #define LAZY_LOCK_X
00085
00086 namespace eyedbsm {
00087
00088 Boolean trace_garb_trs = False;
00089
00090 static TransactionParams defparams = DEFAULT_TRANSACTION_PARAMS;
00091
00092 static void
00093 ESM_transactionRegister(Transaction *trs, Mutex *mp, unsigned int xid);
00094 static void
00095
00096 ESM_transactionUnregister(Transaction *trs, Mutex *mp, unsigned int xid);
00097
00098 static TransactionOP crossOps[OP_CNT][OP_CNT] = {
00099
00100
00101 OCREATE, OCREATE, OCREATE, OCREADEL, OERROR, OCREATE, OERROR,
00102
00103 OERROR, OREAD, OWRITE, ODELETE, OERROR, OCHSIZE, OERROR,
00104
00105 OERROR, OWRITE, OWRITE, ODELETE, OERROR, OCHSIZE, OERROR,
00106
00107 OERROR, OERROR, OERROR, OERROR, OERROR, OERROR, OERROR,
00108 OERROR, OERROR, OERROR, OERROR, OERROR, OERROR, OERROR,
00109
00110
00111
00112 OERROR, OCHSIZE, OWRITE, ODELETE, OCHSIZE, OERROR,
00113
00114 OERROR, OERROR, OERROR, OERROR, OERROR, OERROR
00115 };
00116
00117 static int opSync[OP_CNT] = {
00118 1,
00119 1,
00120 0,
00121 0,
00122 0,
00123 0
00124 };
00125
00126 static Boolean trs_initialized = False;
00127 static LockMode opLockMode[OP_CNT][LockModeIndex_CNT];
00128 static OP lock2op[LockE+1];
00129
00130 #define DEF_MAGORDER 10240
00131 #define MAX_MAGORDER 2000000
00132
00133 int trs_init(void)
00134 {
00135 if (trs_initialized)
00136 return 0;
00137
00138 lock2op[LockN] = LockNOP;
00139 lock2op[LockS] = LockSOP;
00140 lock2op[LockX] = LockXOP;
00141 lock2op[LockSX] = LockSXOP;
00142 lock2op[LockP] = LockPOP;
00143
00144 opLockMode[OCREATE] [R_S_W_S] = LockP;
00145 opLockMode[OREAD] [R_S_W_S] = LockS;
00146 opLockMode[OWRITE] [R_S_W_S] = LockS;
00147 opLockMode[ODELETE] [R_S_W_S] = LockS;
00148 opLockMode[OCHSIZE] [R_S_W_S] = LockS;
00149 opLockMode[OERROR] [R_S_W_S] = LockE;
00150
00151 opLockMode[OCREATE] [R_S_W_SX] = LockP;
00152 opLockMode[OREAD] [R_S_W_SX] = LockS;
00153 opLockMode[OWRITE] [R_S_W_SX] = LockSX;
00154 opLockMode[ODELETE] [R_S_W_SX] = LockSX;
00155 opLockMode[OCHSIZE] [R_S_W_SX] = LockSX;
00156 opLockMode[OERROR] [R_S_W_SX] = LockE;
00157
00158 opLockMode[OCREATE] [R_S_W_X] = LockP;
00159 opLockMode[OREAD] [R_S_W_X] = LockS;
00160 opLockMode[OWRITE] [R_S_W_X] = LockX;
00161 opLockMode[ODELETE] [R_S_W_X] = LockX;
00162 opLockMode[OCHSIZE] [R_S_W_X] = LockX;
00163 opLockMode[OERROR] [R_S_W_X] = LockE;
00164
00165 opLockMode[OCREATE] [R_SX_W_SX] = LockP;
00166 opLockMode[OREAD] [R_SX_W_SX] = LockSX;
00167 opLockMode[OWRITE] [R_SX_W_SX] = LockSX;
00168 opLockMode[ODELETE] [R_SX_W_SX] = LockSX;
00169 opLockMode[OCHSIZE] [R_SX_W_SX] = LockSX;
00170 opLockMode[OERROR] [R_SX_W_SX] = LockE;
00171
00172 opLockMode[OCREATE] [R_SX_W_X] = LockP;
00173 opLockMode[OREAD] [R_SX_W_X] = LockSX;
00174 opLockMode[OWRITE] [R_SX_W_X] = LockX;
00175 opLockMode[ODELETE] [R_SX_W_X] = LockX;
00176 opLockMode[OCHSIZE] [R_SX_W_X] = LockX;
00177 opLockMode[OERROR] [R_SX_W_X] = LockE;
00178
00179 opLockMode[OCREATE] [R_X_W_X] = LockP;
00180 opLockMode[OREAD] [R_X_W_X] = LockX;
00181 opLockMode[OWRITE] [R_X_W_X] = LockX;
00182 opLockMode[ODELETE] [R_X_W_X] = LockX;
00183 opLockMode[OCHSIZE] [R_X_W_X] = LockX;
00184 opLockMode[OERROR] [R_X_W_X] = LockE;
00185
00186 opLockMode[OCREATE] [R_N_W_S] = LockP;
00187 opLockMode[OREAD] [R_N_W_S] = LockN;
00188 opLockMode[OWRITE] [R_N_W_S] = LockS;
00189 opLockMode[ODELETE] [R_N_W_S] = LockS;
00190 opLockMode[OCHSIZE] [R_N_W_S] = LockS;
00191 opLockMode[OERROR] [R_N_W_S] = LockE;
00192
00193 opLockMode[OCREATE] [R_N_W_SX] = LockP;
00194 opLockMode[OREAD] [R_N_W_SX] = LockN;
00195 opLockMode[OWRITE] [R_N_W_SX] = LockSX;
00196 opLockMode[ODELETE] [R_N_W_SX] = LockSX;
00197 opLockMode[OCHSIZE] [R_N_W_SX] = LockSX;
00198 opLockMode[OERROR] [R_N_W_SX] = LockE;
00199
00200 opLockMode[OCREATE] [R_N_W_X] = LockP;
00201 opLockMode[OREAD] [R_N_W_X] = LockN;
00202 opLockMode[OWRITE] [R_N_W_X] = LockX;
00203 opLockMode[ODELETE] [R_N_W_X] = LockX;
00204 opLockMode[OCHSIZE] [R_N_W_X] = LockX;
00205 opLockMode[OERROR] [R_N_W_X] = LockE;
00206
00207 opLockMode[OCREATE] [R_N_W_N] = LockP;
00208 opLockMode[OREAD] [R_N_W_N] = LockN;
00209 opLockMode[OWRITE] [R_N_W_N] = LockN;
00210 opLockMode[ODELETE] [R_N_W_N] = LockN;
00211 opLockMode[OCHSIZE] [R_N_W_N] = LockN;
00212 opLockMode[OERROR] [R_N_W_N] = LockE;
00213
00214 trs_initialized = True;
00215
00216 return 0;
00217 }
00218
00219 static bool must_lock_db(DbHandle const *dbh)
00220 {
00221 #ifdef LAZY_LOCK_X
00222 return dbh->vd->flags == VOLRW;
00223 #else
00224 return true;
00225 #endif
00226 }
00227
00228 static int
00229 magorderHtCount(int magorder)
00230 {
00231 int n = magorder/20;
00232 int p = 1;
00233
00234 for (;;) {
00235 if (p >= n)
00236 break;
00237 p <<= 1;
00238 }
00239
00240 return p;
00241 }
00242
00243 static Boolean
00244 ESM_transactionParamsCompare(const TransactionParams *params1,
00245 const TransactionParams *params2,
00246 Boolean compare_all)
00247 {
00248 int r;
00249 if (params1 == 0 && params2 != 0)
00250 return False;
00251
00252 if (params1 != 0 && params2 == 0)
00253 return False;
00254
00255 if (params1 == 0 && params2 == 0)
00256 return True;
00257
00258 r = (params1->trsmode == params2->trsmode &&
00259 params1->recovmode == params2->recovmode &&
00260 params1->magorder == params2->magorder);
00261
00262 if (!compare_all || !r)
00263 return r ? True : False;
00264
00265 return (r &&
00266 params1->lockmode == params2->lockmode &&
00267 params1->ratioalrt == params2->ratioalrt &&
00268 params1->wait_timeout == params2->wait_timeout) ? True : False;
00269 }
00270
00271 static Status
00272 ESM_transactionLockModeIdx_realize(DbHandle const *dbh,
00273 TransactionContext *trctx,
00274 ObjectLockMode lockmode)
00275 {
00276 if (lockmode == ReadSWriteS)
00277 trctx->lockmodeIndex = R_S_W_S;
00278 else if (lockmode == ReadSWriteSX)
00279 trctx->lockmodeIndex = R_S_W_SX;
00280 else if (lockmode == ReadSWriteX)
00281 trctx->lockmodeIndex = R_S_W_X;
00282
00283 else if (lockmode == ReadSXWriteSX)
00284 trctx->lockmodeIndex = R_SX_W_SX;
00285 else if (lockmode == ReadSXWriteX)
00286 trctx->lockmodeIndex = R_SX_W_X;
00287
00288 else if (lockmode == ReadXWriteX)
00289 trctx->lockmodeIndex = R_X_W_X;
00290
00291 else if (lockmode == ReadNWriteS)
00292 trctx->lockmodeIndex = R_N_W_S;
00293 else if (lockmode == ReadNWriteSX)
00294 trctx->lockmodeIndex = R_N_W_SX;
00295 else if (lockmode == ReadNWriteX)
00296 trctx->lockmodeIndex = R_N_W_X;
00297 else if (lockmode == ReadNWriteN)
00298 trctx->lockmodeIndex = R_N_W_N;
00299
00300 else if (lockmode == DatabaseW)
00301 trctx->lockmodeIndex = DB_W;
00302 else if (lockmode == DatabaseRW)
00303 trctx->lockmodeIndex = DB_RW;
00304 else if (lockmode == DatabaseWtrans)
00305 trctx->lockmodeIndex = DB_Wtrans;
00306
00307 else
00308 return statusMake(INVALID_TRANSACTION_MODE,
00309 "transaction lock mode %d", lockmode);
00310
00311 return Success;
00312 }
00313
00314 static Status
00315 ESM_transactionParamsSet_realize(DbHandle const *dbh,
00316 TransactionContext *trctx,
00317 const TransactionParams *params,
00318 const TransactionParams *oparams)
00319
00320 {
00321 Status se;
00322
00323
00324 if (params->trsmode != TransactionOff &&
00325 params->trsmode != TransactionOn)
00326 return statusMake(INVALID_TRANSACTION_MODE,
00327 "transaction mode %d", params->trsmode);
00328
00329
00330 if (params->recovmode != RecoveryOff &&
00331 params->recovmode != RecoveryPartial &&
00332 params->recovmode != RecoveryFull)
00333 return statusMake(INVALID_TRANSACTION_MODE,
00334 "transaction recovery mode %d", params->recovmode);
00335
00336
00337 se = ESM_transactionLockModeIdx_realize(dbh, trctx, params->lockmode);
00338 if (se) return se;
00339
00340
00341 if ((params->recovmode == RecoveryPartial ||
00342 params->recovmode == RecoveryFull) &&
00343 params->trsmode == TransactionOff)
00344 return statusMake(INVALID_TRANSACTION_MODE,
00345 "cannot have recovery on with transaction off mode");
00346
00347
00348
00349 if (oparams &&
00350 !ESM_transactionParamsCompare(params, oparams, False))
00351 return statusMake(INVALID_TRANSACTION_MODE,
00352 "only lockmode, timeout and ratioalrt can be changed"
00353 "dynamically");
00354
00355 if (params->lockmode == DatabaseW && oparams &&
00356 oparams->lockmode != params->lockmode)
00357 return statusMake(INVALID_TRANSACTION_MODE,
00358 "cannot change dynamically to database W lockmode");
00359
00360 if (params->lockmode == DatabaseRW && oparams &&
00361 oparams->lockmode != params->lockmode)
00362 return statusMake(INVALID_TRANSACTION_MODE,
00363 "cannot change dynamically to database RW lockmode");
00364
00365 if (params->lockmode == DatabaseWtrans && oparams &&
00366 oparams->lockmode != params->lockmode)
00367 return statusMake(INVALID_TRANSACTION_MODE,
00368 "cannot change dynamically to database Wtrans lockmode");
00369
00370 trctx->params = *params;
00371
00372 if (params->magorder < DEF_MAGORDER)
00373 trctx->params.magorder = DEF_MAGORDER;
00374 else if (params->magorder > MAX_MAGORDER)
00375 trctx->params.magorder = MAX_MAGORDER;
00376 else
00377 trctx->params.magorder = params->magorder;
00378
00379 if (params->trsmode == TransactionOff &&
00380 (params->lockmode == ReadNWriteN ||
00381 params->lockmode == DatabaseW ||
00382 params->lockmode == DatabaseRW))
00383 trctx->skip = True;
00384 else
00385 trctx->skip = False;
00386
00387 return Success;
00388 }
00389
00390 Status
00391 ESM_transactionParamsSet(DbHandle const *dbh,
00392 const TransactionParams *params)
00393 {
00394 TransactionContext *trctx;
00395
00396 if (!TR_CNT(dbh))
00397 return statusMake(TRANSACTION_NEEDED, "transaction needed in transactionParamsSet");
00398
00399 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00400
00401 if (ESM_transactionParamsCompare(params, &trctx->params, True))
00402 return Success;
00403
00404 if (!params)
00405 params = &defparams;
00406
00407 return ESM_transactionParamsSet_realize(dbh, trctx, params, &trctx->params);
00408 }
00409
00410 Status
00411 ESM_transactionParamsGet(DbHandle const *dbh,
00412 TransactionParams *params)
00413 {
00414 TransactionContext *trctx;
00415
00416 if (!TR_CNT(dbh))
00417 return statusMake(TRANSACTION_NEEDED, "transaction needed in transactionParamsGet");
00418
00419 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00420
00421 *params = trctx->params;
00422
00423 return Success;
00424 }
00425
00426 Boolean
00427 ESM_isExclusive(DbHandle const *dbh)
00428 {
00429 if (!TR_CNT(dbh))
00430 return False;
00431
00432 return dbh->vd->trctx[TR_CNT(dbh)-1].params.lockmode == DatabaseW ||
00433 dbh->vd->trctx[TR_CNT(dbh)-1].params.lockmode == DatabaseRW ?
00434 True : False;
00435 }
00436
00437 Status
00438 ESM_transactionBegin(DbHandle const *dbh,
00439 const TransactionParams *params)
00440 {
00441 if (dbh->vd->flags & NO_SHM_ACCESS) {
00442 return Success;
00443 }
00444
00445 TransactionContext *trctx;
00446 unsigned int xid = dbh->vd->xid;
00447 DbLock *dblock_W = &dbh->vd->shm_addr->dblock_W;
00448 Status se;
00449
00450 if (TR_CNT(dbh) >= MAXTRS)
00451 return statusMake(TOO_MANY_TRANSACTIONS, "maximum transaction excedeed [max=%d]", MAXTRS);
00452
00453 if (!params)
00454 params = &defparams;
00455
00456 IDB_LOG(IDB_LOG_TRANSACTION, ("transaction xid=%d begin "
00457 "trsmode=%p, lockmode=%d, recovmode=%d, "
00458 "magorder=%u , ratioalrt=%u, timeout=%u",
00459 xid,
00460 params->trsmode,
00461 params->lockmode,
00462 params->recovmode,
00463 params->magorder,
00464 params->ratioalrt,
00465 params->wait_timeout));
00466
00467 trctx = &dbh->vd->trctx[TR_CNT(dbh)++];
00468
00469 if (se = ESM_transactionParamsSet_realize(dbh, trctx, params, 0)) {
00470 TR_CNT(dbh)--;
00471 return se;
00472 }
00473
00474 IDB_LOG(IDB_LOG_TRANSACTION, ("lockmode index=%p\n", trctx->lockmodeIndex));
00475
00476 if (params->lockmode == DatabaseW) {
00477 se = lockX(dbh->vd, dblock_W, xid, trctx->params.wait_timeout);
00478 if (se) {
00479 TR_CNT(dbh)--;
00480 return se;
00481 }
00482 }
00483 else if (must_lock_db(dbh)) {
00484 se = lockS(dbh->vd, dblock_W, xid, trctx->params.wait_timeout);
00485 if (se) {
00486 TR_CNT(dbh)--;
00487 return se;
00488 }
00489 }
00490
00491 if (trctx->skip)
00492 trctx->trs_off = 0;
00493 else {
00494 se = ESM_transactionCreate(dbh, &trctx->params, &trctx->trs_off);
00495 if (se)
00496 return se;
00497
00498 if (!trctx->trs_off) {
00499 TR_CNT(dbh)--;
00500 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
00501 }
00502 }
00503
00504 dbh->vd->shm_addr->stat.tr_begin_cnt = h2x_u32(x2h_u32(dbh->vd->shm_addr->stat.tr_begin_cnt)+1);
00505
00506 return Success;
00507 }
00508
00509 static void
00510 ESM_transactionProtectionsAdvise(DbHandle const *dbh)
00511 {
00512 TransHeader *trshd;
00513 Transaction *trs;
00514 DbShmHeader *shmh = dbh->vd->shm_addr;
00515
00516 Mutex *mp = TRS_MTX(dbh);
00517 XMHandle *xmh = dbh->vd->trs_mh;
00518 Status se;
00519
00520 trshd = &shmh->trs_hdr;
00521
00522 se = MUTEX_LOCK_VOID(mp, 0);
00523 if (se) {
00524 IDB_LOG(IDB_LOG_TRANSACTION, (statusGet(se)));
00525 return;
00526 }
00527
00528 trs = (Transaction *)XM_ADDR(xmh, trshd->first_trs);
00529
00530 while (trs) {
00531 trs->prot_update = True;
00532 trs = (Transaction *)XM_ADDR(xmh, trs->next);
00533 }
00534
00535 MUTEX_UNLOCK(mp, 0);
00536 }
00537
00538 Boolean
00539 ESM_protectionsMustUpdate(DbHandle const *dbh)
00540 {
00541 TransactionContext *trctx;
00542 Transaction *trs;
00543 Boolean prot_update;
00544
00545 if (TR_CNT(dbh) == 0)
00546 return False;
00547
00548 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00549 trs = (Transaction *)XM_ADDR(dbh->vd->trs_mh, trctx->trs_off);
00550 #ifndef NO_INTERNAL_LOCK
00551 MUTEX_LOCKER mtlock(trs->mut);
00552 #endif
00553
00554 prot_update = trs->prot_update;
00555 trs->prot_update = False;
00556 return prot_update;
00557 }
00558
00559 Status
00560 ESM_transactionLockSet(DbHandle const *dbh, ObjectLockMode lockmode,
00561 ObjectLockMode *olockmode)
00562 {
00563 TransactionContext *trctx;
00564
00565 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00566
00567 if (olockmode)
00568 *olockmode = trctx->params.lockmode;
00569 trctx->params.lockmode = lockmode;
00570
00571 return ESM_transactionLockModeIdx_realize(dbh, trctx, lockmode);
00572 }
00573
00574 static void
00575 ESM_PObjectChangeTransOwnerLock(XMHandle *xmh, PObject *po,
00576 XMOffset trs_off, LockMode lock,
00577 Mutex *mp, unsigned int xid);
00578
00579 #define ESM_REGISTER_LOCK(dbh, lock) \
00580 do { \
00581 if ((dbh)->vd->reg && (dbh)->vd->reg_mask) { \
00582 OP op = lock2op[lock]; \
00583 ESM_REGISTER(dbh, op, ESM_addToRegisterLock(dbh, oid, op)); \
00584 } \
00585 } while(0)
00586
00587 Status
00588 ESM_objectDownLock(DbHandle const *dbh, Oid const *const oid)
00589 {
00590 TransactionContext *trctx;
00591 XMHandle *xmh;
00592 Transaction *trs;
00593 HashTable *trs_ht;
00594 HashTable *obj_ht;
00595 XMOffset tro_off;
00596 XMOffset po_off;
00597 TRObject *tro;
00598 PObject *po;
00599 Mutex *mp = TRS_MTX(dbh);
00600 unsigned int xid = dbh->vd->xid;
00601 Status se = Success;
00602
00603
00604
00605 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00606
00607 if (trctx->skip || !NEED_OBJLOCK(trctx))
00608 return Success;
00609
00610 xmh = dbh->vd->trs_mh;
00611
00612 trs = (Transaction *)XM_ADDR(xmh, trctx->trs_off);
00613
00614 ESM_ASSERT(trs->magic == TRS_MAGIC, 0, xid);
00615
00616 obj_ht = (HashTable *)XM_ADDR(xmh, dbh->vd->shm_addr->trs_hdr.obj_ht);
00617 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off);
00618
00619 #ifndef NO_INTERNAL_LOCK
00620 MUTEX_LOCKER mtlock(trs->mut);
00621 #endif
00622 tro_off = HashTableTRObjectLookup(xmh, trs_ht, oid);
00623
00624 tro = (TRObject *)XM_ADDR(xmh, tro_off);
00625 MUTEX_LOCKER trolock(tro->mut);
00626
00627 #ifndef NO_INTERNAL_LOCK
00628 mtlock.unlock();
00629 #endif
00630
00631 if (!tro->lockSX && !tro->lockX && !tro->lockP)
00632 return statusMake(ERROR, "object '%s' is neither lock X, nor lock SX, nor lock P",
00633 getOidString(oid));
00634
00635 #ifdef TRS_SECURE
00636 ESM_ASSERT(tro->magic == TROBJ_MAGIC, 0, 0);
00637 #endif
00638
00639 po = (PObject *)XM_ADDR(xmh, tro->po_off);
00640
00641 #ifdef TRS_SECURE
00642 ESM_ASSERT(po->magic == POBJ_MAGIC, 0, 0);
00643 #endif
00644
00645
00646
00647 MUTEX_LOCK(mp, xid);
00648
00649 se = pobjUnlock(dbh->vd, xmh, po, LockX, mp, xid);
00650
00651 tro->lockX = 0;
00652
00653 if (!se) {
00654 se = pobjLock(dbh, xmh, trctx, trs, tro_off, LockS, po, mp, xid,
00655 trctx->params.wait_timeout);
00656 if (!se) {
00657 tro->lockS++;
00658 ESM_PObjectChangeTransOwnerLock(xmh, po, trctx->trs_off,
00659 LockS, mp, xid);
00660 ESM_REGISTER_LOCK(dbh, LockS);
00661 }
00662 }
00663
00664 MUTEX_UNLOCK(mp, xid);
00665
00666 return se;
00667 }
00668
00669 Status
00670 ESM_transactionRealize(DbHandle const *dbh, TransState state)
00671 {
00672 if (dbh->vd->flags & NO_SHM_ACCESS) {
00673 return Success;
00674 }
00675
00676 TransactionContext *trctx;
00677 DbLock *dblock_W = &dbh->vd->shm_addr->dblock_W;
00678 unsigned int xid = dbh->vd->xid;
00679
00680 if (!TR_CNT(dbh))
00681 return statusMake(TRANSACTION_NEEDED,
00682 "transaction needed in %s",
00683 (state == TransCOMMITING ? "transactionBegin" :
00684 "transactionAbort"));
00685
00686 trctx = &dbh->vd->trctx[--TR_CNT(dbh)];
00687
00688 Status se = Success;
00689
00690
00691
00692
00693
00694
00695 #define NEW_DBLOCK
00696
00697 #ifdef NEW_DBLOCK
00698 if (!trctx->skip)
00699 se = ESM_transactionDelete(dbh, trctx->trs_off, state);
00700 #endif
00701
00702 if (findDbLockXID(dbh->vd, dblock_W, xid, 0, False)) {
00703 if (trctx->params.lockmode == DatabaseW)
00704 unlockX(dbh->vd, dblock_W, xid);
00705 else if (must_lock_db(dbh))
00706 unlockS(dbh->vd, dblock_W, xid);
00707 }
00708
00709 #ifndef NEW_DBLOCK
00710 if (!trctx->skip)
00711 se = ESM_transactionDelete(dbh, trctx->trs_off, state);
00712 #endif
00713
00714 trctx->trs_off = 0;
00715
00716 if (state == TransABORTING)
00717 ESM_protectionsRunTimeUpdate(dbh);
00718 else
00719 ESM_transactionProtectionsAdvise(dbh);
00720
00721 return se;
00722 }
00723
00724 Status
00725 ESM_transactionCommit(DbHandle const *dbh)
00726 {
00727 return ESM_transactionRealize(dbh, TransCOMMITING);
00728 }
00729
00730 Status
00731 ESM_transactionAbort(DbHandle const *dbh)
00732 {
00733 return ESM_transactionRealize(dbh, TransABORTING);
00734 }
00735
00736 static TRObject *
00737 makeTRObject(DbHandle const *dbh, const Oid *oid,
00738 TransactionOP op, LockMode lock, HashTable *trs_ht,
00739 TransactionContext *trctx, XMOffset *tro_off,
00740 Mutex *mp, unsigned int xid)
00741 {
00742 TRObject *tro;
00743 XMHandle *xmh = dbh->vd->trs_mh;
00744
00745 tro = (TRObject *)XMAlloc(xmh, sizeof(TRObject));
00746
00747 if (!tro)
00748 return 0;
00749
00750 tro->op = op;
00751
00752 #ifdef TRS_SECURE
00753 tro->magic = TROBJ_MAGIC;
00754 #endif
00755 tro->lockX = 0;
00756 tro->lockS = 0;
00757 tro->lockSX = 0;
00758 tro->lockP = 0;
00759 tro->data = XM_NULLOFFSET;
00760 tro->prot_oid_set = False;
00761 memset(&tro->prot_oid, 0, sizeof(tro->prot_oid));
00762
00763 tro->oid = *oid;
00764 tro->oidloc.ns = 0;
00765 tro->oidloc.datid = -1;
00766 tro->po_off = 0;
00767 tro->state = Active;
00768 #ifdef TRS_INTER_MUT
00769 mutexInit(dbh->vd, &tro->mut, &tro->mp, "TRANSACTION");
00770 #else
00771
00772 tro->mut.init(eyedblib::Mutex::PROCESS_PRIVATE);
00773 #endif
00774
00775 HashTableTRObjectInsert(xmh, trs_ht, tro);
00776 *tro_off = XM_OFFSET(xmh, tro);
00777 return tro;
00778 }
00779
00780 static PObject *
00781 makePObject(XMHandle *xmh, const Oid *oid, HashTable *obj_ht,
00782 XMOffset trs_off, XMOffset *po_off,
00783 LockMode lock)
00784 {
00785 PObject *po;
00786
00787 po = (PObject *)XMAlloc(xmh, sizeof(PObject));
00788
00789 if (!po)
00790 return 0;
00791
00792 #ifdef TRS_SECURE
00793 po->magic = POBJ_MAGIC;
00794 #endif
00795 po->oid = *oid;
00796 po->lockS = 0;
00797 po->lockX = 0;
00798 po->lockSX = 0;
00799 po->lockPxid = 0;
00800 po->tridx = ~0;
00801 po->wait_cnt = 0;
00802 po->refcnt = 1;
00803 po->state = Active;
00804 po->cond = XM_NULLOFFSET;
00805
00806 po->trs_cnt = 0;
00807 po->trs_own.trs_off = 0;
00808 po->trs_own.trs_lock = DefaultLock;
00809 po->trs_own.next = XM_NULLOFFSET;
00810 po->trs_own.prev = XM_NULLOFFSET;
00811
00812 HashTablePObjectInsert(xmh, obj_ht, po);
00813
00814 *po_off = XM_OFFSET(xmh, po);
00815
00816 return po;
00817 }
00818
00819 static void
00820 print_item_trs(TransOwner *trs_own)
00821 {
00822 printf("\t%d [lock =%d]\n", trs_own->trs_off, trs_own->trs_lock);
00823 }
00824
00825 static void
00826 print_trs(const char *msg, XMHandle *xmh, PObject *po)
00827 {
00828 TransOwner *trs_own;
00829 printf("%s {\n", msg);
00830 print_item_trs(&po->trs_own);
00831
00832 trs_own = (TransOwner *)XM_ADDR(xmh, po->trs_own.next);
00833
00834 while (trs_own) {
00835 print_item_trs(trs_own);
00836 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
00837 }
00838
00839 printf("}\n");
00840 }
00841
00842 static void
00843 ESM_PObjectSuppressTransOwner(XMHandle *, PObject *, XMOffset,
00844 Mutex *, unsigned int);
00845
00846 static void
00847 ESM_PObjectChangeTransOwnerLock(XMHandle *xmh, PObject *po,
00848 XMOffset trs_off, LockMode lock,
00849 Mutex *mp, unsigned int xid)
00850 {
00851 TransOwner *trs_own;
00852
00853 if (po->trs_own.trs_off == trs_off) {
00854 if (po->trs_own.trs_lock == lock)
00855 IDB_LOG(IDB_LOG_TRANSACTION, ("ESM_PObjectChangeTransOwnerLock: %d vs. %d\n",
00856 po->trs_own.trs_lock, lock));
00857 ESM_ASSERT_ABORT(po->trs_own.trs_lock != lock, mp, xid);
00858 po->trs_own.trs_lock = lock;
00859 return;
00860 }
00861
00862 trs_own = (TransOwner *)XM_ADDR(xmh, po->trs_own.next);
00863
00864 while (trs_own) {
00865 if (trs_own->trs_off == trs_off) {
00866 ESM_ASSERT_ABORT(trs_own->trs_lock != lock, mp, xid);
00867 trs_own->trs_lock = lock;
00868 return;
00869 }
00870 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
00871 }
00872
00873 ESM_ASSERT_ABORT(0, mp, xid);
00874 }
00875
00876 static int
00877 addTransOwner(XMHandle *xmh, PObject *po, XMOffset trs_off,
00878 LockMode lock)
00879 {
00880 TransOwner *trs_own;
00881 XMOffset trs_own_off;
00882
00883 TT(printf(" addTransOwner(trs_off = %d, oid = %d.%d)\n",
00884 trs_off, po->oid.nx, po->oid.unique));
00885
00886 po->trs_cnt++;
00887
00888 if (!po->trs_own.trs_off) {
00889 po->trs_own.trs_off = trs_off;
00890 po->trs_own.trs_lock = lock;
00891
00892 ESM_ASSERT_ABORT(!po->trs_own.next, 0, 0);
00893 ESM_ASSERT_ABORT(!po->trs_own.prev, 0, 0);
00894
00895 return 1;
00896 }
00897
00898 trs_own = (TransOwner *)XMAlloc(xmh, sizeof(TransOwner));
00899
00900 if (!trs_own)
00901 return 0;
00902
00903 trs_own->trs_off = trs_off;
00904 trs_own->trs_lock = lock;
00905 trs_own_off = XM_OFFSET(xmh, trs_own);
00906
00907 trs_own->next = po->trs_own.next;
00908 if (po->trs_own.next)
00909 ((TransOwner *)XM_ADDR(xmh, po->trs_own.next))->prev = trs_own_off;
00910 trs_own->prev = XM_NULLOFFSET;
00911 po->trs_own.next = trs_own_off;
00912
00913 return 1;
00914 }
00915
00916 const Oid *
00917 ESM_getProtection(DbHandle const *dbh, const Oid *oid,
00918 const Oid *prot_oid)
00919 {
00920 TransactionContext *trctx;
00921 XMHandle *xmh;
00922 Transaction *trs;
00923 HashTable *trs_ht;
00924 XMOffset tro_off;
00925 TRObject *tro;
00926
00927 if (!TR_CNT(dbh))
00928 return prot_oid;
00929
00930 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
00931
00932 if (trctx->skip)
00933 return prot_oid;
00934
00935 xmh = dbh->vd->trs_mh;
00936
00937 trs = (Transaction *)XM_ADDR(xmh, trctx->trs_off);
00938
00939 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off);
00940
00941 #ifndef NO_INTERNAL_LOCK
00942 MUTEX_LOCKER mtlock(trs->mut);
00943 #endif
00944 tro_off = HashTableTRObjectLookup(xmh, trs_ht, oid);
00945
00946 if (!tro_off)
00947 return prot_oid;
00948
00949 tro = (TRObject *)XM_ADDR(xmh, tro_off);
00950
00951 if (tro->prot_oid_set) {
00952 printf("OUPS SPECIAL PROT_OID!!!!\n");
00953 return &tro->prot_oid;
00954 }
00955
00956 return prot_oid;
00957 }
00958
00959
00960
00961 Status
00962 ESM_objectGetLock(DbHandle const *dbh, const Oid *oid, LockMode *rlock)
00963 {
00964 XMHandle *xmh;
00965 int tridx;
00966 HashTable *trs_ht;
00967 XMOffset tro_off;
00968 TRObject *tro;
00969 TransactionContext *trctx;
00970 Transaction *trs;
00971
00972 tridx = TR_CNT(dbh)-1;
00973 trctx = &dbh->vd->trctx[tridx];
00974
00975 xmh = dbh->vd->trs_mh;
00976 trs = (Transaction *)XM_ADDR(xmh, trctx->trs_off);
00977
00978 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off);
00979
00980 #ifndef NO_INTERNAL_LOCK
00981 MUTEX_LOCKER mtlock(trs->mut);
00982 #endif
00983 tro_off = HashTableTRObjectLookup(xmh, trs_ht, oid);
00984 tro = (TRObject *)XM_ADDR(xmh, tro_off);
00985
00986 if (tro) {
00987 if (tro->lockX)
00988 *rlock = LockX;
00989 else if (tro->lockSX)
00990 *rlock = LockSX;
00991 else if (tro->lockP)
00992 *rlock = LockP;
00993 else if (tro->lockS)
00994 *rlock = LockS;
00995 else
00996 *rlock = LockN;
00997 }
00998 else
00999 *rlock = LockN;
01000
01001 return Success;
01002 }
01003
01004 static eyedblib::int64 current_time()
01005 {
01006 struct timeval tv;
01007
01008 gettimeofday(&tv, 0);
01009
01010 return (eyedblib::int64)tv.tv_sec * 1000000 + tv.tv_usec;
01011 }
01012
01013 Status
01014 ESM_objectLock(DbHandle const *dbh, const Oid *oid, TransactionOP op,
01015 Boolean *popsync, TRObject **ptro)
01016 {
01017 return ESM_objectLockCheck(dbh, oid, op, popsync, 0, ptro);
01018 }
01019
01020 Status
01021 ESM_objectLockCheck(DbHandle const *dbh, const Oid *oid,
01022 TransactionOP op, Boolean *popsync,
01023 Boolean *exists, TRObject **ptro)
01024 {
01025 TransactionContext *trctx;
01026 XMHandle *xmh;
01027 Transaction *trs;
01028 HashTable *trs_ht;
01029 HashTable *obj_ht;
01030 XMOffset tro_off;
01031 XMOffset po_off;
01032 TRObject *tro;
01033 PObject *po;
01034 LockMode lock;
01035 Mutex *mp = TRS_MTX(dbh);
01036 unsigned int xid = dbh->vd->xid;
01037 Status se = Success;
01038 int tridx;
01039 LockMode wlock = DefaultLock;
01040
01041 if (!TR_CNT(dbh)) {
01042 if (popsync)
01043 *popsync = True;
01044 if (exists)
01045 *exists = False;
01046 return Success;
01047 }
01048
01049 tridx = TR_CNT(dbh)-1;
01050 trctx = &dbh->vd->trctx[tridx];
01051
01052 if (trctx->skip) {
01053 if (popsync)
01054 *popsync = True;
01055 if (exists)
01056 *exists = False;
01057 return Success;
01058 }
01059
01060 if (op == PWRITE)
01061 op = OWRITE;
01062 else if (op == PREAD)
01063 op = OREAD;
01064
01065 if (op & LOCKX) {
01066
01067 op = (TransactionOP)(op & ~LOCKX);
01068 wlock = LockX;
01069 }
01070 else if (op & LOCKSX) {
01071
01072 op = (TransactionOP)(op & ~LOCKSX);
01073 wlock = LockSX;
01074 }
01075 else if (op & LOCKS) {
01076
01077 op = (TransactionOP)(op & ~LOCKS);
01078 wlock = LockS;
01079 }
01080 else if (op & LOCKN) {
01081
01082 if (popsync)
01083 *popsync = True;
01084 if (exists)
01085 *exists = False;
01086 return Success;
01087 }
01088
01089 xmh = dbh->vd->trs_mh;
01090 trs = (Transaction *)XM_ADDR(xmh, trctx->trs_off);
01091
01092 trs->access_time = current_time();
01093
01094 ESM_ASSERT(trs->magic == TRS_MAGIC, 0, xid);
01095
01096
01097 obj_ht = (HashTable *)XM_ADDR(xmh, dbh->vd->shm_addr->trs_hdr.obj_ht);
01098 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off);
01099
01100 #ifndef NO_INTERNAL_LOCK
01101 MUTEX_LOCKER mtlock(trs->mut);
01102 #endif
01103 if (op == OCREATE)
01104 tro_off = 0;
01105 else
01106 tro_off = HashTableTRObjectLookup(xmh, trs_ht, oid);
01107
01108 if (!tro_off) {
01109 if (exists && *exists) {
01110 *exists = False;
01111 return Success;
01112 }
01113
01114 if (wlock != DefaultLock)
01115 lock = wlock;
01116 else {
01117 ESM_ASSERT_ABORT(op < OP_CNT && op >= 0 && trctx->lockmodeIndex < LockModeIndex_CNT && trctx->lockmodeIndex >= 0, 0, 0);
01118 lock = opLockMode[op][trctx->lockmodeIndex];
01119 }
01120
01121 ESM_REGISTER_LOCK(dbh, lock);
01122
01123 if (lock == LockN) {
01124
01125
01126 if (op != OCREATE) {
01127 if (NEED_LOCK(trctx))
01128 MUTEX_LOCK(mp, xid);
01129 XMOffset tpo_off = HashTablePObjectLookup(xmh, obj_ht, oid);
01130 if (tpo_off) {
01131 PObject *tpo = (PObject *)XM_ADDR(xmh, tpo_off);
01132 if (tpo->lockPxid && (tpo->lockPxid != xid || tpo->tridx != tridx)) {
01133 if (NEED_LOCK(trctx))
01134 MUTEX_UNLOCK(mp, xid);
01135 return statusMake(INVALID_OID, "invalid oid '%s'",
01136 getOidString(oid));
01137 }
01138 }
01139
01140 if (NEED_LOCK(trctx))
01141 MUTEX_UNLOCK(mp, xid);
01142 }
01143
01144 if (popsync)
01145 *popsync = True;
01146 return Success;
01147 }
01148
01149 #ifdef QUICK_READ_LOCK
01150
01151
01152
01153
01154
01155 if (op == OREAD && lock == LockS) {
01156 if (popsync)
01157 *popsync = True;
01158 return Success;
01159 }
01160 #endif
01161 if (NEED_LOCK(trctx))
01162 MUTEX_LOCK(mp, xid);
01163
01164 tro = makeTRObject(dbh, oid, op, lock, trs_ht, trctx, &tro_off, mp,
01165 xid);
01166
01167 if (!tro) {
01168 if (NEED_LOCK(trctx))
01169 MUTEX_UNLOCK(mp, xid);
01170 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01171 }
01172
01173 MUTEX_LOCKER trolock(tro->mut);
01174 #ifndef NO_INTERNAL_LOCK
01175 mtlock.unlock();
01176 #endif
01177
01178 if (trctx->params.ratioalrt != 0 &&
01179 trctx->params.magorder != MAX_MAGORDER &&
01180 trctx->params.magorder * trctx->params.ratioalrt < trs->obj_cnt) {
01181 if (NEED_LOCK(trctx))
01182 MUTEX_UNLOCK(mp, xid);
01183 return statusMake(ERROR, "transaction ratio alert: "
01184 "%d objects in transaction, magorder is %u, "
01185 "ratioalrt is %u", trs->obj_cnt,
01186 trctx->params.magorder,
01187 trctx->params.ratioalrt);
01188 }
01189
01190 if (op == OCREATE)
01191 po_off = 0;
01192 else
01193 po_off = HashTablePObjectLookup(xmh, obj_ht, oid);
01194
01195 if (!po_off) {
01196 po = makePObject(xmh, oid, obj_ht, trctx->trs_off, &po_off,
01197 lock);
01198 if (!po) {
01199 if (NEED_LOCK(trctx))
01200 MUTEX_UNLOCK(mp, xid);
01201 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01202 }
01203
01204 TT(printf("ESM_objectLock (new PObject = %d)\n", po_off));
01205 }
01206 else {
01207 po = (PObject *)XM_ADDR(xmh, po_off);
01208
01209 po->refcnt++;
01210 #ifdef TRS_SECURE
01211 ESM_ASSERT(po->magic == POBJ_MAGIC, mp, xid);
01212 #endif
01213 TT(printf("ESM_objectLock (old PObject = %d)\n", po_off));
01214 }
01215
01216 tro->po_off = po_off;
01217
01218 if (po->lockPxid && (po->lockPxid != xid || po->tridx != tridx)) {
01219 if (NEED_LOCK(trctx))
01220 MUTEX_UNLOCK(mp, xid);
01221 return statusMake(INVALID_OID, "invalid oid '%s'",
01222 getOidString(oid));
01223 }
01224
01225 if (NEED_OBJLOCK(trctx)) {
01226 if (lock == LockX || lock == LockS || lock == LockSX) {
01227 se = pobjLock(dbh, xmh, trctx, trs, tro_off, lock,
01228 po, mp, xid, trctx->params.wait_timeout);
01229
01230 if (!se) {
01231 if (lock == LockX)
01232 tro->lockX = 1;
01233 else if (lock == LockS)
01234 tro->lockS = 1;
01235 else if (lock == LockSX)
01236 tro->lockSX = 1;
01237 }
01238 }
01239 else if (lock == LockP && trctx->params.trsmode != TransactionOff) {
01240 po->lockPxid = xid;
01241 po->tridx = tridx;
01242 tro->lockP = 1;
01243 }
01244
01245 if (!se) {
01246 if (!addTransOwner(xmh, po, trctx->trs_off, lock)) {
01247 if (NEED_LOCK(trctx))
01248 MUTEX_UNLOCK(mp, xid);
01249 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01250 }
01251 }
01252 }
01253
01254 trs->obj_cnt++;
01255
01256 if (NEED_LOCK(trctx))
01257 MUTEX_UNLOCK(mp, xid);
01258 }
01259 else {
01260 TransactionOP oop;
01261
01262 tro = (TRObject *)XM_ADDR(xmh, tro_off);
01263
01264 MUTEX_LOCKER trolock(tro->mut);
01265 #ifndef NO_INTERNAL_LOCK
01266 mtlock.unlock();
01267 #endif
01268
01269 #ifdef TRS_SECURE
01270 ESM_ASSERT(!memcmp(&tro->oid, oid, sizeof(Oid)), 0, 0);
01271 #endif
01272 if (tro->op == ODELETE)
01273 return statusMake(ERROR, "object %s is deleted",
01274 getOidString(oid));
01275
01276 oop = tro->op;
01277
01278 ESM_ASSERT_ABORT(tro->op < OP_CNT && tro->op >= 0 && op < OP_CNT && op >= 0, 0, 0);
01279 tro->op = crossOps[tro->op][op];
01280
01281 if (tro->op == OERROR)
01282 return statusMake(ERROR,
01283 "operation %d followed by %d is invalid",
01284 oop, op);
01285
01286 if (wlock != DefaultLock)
01287 lock = wlock;
01288 else
01289 lock = opLockMode[tro->op][trctx->lockmodeIndex];
01290
01291 ESM_REGISTER_LOCK(dbh, lock);
01292
01293 if (lock == LockN) {
01294 if (popsync)
01295 *popsync = True;
01296 return Success;
01297 }
01298
01299 #define OCREADEL_SYNC
01300 #ifdef OCREADEL_SYNC
01301 if (tro->op == OCREADEL) {
01302
01303 se = ESM_objectDelete(dbh, oid, OPShrinkingPhase);
01304 return se;
01305 }
01306 #endif
01307
01308 #ifdef TRS_SECURE
01309 ESM_ASSERT(tro->magic == TROBJ_MAGIC, 0, 0);
01310 #endif
01311 po = (PObject *)XM_ADDR(xmh, tro->po_off);
01312
01313 if (!tro->po_off) {
01314 IDB_LOG(IDB_LOG_TRANSACTION,
01315 ("internal transaction error: transaction object offset "
01316 "should not be null\n"));
01317 return statusMake(ERROR,
01318 "internal transaction error: "
01319 "transaction object offset "
01320 "should not be null");
01321 }
01322
01323 if (!po)
01324 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01325
01326 #ifdef TRS_SECURE
01327 ESM_ASSERT(po->magic == POBJ_MAGIC, 0, 0);
01328 #endif
01329
01330 if (po->lockPxid && (po->lockPxid != xid || po->tridx != tridx))
01331 return statusMake(INVALID_OID, "invalid oid '%s'",
01332 getOidString(oid));
01333
01334 if (NEED_OBJLOCK(trctx)) {
01335 if (lock == LockX || lock == LockSX) {
01336 if ((lock == LockX && !tro->lockX) ||
01337 (lock == LockSX && !tro->lockSX && !tro->lockX)) {
01338 LockMode olock;
01339 int r = 0;
01340 if (tro->lockS) olock = LockS;
01341 else if (tro->lockX) olock = LockX;
01342 else if (tro->lockSX) olock = LockSX;
01343 else olock = DefaultLock;
01344
01345 if (NEED_LOCK(trctx))
01346 MUTEX_LOCK(mp, xid);
01347
01348 if (olock) {
01349
01350 if (tro->lockS) {
01351 pobjUnlock(dbh->vd, xmh, po, LockS, mp, xid);
01352 tro->lockS = 0;
01353 }
01354
01355 if (tro->lockSX) {
01356 pobjUnlock(dbh->vd, xmh, po, LockSX, mp, xid);
01357 tro->lockSX = 0;
01358 }
01359 }
01360
01361 se = pobjLock(dbh, xmh, trctx, trs, tro_off, lock,
01362 po, mp, xid, trctx->params.wait_timeout);
01363
01364 if (!se) {
01365 if (olock)
01366 ESM_PObjectChangeTransOwnerLock(xmh, po, trctx->trs_off,
01367 lock, mp, xid);
01368
01369 else if (!addTransOwner(xmh, po, trctx->trs_off,
01370 lock)) {
01371 if (NEED_LOCK(trctx))
01372 MUTEX_UNLOCK(mp, xid);
01373 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01374 }
01375
01376 if (lock == LockX)
01377 tro->lockX++;
01378 else if (lock == LockSX)
01379 tro->lockSX++;
01380 }
01381 else if (olock) {
01382 if (tro->lockP)
01383 printf("OUH LA LA ERROR POTENTIELLE GRAVE!\n");
01384 tro->lockP = 0;
01385 ESM_PObjectSuppressTransOwner(xmh, po, trctx->trs_off,
01386 mp, xid);
01387 }
01388
01389 if (NEED_LOCK(trctx))
01390 MUTEX_UNLOCK(mp, xid);
01391 }
01392 else if (lock == LockX)
01393 tro->lockX++;
01394 else if (lock == LockSX)
01395 tro->lockSX++;
01396 }
01397 else if (lock == LockS) {
01398 if (!tro->lockS && !tro->lockX && !tro->lockSX) {
01399
01400 if (NEED_LOCK(trctx))
01401 MUTEX_LOCK(mp, xid);
01402
01403 se = pobjLock(dbh, xmh, trctx, trs, tro_off, LockS,
01404 po, mp, xid, trctx->params.wait_timeout);
01405
01406 if (!se) {
01407
01408 if (!addTransOwner(xmh, po, trctx->trs_off, lock)) {
01409 if (NEED_LOCK(trctx))
01410 MUTEX_UNLOCK(mp, xid);
01411 return statusMake(NO_SHMSPACE_LEFT, trTooLarge);
01412 }
01413
01414 tro->lockS = 1;
01415 }
01416
01417 if (NEED_LOCK(trctx))
01418 MUTEX_UNLOCK(mp, xid);
01419 }
01420 else if (tro->lockS)
01421 tro->lockS++;
01422 }
01423 else if (lock == LockP && trctx->params.trsmode != TransactionOff) {
01424 po->lockPxid = xid;
01425 po->tridx = tridx;
01426 tro->lockP++;
01427 }
01428 }
01429 }
01430
01431 if (!se) {
01432 if (popsync) {
01433 if (trctx->params.trsmode == TransactionOff) {
01434 if (op == OCHSIZE)
01435 return statusMake(ERROR,
01436 "size modify operation cannot be "
01437 "performed in transaction off mode");
01438 *popsync = True;
01439 }
01440 else if (op == OCHSIZE && tro->op == OCREATE)
01441 *popsync = False;
01442 else
01443 *popsync = opSync[tro->op] ? True : False;
01444 }
01445
01446 if (ptro)
01447 *ptro = tro;
01448 }
01449
01450 if (se) {
01451
01452
01453
01454
01455
01456
01457
01458
01459 IDB_LOG(IDB_LOG_TRANSACTION, ("ESM_objectLock(lock = %d, tro->lock %d, %d. po->refcnt %d, "
01460 "xid: %d: %s", lock, tro->lockS, tro->lockX, po->refcnt, xid,
01461 statusGet(se)));
01462 }
01463 return se;
01464 }
01465
01466 #ifdef EYEDB_USE_DATA_VMEM
01467 static void *
01468 #else
01469 static XMOffset
01470 #endif
01471 trobjDataMake(XMHandle *xmh, unsigned int size)
01472 {
01473 #ifdef EYEDB_USE_DATA_VMEM
01474 char *data = (char *)m_malloc(objDataGetSize(size));
01475 #else
01476 char *data = (char *)XMAlloc(xmh, objDataGetSize(size));
01477 #endif
01478
01479 if (!data)
01480 return XM_NULLOFFSET;
01481
01482 objDataSize(data) = size;
01483 objDataAll(data) = 0;
01484
01485 memset(objDataMask(data), 0, maskSize(size));
01486
01487 #ifdef EYEDB_USE_DATA_VMEM
01488
01489 return data;
01490 #else
01491 return XM_OFFSET(xmh, data);
01492 #endif
01493 }
01494
01495 static void
01496 pobjMakeMask(char *data, unsigned int start, unsigned int length)
01497 {
01498 if (start == 0 && length == objDataSize(data))
01499 objDataAll(data) = 1;
01500 else {
01501 char *m = objDataMask(data) + start;
01502
01503 while (length--)
01504 *m++ = 1;
01505 }
01506 }
01507
01508 char *
01509 ESM_trobjDataGetIfExist(DbHandle const *dbh, TRObject *tro)
01510 {
01511 XMHandle *xmh = dbh->vd->trs_mh;
01512
01513 if (!tro->data || !objDataAll(tro->data)) {
01514 return 0;
01515 }
01516
01517 #ifdef EYEDB_USE_DATA_VMEM
01518 return objDataData(tro->data);
01519 #else
01520 return XM_ADDR(xmh, tro->data) + objDataOffset;
01521 #endif
01522 }
01523
01524 char *
01525 ESM_trobjDataGet(DbHandle const *dbh, TRObject *tro, unsigned int size)
01526 {
01527 XMHandle *xmh = dbh->vd->trs_mh;
01528
01529 if (!tro->data)
01530 tro->data = trobjDataMake(xmh, size);
01531
01532 #ifdef EYEDB_USE_DATA_VMEM
01533 return (char *)tro->data;
01534 #else
01535 return XM_ADDR(xmh, tro->data);
01536 #endif
01537 }
01538
01539 void
01540 ESM_trobjDataWrite(char *dest, const char *src,
01541 unsigned int start, unsigned int length,
01542 OPMode opmode, Boolean opsync)
01543 {
01544 TT(printf("ESM_trobjDataWrite(opsync = %d, start = %d, length = %d, opmode = %d)\n", opsync, start, length, opmode));
01545 if (opmode == OPGrowingPhase) {
01546 if (opsync)
01547 memcpy(dest + start, src, length);
01548 else {
01549 memcpy(objDataData(dest) + start, src, length);
01550 pobjMakeMask(dest, start, length);
01551 }
01552 }
01553 else if (opmode == OPShrinkingPhase) {
01554
01555 if (length != objDataSize(src)) {
01556 IDB_LOG(IDB_LOG_TRANSACTION, ("trobjDataWRITE %d vs. %d\n", length, objDataSize(src)));
01557 abort();
01558 }
01559
01560 if (objDataAll(src))
01561 memcpy(dest, objDataData(src), length);
01562 else {
01563 char *m = objDataMask(src);
01564 int i, size = objDataSize(src);
01565
01566 src = objDataData(src);
01567
01568 for (i = 0; i < size; i++, dest++, src++, m++)
01569 if (*m)
01570 *dest = *src;
01571 }
01572 }
01573 }
01574
01575 Status
01576 ESM_trobjDataRead(char *dest, const char *src, const char *dbsrc,
01577 unsigned int start, unsigned int length,
01578 Boolean opsync, Boolean nocopy)
01579 {
01580 TT(printf("ESM_trobjDataRead(opsync = %d, start = %d, length = %d)\n", opsync, start, length));
01581
01582 if (opsync) {
01583 if (nocopy)
01584 *(const char **)dest = src + start;
01585 else
01586 memcpy(dest, src + start, length);
01587
01588 return Success;
01589 }
01590
01591 if (objDataAll(src)) {
01592 if (nocopy)
01593 *(const char **)dest = objDataData(src) + start;
01594 else
01595 memcpy(dest, objDataData(src) + start, length);
01596
01597 return Success;
01598 }
01599
01600 if (nocopy)
01601 return statusMake(ERROR, "internal error in trobjDataRead : "
01602 "cannot read without copy");
01603
01604 char *m = objDataMask(src) + start;
01605 int i, size = objDataSize(src);
01606
01607 src = objDataData(src) + start;
01608 dbsrc += start;
01609
01610 for (i = 0; i < length; i++, dest++, src++, dbsrc++, m++)
01611 *dest = (*m ? *src : *dbsrc);
01612
01613 return Success;
01614 }
01615
01616 Status
01617 ESM_bornAgainEpilogue(DbHandle const *dbh, Oid const *const o_oid,
01618 Oid const *const n_oid, NS ns, short datid)
01619 {
01620 TransactionContext *trctx;
01621 XMHandle *xmh;
01622 Transaction *trs;
01623 HashTable *obj_ht;
01624 HashTable *trs_ht;
01625 XMOffset off;
01626 Mutex *mp = TRS_MTX(dbh);
01627 Status se = Success;
01628 TRObject *o_tro, *n_tro;
01629 PObject *o_po, *n_po;
01630 unsigned int xid = dbh->vd->xid;
01631
01632 xmh = dbh->vd->trs_mh;
01633
01634 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
01635
01636 trs = (Transaction *)XM_ADDR(xmh, trctx->trs_off);
01637 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off),
01638 obj_ht = (HashTable *)XM_ADDR(xmh, dbh->vd->shm_addr->trs_hdr.obj_ht);
01639
01640 #ifndef NO_INTERNAL_LOCK
01641 MUTEX_LOCKER mtlock(trs->mut);
01642 #endif
01643 off = HashTableTRObjectLookup(xmh, trs_ht, o_oid);
01644 o_tro = (TRObject *)XM_ADDR(xmh, off);
01645 off = o_tro->po_off;
01646 o_po = (PObject *)XM_ADDR(xmh, off);
01647
01648 off = HashTableTRObjectLookup(xmh, trs_ht, n_oid);
01649 n_tro = (TRObject *)XM_ADDR(xmh, off);
01650 off = n_tro->po_off;
01651 n_po = (PObject *)XM_ADDR(xmh, off);
01652
01653 if (NEED_LOCK(trctx))
01654 MUTEX_LOCK(mp, xid);
01655 HashTablePObjectSuppress(xmh, obj_ht, n_po);
01656 HashTableTRObjectSuppress(xmh, trs_ht, n_tro);
01657
01658 n_tro->oid = *o_oid;
01659 n_po->oid = *o_oid;
01660
01661 HashTablePObjectInsert(xmh, obj_ht, n_po);
01662 HashTableTRObjectInsert(xmh, trs_ht, n_tro);
01663
01664 o_tro->oidloc.ns = ns+1;
01665 o_tro->oidloc.datid = datid;
01666
01667
01668 o_tro->oid.setUnique(o_tro->oid.getUnique() + 1);
01669 o_po->oid.setUnique(o_po->oid.getUnique() + 1);
01670
01671 if (NEED_LOCK(trctx))
01672 MUTEX_UNLOCK(mp, xid);
01673 return se;
01674 }
01675
01676 #define TRHT_COUNT 4096
01677
01678 void
01679 ESM_transInit(DbDescription *vd, char *addr, unsigned int shmsize)
01680 {
01681 DbShmHeader *shmh = (DbShmHeader *)addr;
01682 XMHandle *xmh;
01683 HashTable *ht;
01684
01685 IDB_LOG(IDB_LOG_TRANSACTION, ("ESM_transInit(0x%x, shmsize=%x)\n", addr, shmsize));
01686
01687 xmh = XMCreate((char *)(addr + SHM_HEADSIZE), shmsize - SHM_HEADSIZE, vd);
01688
01689 ht = HashTableCreate(xmh, TRHT_COUNT);
01690
01691 TT(printf("ESM_transInit(%p)\n", addr));
01692
01693 shmh->trs_hdr.obj_ht = XM_OFFSET(xmh, ht);
01694 shmh->trs_hdr.first_trs = 0;
01695 shmh->trs_hdr.tr_cnt = 0;
01696
01697 XMClose(xmh);
01698 }
01699
01700
01701 Status
01702 ESM_transactionCreate(DbHandle const *dbh,
01703 const TransactionParams *params, XMOffset *off)
01704 {
01705 if (dbh->vd->flags & NO_SHM_ACCESS) {
01706 return Success;
01707 }
01708
01709 XMHandle *xmh;
01710 XMOffset trs_off;
01711 TransHeader *trshd;
01712 Transaction *trs;
01713 HashTable *ht;
01714 Mutex *mp = TRS_MTX(dbh);
01715 unsigned int xid = dbh->vd->xid;
01716 Status se;
01717
01718
01719
01720
01721 xmh = dbh->vd->trs_mh;
01722 TT(printf("ESM_transactionCreate(%x)\n", xmh));
01723 trs = (Transaction *)XMAlloc(xmh, sizeof(Transaction));
01724
01725 if (!trs) {
01726 *off = XM_NULLOFFSET;
01727 return Success;
01728 }
01729
01730 #ifdef TRS_SECURE
01731 trs->magic = TRS_MAGIC;
01732 #endif
01733 trs->trs_state = TransACTIVE;
01734 trs->proc_state = NilProcState;
01735 trs->trobj_wait = 0;
01736 trs->lock_wait = (LockMode)0;
01737 trs->obj_cnt = 0;
01738 trs->del_obj_cnt = 0;
01739 trs->xid = dbh->vd->xid;
01740 trs->wrimmediate = (params->trsmode == TransactionOff ? True : False);
01741 trs->prot_update = False;
01742 trs->dl = 0;
01743 trs->timestamp = 0;
01744 trs->create_time = current_time();
01745 trs->access_time = current_time();
01746 #ifdef TRS_INTER_MUT
01747 mutexInit(dbh->vd, &trs->mut, &trs->mp, "TRANSACTION");
01748 #else
01749 trs->mut.init(eyedblib::Mutex::PROCESS_PRIVATE);
01750 #endif
01751
01752 ESM_transactionRegister(trs, mp, xid);
01753
01754 trs_off = XM_OFFSET(xmh, trs);
01755
01756 trshd = &dbh->vd->shm_addr->trs_hdr;
01757
01758 #ifdef TRS_DBG
01759
01760 #endif
01761
01762 se = MUTEX_LOCK_VOID(mp, xid);
01763 if (se) return se;
01764
01765 if (trshd->first_trs)
01766 ((Transaction *)XM_ADDR(xmh, trshd->first_trs))->prev = trs_off;
01767
01768 trs->next = trshd->first_trs;
01769 trs->prev = 0;
01770
01771 trshd->first_trs = trs_off;
01772 #ifndef NEW_TR_CNT
01773 trshd->tr_cnt++;
01774 #endif
01775
01776 MUTEX_UNLOCK(mp, xid);
01777
01778 TT(printf("creating transaction #%d\n", trshd->tr_cnt - 1));
01779
01780 ht = HashTableCreate(xmh, magorderHtCount(params->magorder));
01781
01782 trs->ht_off = XM_OFFSET(xmh, ht);
01783
01784 *off = trs_off;
01785 return Success;
01786 }
01787
01788 static void
01789 ESM_PObjectRemove(DbDescription *vd, XMHandle *xmh, HashTable *obj_ht,
01790 PObject *po)
01791 {
01792 TT(printf("PObjectRemove\n"));
01793
01794 if (po->cond) {
01795 condDelete(vd, xmh, po->cond);
01796
01797
01798
01799
01800 }
01801
01802 po->state = Deleted;
01803
01804 HashTablePObjectSuppress(xmh, obj_ht, po);
01805
01806 #ifdef TRS_SECURE
01807 po->magic = POBJ_MAGIC_DELETED;
01808 #endif
01809
01810 po->state = Zombie;
01811
01812 XMFree(xmh, po);
01813 }
01814
01815 static void
01816 check_trans_owner(XMHandle *xmh, PObject *po)
01817 {
01818 TransOwner *trs_own = &po->trs_own;
01819 while (trs_own) {
01820 Transaction *trs = (Transaction *)XM_ADDR(xmh, trs_own->trs_off);
01821 if (trs->magic != TRS_MAGIC)
01822 printf("%d: check_trans_owner: trs magic trsoff=%p failed\n", rpc_getpid(), XM_OFFSET(xmh, trs));
01823 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
01824 }
01825 }
01826
01827 static void
01828 ESM_PObjectSuppressTransOwner(XMHandle *xmh, PObject *po, XMOffset trs_off,
01829 Mutex *mp, unsigned int xid)
01830 {
01831 TT(printf("PObjectSuppressTransOwner trs_off = %d, oid = %d.%d\n",
01832 trs_off, po->oid.nx, po->oid.unique));
01833
01834 ESM_ASSERT_ABORT(po->trs_own.trs_off, mp, xid);
01835
01836 if (po->trs_own.trs_off == trs_off) {
01837 TT(printf("PObjectSuppressTransOwner : first link found #1\n"));
01838
01839 if (po->trs_own.next) {
01840 TransOwner *next_trs_own =
01841 ((TransOwner *)XM_ADDR(xmh, po->trs_own.next));
01842
01843 po->trs_own.trs_off = next_trs_own->trs_off;
01844 po->trs_own.trs_lock = next_trs_own->trs_lock;
01845 po->trs_own.next = next_trs_own->next;
01846 if (next_trs_own->next)
01847 ((TransOwner *)XM_ADDR(xmh, next_trs_own->next))->prev =
01848 XM_NULLOFFSET;
01849 XMFree(xmh, next_trs_own);
01850 }
01851 else {
01852 po->trs_own.trs_off = XM_NULLOFFSET;
01853 po->trs_own.trs_lock = DefaultLock;
01854 }
01855 po->trs_cnt--;
01856 }
01857 else {
01858 TransOwner *trs_own;
01859 int cnt = 0;
01860 trs_own = (TransOwner *)XM_ADDR(xmh, po->trs_own.next);
01861
01862 TT(printf("PObjectSuppressTransOwner : other link found #1 %p\n",
01863 po->trs_own.next));
01864
01865 while (trs_own) {
01866 if (trs_own->trs_off == trs_off) {
01867 TransOwner *next_trs_own, *prev_trs_own;
01868
01869 next_trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
01870 prev_trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->prev);
01871
01872 if (next_trs_own)
01873 next_trs_own->prev = trs_own->prev;
01874
01875 if (prev_trs_own)
01876 prev_trs_own->next = trs_own->next;
01877 else
01878 po->trs_own.next = trs_own->next;
01879
01880 XMFree(xmh, trs_own);
01881 TT(printf("PObjectSuppressTransOwner : %d link found\n", cnt));
01882 po->trs_cnt--;
01883 return;
01884 }
01885
01886 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
01887 cnt++;
01888 }
01889
01890 ESM_ASSERT_ABORT(0, mp, xid);
01891 }
01892 }
01893
01894 static Status
01895 TRObjectUnlock(DbHandle const *dbh, XMHandle *xmh, Mutex *mp,
01896 unsigned int xid, HashTable *obj_ht,
01897 TRObject *tro, XMOffset trs_off)
01898 {
01899 PObject *po;
01900 Status s;
01901 DbDescription *vd = dbh->vd;
01902 TransactionContext *trctx;
01903
01904 po = (PObject *)XM_ADDR(xmh, tro->po_off);
01905
01906 if (!po || po->state != Active)
01907 return Success;
01908
01909 #ifdef TRS_SECURE
01910 if (po->magic != POBJ_MAGIC)
01911 IDB_LOG(IDB_LOG_TRANSACTION, ("magic = %x, oid = %s\n", po->magic, getOidString(&po->oid)));
01912 ESM_ASSERT(po->magic == POBJ_MAGIC, 0, 0);
01913 #endif
01914 TT(printf("TRObjectUnlock(nx = %d)\n", tro->oid.nx));
01915
01916 trctx = &dbh->vd->trctx[TR_CNT(dbh)-1];
01917
01918 if (NEED_LOCK(trctx))
01919 MUTEX_LOCK(mp, xid);
01920
01921 if (NEED_OBJLOCK(trctx)) {
01922 if (tro->lockX) {
01923 s = pobjUnlock(vd, xmh, po, LockX, mp, xid);
01924 if (s) {
01925 if (NEED_LOCK(trctx))
01926 MUTEX_UNLOCK(mp, xid);
01927 return s;
01928 }
01929 }
01930 else if (tro->lockS) {
01931 s = pobjUnlock(vd, xmh, po, LockS, mp, xid);
01932 if (s) {
01933 if (NEED_LOCK(trctx))
01934 MUTEX_UNLOCK(mp, xid);
01935 return s;
01936 }
01937 }
01938 else if (tro->lockSX) {
01939 s = pobjUnlock(vd, xmh, po, LockSX, mp, xid);
01940 if (s) {
01941 if (NEED_LOCK(trctx))
01942 MUTEX_UNLOCK(mp, xid);
01943 return s;
01944 }
01945 }
01946
01947
01948 if (tro->lockP) {
01949 po->lockPxid = 0;
01950 po->tridx = ~0;
01951 }
01952
01953
01954
01955 if (tro->lockX || tro->lockS || tro->lockP)
01956 ESM_PObjectSuppressTransOwner(xmh, po, trs_off, mp, xid);
01957 }
01958
01959 if (!--po->refcnt)
01960 ESM_PObjectRemove(vd, xmh, obj_ht, po);
01961
01962 if (NEED_LOCK(trctx))
01963 MUTEX_UNLOCK(mp, xid);
01964
01965 tro->po_off = XM_NULLOFFSET;
01966
01967 if (tro->data) {
01968 #ifdef EYEDB_USE_DATA_VMEM
01969 #ifdef TRS_SECURE
01970 *(char *)tro->data = 0;
01971 #endif
01972 free((char *)tro->data);
01973 #else
01974 #ifdef TRS_SECURE
01975 *objDataData(XM_ADDR(xmh, tro->data)) = 0;
01976 #endif
01977 XMFree(xmh, XM_ADDR(xmh, tro->data));
01978 #endif
01979 }
01980
01981 return Success;
01982 }
01983
01984 static Status
01985 ESM_pobjectRealize(DbHandle const *dbh, XMHandle *xmh,
01986 TRObject *tro, TransState state,
01987 RecoveryMode recovmode)
01988 {
01989
01990 Status se = Success;
01991 PObject *po = (PObject *)XM_ADDR(xmh, tro->po_off);
01992
01993 if (!po)
01994 return se;
01995
01996 if (state == TransCOMMITING) {
01997
01998 if (tro->op == OCREATE) {
01999
02000
02001
02002
02003
02004 ESM_objectValidate(dbh, &po->oid);
02005
02006
02007
02008
02009 }
02010 #ifdef OCREADEL_SYNC
02011 else if (tro->op == ODELETE)
02012 #else
02013 else if (tro->op == ODELETE || tro->op == OCREADEL)
02014 #endif
02015 {
02016 if (tro->oidloc.ns) {
02017 po->oid.setUnique(po->oid.getUnique() - 1);
02018 se = ESM_objectDeleteByOidLoc(dbh, &po->oid, tro->oidloc.ns-1,
02019 tro->oidloc.datid);
02020 }
02021 else
02022 se = ESM_objectDelete(dbh, &po->oid, OPShrinkingPhase);
02023
02024
02025
02026
02027
02028 }
02029 else if (tro->op == OWRITE) {
02030 if (tro->data) {
02031 #ifdef EYEDB_USE_DATA_VMEM
02032 se = ESM_objectWrite(dbh, 0, 0, (void *)tro->data, &po->oid,
02033 OPShrinkingPhase);
02034 #else
02035 se = ESM_objectWrite(dbh, 0, 0, XM_ADDR(xmh, tro->data), &po->oid,
02036 OPShrinkingPhase);
02037 #endif
02038
02039
02040
02041
02042 }
02043
02044 if (tro->prot_oid_set) {
02045 se = ESM_objectProtectionSet(dbh, &po->oid, &tro->prot_oid,
02046 OPShrinkingPhase);
02047
02048
02049
02050
02051 }
02052 }
02053 else if (tro->op == OCHSIZE) {
02054
02055
02056
02057
02058
02059 }
02060 }
02061 else if (state == TransABORTING) {
02062 #ifdef OCREADEL_SYNC
02063 if (tro->op == OCREATE)
02064 #else
02065 if (tro->op == OCREATE || tro->op == OCREADEL)
02066 #endif
02067 {
02068 se = ESM_objectDelete(dbh, &po->oid, OPShrinkingPhase);
02069
02070
02071
02072
02073 }
02074
02075 if (tro->op == ODELETE && tro->oidloc.ns) {
02076 po->oid.setUnique(po->oid.getUnique() - 1);
02077 ESM_objectRestore(dbh, &po->oid, tro->oidloc.ns-1,
02078 tro->oidloc.datid);
02079
02080
02081
02082
02083 }
02084 }
02085
02086 return se;
02087 }
02088
02089 void
02090 ESM_transactionObjectProtSet(TRObject *tro, const Oid *prot_oid)
02091 {
02092 tro->prot_oid_set = True;
02093 tro->prot_oid = *prot_oid;
02094 }
02095
02096 static void
02097 wait_a_little()
02098 {
02099 int i;
02100 static float f;
02101
02102 f = 0.0;
02103
02104 for (i = 0; i < 10000; i++)
02105 f += 0.1;
02106 }
02107
02108 static Boolean
02109 ESM_isTrsActive(Transaction *trs)
02110 {
02111 int del_obj_cnt = trs->del_obj_cnt;
02112
02113 #if 1
02114 wait_a_little();
02115
02116 #else
02117 sleep(1);
02118 #endif
02119
02120 if (del_obj_cnt == trs->del_obj_cnt) {
02121 IDB_LOG(IDB_LOG_TRANSACTION, ("transaction is *not* active\n"));
02122 return False;
02123 }
02124
02125 IDB_LOG(IDB_LOG_TRANSACTION, ("transaction is active\n"));
02126 return True;
02127 }
02128
02129 static Boolean
02130 ESM_checkTrsState(Mutex *mp, unsigned int xid,
02131 Transaction *trs, TransState *state,
02132 Boolean *trs_active)
02133 {
02134
02135
02136 if (trs_active)
02137 *trs_active = False;
02138
02139 if (MUTEX_LOCK_VOID(mp, xid))
02140 return False;
02141
02142 if (trs->trs_state == TransCOMMITED ||
02143 trs->trs_state == TransABORTED) {
02144 MUTEX_UNLOCK(mp, xid);
02145 IDB_LOG(IDB_LOG_TRANSACTION,
02146 ("WARNING: transaction %d [%p] already deleted\n",
02147 xid, trs));
02148 return False;
02149 }
02150
02151 if (trs->trs_state == TransCOMMITING) {
02152 MUTEX_UNLOCK(mp, xid);
02153 if (!ESM_isTrsActive(trs)) {
02154 IDB_LOG(IDB_LOG_TRANSACTION, ("WARNING try to recover commiting\n"));
02155 *state = trs->trs_state;
02156 return True;
02157 }
02158
02159 IDB_LOG(IDB_LOG_TRANSACTION, ("WARNING commiting is running\n"));
02160 if (trs_active)
02161 *trs_active = True;
02162 return False;
02163 }
02164
02165 if (trs->trs_state == TransABORTING) {
02166 MUTEX_UNLOCK(mp, xid);
02167
02168 if (!ESM_isTrsActive(trs)) {
02169 IDB_LOG(IDB_LOG_TRANSACTION, ("WARNING try to recover aborting\n"));
02170 *state = trs->trs_state;
02171 return True;
02172 }
02173
02174 IDB_LOG(IDB_LOG_TRANSACTION, ("WARNING aborting is running\n"));
02175 if (trs_active)
02176 *trs_active = True;
02177 return False;
02178 }
02179
02180 if (!*state && trs->trs_state == TransACTIVE)
02181 *state = TransABORTING;
02182
02183 trs->trs_state = *state;
02184
02185 MUTEX_UNLOCK(mp, xid);
02186
02187 return True;
02188 }
02189
02190 #define SECURE_FREE
02191
02192 #ifdef SECURE_FREE
02193 struct SecureFree {
02194 SecureFree(XMHandle *xmh, void *trs) : xmh(xmh), trs(trs) {}
02195 ~SecureFree() { XMFree(xmh, trs); }
02196 XMHandle *xmh;
02197 void *trs;
02198 };
02199 #endif
02200
02201 static Status
02202 ESM_transactionDeleteRealize(DbHandle const *dbh,
02203 XMOffset trs_off, unsigned int xid,
02204 XMHandle *xmh, TransState state,
02205 Boolean *trs_active)
02206 {
02207 if (dbh->vd->flags & NO_SHM_ACCESS) {
02208 return Success;
02209 }
02210
02211 DbShmHeader *shmh = dbh->vd->shm_addr;
02212 Transaction *trs, *trs_next, *trs_prev;
02213 TransHeader *trshd;
02214 HashTable *trs_ht;
02215 int i, count;
02216 XMOffset *tro_poff;
02217 HashTable *obj_ht;
02218 Mutex *mp = TRS_MTX(dbh);
02219 int cnt = 0;
02220 int del_cnt = 0;
02221 time_t t;
02222 Status s, s_err;
02223 TRObject *tro;
02224 TransactionContext *trctx = &dbh->vd->trctx[TR_CNT(dbh)];
02225
02226
02227
02228
02229
02230
02231 s_err = Success;
02232
02233 trshd = &shmh->trs_hdr;
02234 trs = (Transaction *)XM_ADDR(xmh, trs_off);
02235 #ifdef SECURE_FREE
02236
02237
02238 SecureFree _(xmh, trs);
02239 #endif
02240
02241 #ifndef NO_INTERNAL_LOCK
02242 MUTEX_LOCKER mtlock(trs->mut);
02243 #endif
02244
02245
02246
02247
02248 time(&t);
02249
02250 IDB_LOG(IDB_LOG_TRANSACTION, ("transaction delete xid=%d\n", xid));
02251
02252
02253
02254
02255 #ifdef TRS_SECURE
02256 ESM_ASSERT(trs->magic == TRS_MAGIC, 0, 0);
02257 #endif
02258
02259 if (!ESM_checkTrsState(mp, xid, trs, &state, trs_active))
02260 return Success;
02261
02262 obj_ht = (HashTable *)XM_ADDR(xmh, trshd->obj_ht);
02263
02264 trs_ht = (HashTable *)XM_ADDR(xmh, trs->ht_off);
02265
02266 count = trs_ht->mask + 1;
02267
02268 IDB_LOG(IDB_LOG_TRANSACTION,
02269 ("transaction xid=%d %s [object count=%d, state=%d]\n",
02270 xid, state == TransCOMMITING ? "commiting" : "aborting",
02271 trs->obj_cnt, state));
02272
02273 #ifdef KEEP_ORDER
02274 tro = (TRObject *)XM_ADDR(xmh, trs_ht->xlast);
02275 while (tro) {
02276 XMOffset xprev = tro->xprev;
02277 #else
02278
02279
02280
02281
02282
02283
02284 #endif
02285 if (tro->state == Active) {
02286 if (!trs->wrimmediate) {
02287 s = ESM_pobjectRealize(dbh, xmh, tro, state,
02288 trctx->params.recovmode);
02289 if (s) return s;
02290 }
02291 #ifdef TRS_SECURE
02292 ESM_ASSERT(tro->magic == TROBJ_MAGIC ||
02293 tro->magic == TROBJ_MAGIC_DELETED, 0, 0);
02294 #endif
02295 s = TRObjectUnlock(dbh, xmh, mp, xid, obj_ht, tro, trs_off);
02296 if (s) s_err = s;
02297 tro->state = Deleted;
02298 #ifdef TRS_SECURE
02299 tro->magic = TROBJ_MAGIC_DELETED;
02300 #endif
02301 trs->del_obj_cnt++;
02302 }
02303 else
02304 del_cnt++;
02305
02306
02307
02308 #ifdef KEEP_ORDER
02309 tro = (TRObject *)XM_ADDR(xmh, xprev);
02310 #else
02311 tro = (TRObject *)XM_ADDR(xmh, next);
02312 #endif
02313 cnt++;
02314 #ifndef KEEP_ORDER
02315
02316 #endif
02317 }
02318
02319
02320 trs->trs_state = (trs->trs_state == TransABORTING ? TransABORTED :
02321 TransCOMMITED);
02322
02323 IDB_LOG(IDB_LOG_TRANSACTION, ("transaction xid=%d done\n", xid));
02324
02325
02326 for (i = 0, tro_poff = &trs_ht->offs[0]; i < count; i++, tro_poff++) {
02327 TRObject *tro = (TRObject *)XM_ADDR(xmh, *tro_poff);
02328 while (tro) {
02329 XMOffset next = tro->next;
02330 tro->state = Zombie;
02331 XMFree(xmh, tro);
02332 tro = (TRObject *)XM_ADDR(xmh, next);
02333 }
02334 }
02335
02336 if (state == TransCOMMITING)
02337 shmh->stat.tr_commit_cnt = h2x_u32(x2h_u32(shmh->stat.tr_commit_cnt)+1);
02338 else if (state == TransABORTING)
02339 shmh->stat.tr_abort_cnt = h2x_u32(x2h_u32(shmh->stat.tr_abort_cnt)+1);
02340
02341
02342
02343 ESM_transactionUnregister(trs, mp, xid);
02344
02345 s = MUTEX_LOCK_VOID(mp, xid);
02346 if (s)
02347 return s;
02348
02349 trs_next = (Transaction *)XM_ADDR(xmh, trs->next);
02350 trs_prev = (Transaction *)XM_ADDR(xmh, trs->prev);
02351
02352 if (trs_next)
02353 trs_next->prev = trs->prev;
02354
02355 if (trs_prev)
02356 trs_prev->next = trs->next;
02357 else
02358 trshd->first_trs = trs->next;
02359
02360 #ifndef NEW_TR_CNT
02361 trshd->tr_cnt--;
02362 assert(trshd->tr_cnt >= 0);
02363 #endif
02364 MUTEX_UNLOCK(mp, xid);
02365
02366 XMFree(xmh, trs_ht);
02367
02368 #ifdef TRS_SECURE
02369 trs->magic = 0;
02370 trs->xid = 0;
02371 #endif
02372 #ifndef SECURE_FREE
02373 XMFree(xmh, trs);
02374 #endif
02375
02376 #ifdef TRS_DBG
02377
02378 #endif
02379 TT(printf("%d objects found in transaction %d\n", cnt, trshd->tr_cnt));
02380
02381 TT(printf("deleting transaction %p: done!\n", trs_off));
02382 return s_err;
02383 }
02384
02385 Status
02386 ESM_transactionDelete(DbHandle const *dbh, XMOffset trs_off,
02387 TransState state)
02388 {
02389 return ESM_transactionDeleteRealize(dbh, trs_off, dbh->vd->xid,
02390 dbh->vd->trs_mh, state, 0);
02391 }
02392
02393 #define REINIT(MP, XID)
02394
02395 Status
02396 ESM_transactionsRelease(DbDescription *vd, DbShmHeader *shmh,
02397 const char *dbfile, int xid,
02398 XMHandle *xmh, Boolean *trs_active)
02399 {
02400 TransHeader *trshd;
02401 Transaction *trs;
02402 int i;
02403 int cnt = 0, pcnt = 0;
02404 Mutex *mp = &vd->mp[TRS];
02405 XMOffset trs_off;
02406 XMOffset trs_x[MAXTRS];
02407 DbHandle *dbh;
02408 Status se;
02409 time_t t;
02410
02411 time(&t);
02412 IDB_LOG(IDB_LOG_TRANSACTION, ("transactions release xid=%d\n", xid));
02413
02414 REINIT(&shmh->lock.mp, xid);
02415 REINIT(&shmh->mtx.mp[MAP], xid);
02416 REINIT(&shmh->mtx.mp[TRS], xid);
02417 REINIT(&shmh->mtx.mp[NX], xid);
02418 REINIT(&shmh->mtx.mp[SLT], xid);
02419 REINIT(&shmh->mtx.mp[LSL], xid);
02420
02421 trshd = &shmh->trs_hdr;
02422
02423 MUTEX_LOCK(mp, xid);
02424
02425 trs_off = trshd->first_trs;
02426 trs = (Transaction *)XM_ADDR(xmh, trs_off);
02427
02428 cnt = 0;
02429 pcnt = 0;
02430
02431 while (trs) {
02432 cnt++;
02433 #ifdef TRS_SECURE
02434 if (trs->magic != TRS_MAGIC)
02435 IDB_LOG(IDB_LOG_TRANSACTION, ("TRS magic 0x%x, expected 0x%x\n",
02436 trs->magic, TRS_MAGIC));
02437 ESM_ASSERT(trs->magic == TRS_MAGIC, 0, 0);
02438 #endif
02439 if (!xid || trs->xid == xid)
02440 trs_x[pcnt++] = trs_off;
02441 trs_off = trs->next;
02442 trs = (Transaction *)XM_ADDR(xmh, trs_off);
02443 }
02444
02445 MUTEX_UNLOCK(mp, xid);
02446
02447 IDB_LOG(IDB_LOG_TRANSACTION, ("%d transactions running\n", cnt));
02448 IDB_LOG(IDB_LOG_TRANSACTION, ("%d transactions for the current closing process\n", pcnt));
02449
02450 if (pcnt) {
02451 Status se = ESM_dbOpen(dbfile, VOLRW, 0, 0, 0, 0, xid, 0, &dbh);
02452
02453
02454
02455
02456
02457
02458
02459 if (se)
02460 return se;
02461
02462 for (i = 0; i < pcnt; i++) {
02463 if (((Transaction *)XM_ADDR(xmh, trs_x[i]))->magic)
02464 se = ESM_transactionDeleteRealize(dbh, trs_x[i], xid, xmh, NilTransState, trs_active);
02465 else
02466 IDB_LOG(IDB_LOG_TRANSACTION, ("WARNING transaction deletion reentrance\n"));
02467
02468 if (se)
02469 break;
02470 }
02471
02472 ESM_dbClose(dbh);
02473 return se;
02474 }
02475
02476 TT(printf("TRANSACTIONS RELEASE #3\n"));
02477 return Success;
02478 }
02479
02480 void
02481 DbMutexesInit(DbDescription *vd, DbShmHeader *shmh)
02482 {
02483 lockInit(vd, &shmh->dblock_W, "database W");
02484 lockInit(vd, &shmh->dblock_RW, "database RW");
02485 lockInit(vd, &shmh->dblock_Wtrans, "database Wtrans");
02486
02487 mutexInit(vd, VD2MTX(vd, MAP), &shmh->mtx.mp[MAP], "map");
02488 mutexInit(vd, VD2MTX(vd, TRS), &shmh->mtx.mp[TRS], "trs");
02489 mutexInit(vd, VD2MTX(vd, NX), &shmh->mtx.mp[NX], "nx");
02490 mutexInit(vd, VD2MTX(vd, SLT), &shmh->mtx.mp[SLT], "slot");
02491 mutexInit(vd, VD2MTX(vd, LSL), &shmh->mtx.mp[LSL], "lsl");
02492 }
02493
02494 void
02495 DbMutexesLightInit(DbDescription *vd, DbShmHeader *shmh)
02496 {
02497 lockLightInit(vd, &shmh->dblock_W);
02498 lockLightInit(vd, &shmh->dblock_RW);
02499 lockLightInit(vd, &shmh->dblock_Wtrans);
02500
02501 mutexLightInit(vd, &vd->mp[MAP], &shmh->mtx.mp[MAP]);
02502 mutexLightInit(vd, &vd->mp[TRS], &shmh->mtx.mp[TRS]);
02503 mutexLightInit(vd, &vd->mp[NX], &shmh->mtx.mp[NX]);
02504 mutexLightInit(vd, &vd->mp[SLT], &shmh->mtx.mp[SLT]);
02505 mutexLightInit(vd, &vd->mp[LSL], &shmh->mtx.mp[LSL]);
02506 }
02507
02508 Status
02509 DbMutexesRelease(DbDescription *vd, DbShmHeader *shmh, unsigned int xid)
02510 {
02511 if (vd->flags & NO_SHM_ACCESS) {
02512 return Success;
02513 }
02514
02515 Mutex *mp;
02516 bool lockX;
02517
02518 IDB_LOG(IDB_LOG_TRANSACTION, ("eyedbsm: DbMutexesRelease\n"));
02519
02520 DbLock *dblocks[] = {&shmh->dblock_W, &shmh->dblock_RW, &shmh->dblock_Wtrans};
02521
02522 for (unsigned int i = 0; i < sizeof(dblocks)/sizeof(dblocks[0]); i++) {
02523 while (findDbLockXID(vd, dblocks[i], xid, &lockX, True)) {
02524 IDB_LOG(IDB_LOG_TRANSACTION, ("eyedbsm: main db mutex is kept by CURRENT xid = %d lockX = %d\n", xid, lockX));
02525
02526
02527
02528 if (lockX)
02529 unlockX(vd, dblocks[i], xid);
02530 else
02531 unlockS(vd, dblocks[i], xid);
02532 }
02533 }
02534
02535 mp = vd->mp;
02536
02537 for (int i = 0; i < MTX_CNT; i++, mp++)
02538 mutexCheckNotLock(mp, xid);
02539
02540 fflush(stderr);
02541 return Success;
02542 }
02543
02544 static Transaction **
02545 transOwnerMake(XMHandle *xmh, XMOffset trs_off, PObject *po,
02546 LockMode lockmode, int *pn)
02547 {
02548 Transaction **trs_set;
02549 Transaction *trs;
02550 TransOwner *trs_own;
02551 int n;
02552
02553 if (!po->trs_own.trs_off) {
02554 *pn = 0;
02555 return (Transaction **)0;
02556 }
02557
02558 n = 0;
02559
02560 trs_set = (Transaction **)m_calloc(sizeof(Transaction *), po->trs_cnt);
02561
02562 if (lockmode == LockX) {
02563 trs = (Transaction *)XM_ADDR(xmh, po->trs_own.trs_off);
02564
02565 if (trs->magic != TRS_MAGIC)
02566 printf("%d: trs magic trsoff=%p failed\n", rpc_getpid(), XM_OFFSET(xmh, trs));
02567 if (trs->trobj_wait || po->trs_own.trs_off == trs_off)
02568 trs_set[n++] = trs;
02569
02570 trs_own = (TransOwner *)XM_ADDR(xmh, po->trs_own.next);
02571
02572 while (trs_own) {
02573 trs = (Transaction *)XM_ADDR(xmh, trs_own->trs_off);
02574 if (trs->magic != TRS_MAGIC)
02575 printf("%d: trs magic trsoff=%p failed\n", rpc_getpid(), XM_OFFSET(xmh, trs));
02576 if (trs->trobj_wait || trs_own->trs_off == trs_off)
02577 trs_set[n++] = trs;
02578 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
02579 }
02580
02581
02582 }
02583 else {
02584 if (po->trs_own.trs_lock == LockX) {
02585 trs = (Transaction *)XM_ADDR(xmh, po->trs_own.trs_off);
02586 if (trs->magic != TRS_MAGIC)
02587 printf("%d: trs magic trsoff=%p failed\n", rpc_getpid(), XM_OFFSET(xmh, trs));
02588
02589 if (po->trs_own.trs_off == trs_off || trs->trobj_wait)
02590 trs_set[n++] = trs;
02591 }
02592
02593 trs_own = (TransOwner *)XM_ADDR(xmh, po->trs_own.next);
02594
02595 while (trs_own) {
02596 if (trs_own->trs_lock == LockX) {
02597 trs = (Transaction *)XM_ADDR(xmh, trs_own->trs_off);
02598 if (trs->magic != TRS_MAGIC)
02599 printf("%d: trs magic trsoff=%p failed\n", rpc_getpid(), XM_OFFSET(xmh, trs));
02600 if (trs_own->trs_off == trs_off || trs->trobj_wait)
02601 trs_set[n++] = trs;
02602 }
02603
02604 trs_own = (TransOwner *)XM_ADDR(xmh, trs_own->next);
02605 }
02606
02607
02608 }
02609
02610 *pn = n;
02611 return trs_set;
02612 }
02613
02614 static Status
02615 deadLockCheckRealize(XMHandle *xmh, XMOffset trs_off,
02616 const Oid *oid_base,
02617 const Oid *oid_w,
02618 Transaction **trs_set, int n)
02619 {
02620 int i;
02621 for (i = 0; i < n; i++) {
02622 Transaction *trs = trs_set[i];
02623
02624 #ifdef TRS_SECURE
02625 if (trs->magic != TRS_MAGIC)
02626 printf("!!ouh lala!! %p vs. %p\n", trs->magic, XM_OFFSET(xmh, trs));
02627
02628 ESM_ASSERT(trs->magic == TRS_MAGIC, 0, 0);
02629 #endif
02630 if (oid_w && XM_OFFSET(xmh, trs) == trs_off)
02631 return statusMake(DEADLOCK_DETECTED, "trying lock %s, dead lock through %s",
02632 getOidString(oid_base),
02633 getOidString(oid_w));
02634 else if (trs->dl)
02635 continue;
02636 else if (trs->trobj_wait) {
02637 TRObject *trow = (TRObject *)XM_ADDR(xmh, trs->trobj_wait);
02638 PObject *pow;
02639 Transaction **xtrs_set;
02640 int xn;
02641 Status se;
02642
02643 pow = (PObject *)XM_ADDR(xmh, trow->po_off);
02644 ESM_ASSERT(pow, 0, 0);
02645
02646 trs->dl = 1;
02647
02648 xtrs_set = transOwnerMake(xmh, trs_off, pow, trs->lock_wait, &xn);
02649 if (xn) {
02650 se = deadLockCheckRealize(xmh, trs_off, oid_base,
02651 &pow->oid, xtrs_set, xn);
02652 free(xtrs_set);
02653 }
02654 else
02655 se = Success;
02656
02657 trs->dl = 0;
02658
02659 if (se)
02660 return se;
02661 }
02662
02663 }
02664
02665 return Success;
02666 }
02667
02668 Status
02669 deadLockCheck(XMHandle *xmh, Transaction *trs, PObject *po,
02670 LockMode lockmode)
02671 {
02672 Transaction **trs_set;
02673 XMOffset trs_off = XM_OFFSET(xmh, trs);
02674 int n;
02675
02676 trs_set = transOwnerMake(xmh, trs_off, po, lockmode, &n);
02677
02678 if (n) {
02679 Status se = deadLockCheckRealize(xmh, trs_off, &po->oid,
02680 0, trs_set, n);
02681 free(trs_set);
02682 return se;
02683 }
02684
02685 return Success;
02686 }
02687
02688 const char *
02689 getOidString(const Oid *oid)
02690 {
02691 #define N 8
02692 static char str[N][128];
02693 static int n;
02694 char *p;
02695
02696 if (!oid)
02697 return "NULL";
02698
02699 if (n >= N)
02700 n = 0;
02701
02702 p = str[n++];
02703
02704 sprintf(p, "%u.%u.%u:oid", oid->getNX(), dbidGet(oid), oid->getUnique());
02705 return p;
02706 }
02707
02708
02709
02710
02711
02712 static pthread_t recovid;
02713 static pthread_mutex_t recov_mp = PTHREAD_MUTEX_INITIALIZER;
02714
02715 #define MAXTRS 64
02716
02717 typedef struct {
02718
02719 unsigned int xid;
02720 } RecovArg;
02721
02722 #define INTERVAL 5
02723
02724 static int recovtrs_cnt;
02725
02726 static struct {
02727 Mutex *mp;
02728 Transaction *trs;
02729 } recovtrs[MAXTRS];
02730
02731
02732
02733
02734
02735 static void
02736 markActive(Transaction *trs, Mutex *mp, unsigned int xid)
02737 {
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750 time(&trs->timestamp);
02751 }
02752
02753 static void
02754 markInactive(Transaction *trs, Mutex *mp, unsigned int xid)
02755 {
02756 if (!MUTEX_LOCK_VOID(mp, xid)) {
02757 trs->timestamp = 0;
02758 MUTEX_UNLOCK(mp, xid);
02759 }
02760 }
02761
02762
02763 static void *
02764 recovfun(void *arg)
02765 {
02766 unsigned int xid = ((RecovArg *)arg)->xid;
02767
02768 free(arg);
02769
02770 for (;;) {
02771 int i;
02772 sleep(INTERVAL);
02773
02774 pthread_mutex_lock(&recov_mp);
02775
02776 for (i = 0; i < recovtrs_cnt; i++)
02777 if (recovtrs[i].trs)
02778 markActive(recovtrs[i].trs, recovtrs[i].mp, xid);
02779
02780 pthread_mutex_unlock(&recov_mp);
02781 }
02782 return (void *)0;
02783 }
02784
02785
02786 static void
02787 ESM_transactionRegister(Transaction *trs, Mutex *mp, unsigned int xid)
02788 {
02789 int i;
02790
02791 if (!recovid && !getenv("EYEDB_NO_MARK_ACTIVE")) {
02792 RecovArg *arg = (RecovArg *)m_malloc(sizeof(RecovArg));
02793 arg->xid = xid;
02794 pthread_create(&recovid, NULL, recovfun, arg);
02795 }
02796
02797 markActive(trs, mp, xid);
02798
02799 pthread_mutex_lock(&recov_mp);
02800
02801 for (i = 0; i < MAXTRS; i++)
02802 if (!recovtrs[i].mp) {
02803 recovtrs[i].trs = trs;
02804 recovtrs[i].mp = mp;
02805 if (i >= recovtrs_cnt)
02806 recovtrs_cnt = i+1;
02807 break;
02808 }
02809
02810 pthread_mutex_unlock(&recov_mp);
02811 }
02812
02813 static void
02814 ESM_transactionUnregister(Transaction *trs, Mutex *mp, unsigned int xid)
02815 {
02816 int i;
02817
02818 markInactive(trs, mp, xid);
02819
02820 pthread_mutex_lock(&recov_mp);
02821
02822 for (i = 0; i < recovtrs_cnt; i++)
02823 if (recovtrs[i].trs == trs) {
02824 recovtrs[i].mp = 0;
02825 recovtrs[i].trs = 0;
02826 if (i == recovtrs_cnt - 1)
02827 recovtrs_cnt--;
02828 break;
02829 }
02830
02831 pthread_mutex_unlock(&recov_mp);
02832 }
02833
02834 Status
02835 ESM_transactionsGarbage(DbHandle const *dbh, Boolean mustLock)
02836 {
02837 DbShmHeader *shmh = dbh->vd->shm_addr;
02838 unsigned int xid = dbh->vd->xid;
02839 Mutex *mp = TRS_MTX(dbh);
02840 XMHandle *xmh = dbh->vd->trs_mh;
02841 TransHeader *trshd;
02842 Transaction *trs;
02843 int inactrs_cnt = 0;
02844 int i;
02845 Transaction *inactrs[MAXTRS];
02846 Status se;
02847
02848
02849
02850
02851 trshd = &shmh->trs_hdr;
02852
02853 if (mustLock && (se = MUTEX_LOCK_VOID(mp, xid)))
02854 return se;
02855
02856 trs = (Transaction *)XM_ADDR(xmh, trshd->first_trs);
02857
02858 while(trs) {
02859 if (!ESM_isTransactionActive(trs) &&
02860 trs->trs_state != TransABORTING &&
02861 trs->trs_state != TransCOMMITING) {
02862 time_t ts;
02863 inactrs[inactrs_cnt++] = trs;
02864 time(&ts);
02865 trs->timestamp = ts;
02866 }
02867
02868 trs = (Transaction *)XM_ADDR(xmh, trs->next);
02869 }
02870
02871 if (mustLock)
02872 MUTEX_UNLOCK(mp, xid);
02873
02874 for (i = 0; i < inactrs_cnt; i++) {
02875
02876
02877
02878
02879 IDB_LOG(IDB_LOG_TRANSACTION,
02880 ("RECOVERY SYSTEM : aborting the transaction xid = %d\n",
02881 inactrs[i]->xid));
02882 if (trace_garb_trs) {
02883 printf("Deleting inactive transaction\n");
02884 printf(" Server Pid %d\n", inactrs[i]->xid);
02885 printf(" Object Count %d\n", inactrs[i]->obj_cnt);
02886 printf(" Deleted Object Count %d\n", inactrs[i]->del_obj_cnt);
02887 printf(" Last Access on %s\n", eyedblib::setbuftime(inactrs[i]->access_time));
02888 }
02889 se = ESM_transactionDelete(dbh, XM_OFFSET(xmh, inactrs[i]), TransABORTING);
02890 if (se) return se;
02891 #ifdef USE_SHM_REFCNT
02892 if (mustLock && (se = MUTEX_LOCK_VOID(mp, xid)))
02893 return se;
02894 --shmh->refcnt;
02895 if (mustLock)
02896 MUTEX_UNLOCK(mp, xid);
02897 #endif
02898 }
02899
02900 return Success;
02901 }
02902
02903 extern Boolean
02904 ESM_isTransactionActive(Transaction *trs)
02905 {
02906 time_t ts;
02907
02908 time(&ts);
02909
02910 if (ts - trs->timestamp > 6 * INTERVAL)
02911 return False;
02912
02913 return True;
02914 }
02915 }