lock.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
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) /*(X, fflush(stdout))*/
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   /* pobject part */
00307   /* these functions assumes that mp is already locked! */
00308 
00309   /*
00310     #undef TRACE
00311     #define TRACE(X) X
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 }

Generated on Mon Dec 22 18:15:58 2008 for eyedb by  doxygen 1.5.3