SQLite4
Check-in [f7fc6aeec8]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add connect/disconnect locking. And locking primitives for single-process mode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f7fc6aeec8f3a568a472fa04b367b9ea4010f95f
User & Date: dan 2013-10-23 20:28:42
Context
2013-10-23
22:43
Fix undetected multiplication overflow check-in: 2eba06d522 user: peterreid tags: trunk
20:28
Add connect/disconnect locking. And locking primitives for single-process mode. check-in: f7fc6aeec8 user: dan tags: trunk
19:31
Progress on reading and writing frames from and to the log file. check-in: 5ba2ff0701 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btInt.h.

   196    196   /*************************************************************************
   197    197   ** Interface to bt_lock.c functionality.
   198    198   */
   199    199   typedef struct BtShared BtShared;
   200    200   typedef struct BtLock BtLock;
   201    201   struct BtLock {
   202    202     /* These three are set by the bt_pager module and thereafter used by 
   203         -  ** both bt_lock and bt_pager. */
          203  +  ** the bt_lock, bt_pager and bt_log modules. */
   204    204     sqlite4_env *pEnv;              /* SQLite environment */
   205    205     bt_env *pVfs;                   /* Bt environment */
   206    206     bt_file *pFd;                   /* Database file descriptor */
   207    207   
   208    208     /* These are used only by the bt_lock module. */
   209    209     BtShared *pShared;              /* Shared by all handles on this file */
   210    210     BtLock *pNext;                  /* Next connection using pShared */
          211  +  u32 mExclLock;                  /* Mask of exclusive locks held */
          212  +  u32 mSharedLock;                /* Mask of shared locks held */
   211    213   };
   212    214   
   213    215   /* Connect and disconnect procedures */
   214    216   int sqlite4BtLockConnect(BtLock*, int (*xRecover)(BtLock*));
   215    217   int sqlite4BtLockDisconnect(BtLock*, int(*xCkpt)(BtLock*), int(*xDel)(BtLock*));
   216    218   
   217    219   /* Obtain and release the WRITER lock */

Changes to src/bt_lock.c.

    14     14   #include "btInt.h"
    15     15   
    16     16   #include "sqliteInt.h"
    17     17   
    18     18   #include <string.h>
    19     19   #include <assert.h>
    20     20   #include <stdio.h>
           21  +
           22  +#define BT_LOCK_DMS1       0      /* DMS1 */
           23  +#define BT_LOCK_DMS2_RW    1      /* DMS2/rw */
           24  +#define BT_LOCK_DMS2_RO    2      /* DMS2/ro */
           25  +#define BT_LOCK_WRITER     3      /* WRITER lock */
           26  +#define BT_LOCK_CKPTER     4      /* CHECKPOINTER lock */
           27  +#define BT_LOCK_READER0    5      /* Array of BT_NREADER locks */
           28  +
           29  +#define BT_LOCK_UNLOCK     0
           30  +#define BT_LOCK_SHARED     1
           31  +#define BT_LOCK_EXCL       2
    21     32   
    22     33   typedef struct BtFile BtFile;
    23     34   
    24     35   /*
    25     36   ** Global data. All global variables used by code in this file are grouped
    26     37   ** into the following structure instance.
    27     38   **
................................................................................
    69     80   
    70     81   /*
    71     82   ** Relinquish the mutex obtained by calling btLockMutexEnter().
    72     83   */
    73     84   static void btLockMutexLeave(){
    74     85     /* todo... */
    75     86   }
           87  +
           88  +/*
           89  +** Attempt to obtain the lock identified by the iLock and bExcl parameters.
           90  +** If successful, return SQLITE4_OK. If the lock cannot be obtained because 
           91  +** there exists some other conflicting lock, return SQLITE4_BUSY. If some 
           92  +** other error occurs, return an SQLite4 error code.
           93  +**
           94  +** Parameter iLock must be one of BT_LOCK_WRITER, WORKER or CHECKPOINTER,
           95  +** or else a value returned by the BT_LOCK_READER macro.
           96  +*/
           97  +static int btLockLockop(
           98  +  BtLock *p,                      /* BtLock handle */
           99  +  int iLock,                      /* Slot to lock */
          100  +  int eOp,                        /* One of BT_LOCK_UNLOCK, SHARED or EXCL */
          101  +  int bBlock                      /* True for a blocking lock */
          102  +){
          103  +  const u32 mask = ((u32)1 << iLock);
          104  +  int rc = SQLITE4_OK;
          105  +  BtShared *pShared = p->pShared;
          106  +
          107  +  assert( iLock>=0 && iLock<(BT_LOCK_READER0 + BT_NREADER) );
          108  +  assert( (BT_LOCK_READER0+BT_NREADER)<=32 );
          109  +  assert( eOp==BT_LOCK_UNLOCK || eOp==BT_LOCK_SHARED || eOp==BT_LOCK_EXCL );
          110  +
          111  +  /* Check for a no-op. Proceed only if this is not one of those. */
          112  +  if( (eOp==BT_LOCK_UNLOCK && (mask & (p->mExclLock|p->mSharedLock))!=0)
          113  +   || (eOp==BT_LOCK_SHARED && (mask & (p->mExclLock|p->mSharedLock))==0)
          114  +   || (eOp==BT_LOCK_EXCL   && (mask & p->mExclLock)==0)
          115  +  ){
          116  +    BtLock *pIter;
          117  +    int nExcl = 0;                /* Number of connections holding EXCLUSIVE */
          118  +    int nShared = 0;              /* Number of connections holding SHARED */
          119  +    sqlite4_mutex_enter(pShared->pClientMutex);
          120  +
          121  +    /* Figure out the locks currently held by this process on iLock, not
          122  +    ** including any held by this connection.  */
          123  +    for(pIter=pShared->pLock; pIter; pIter=pIter->pNext){
          124  +      assert( (pIter->mExclLock & pIter->mSharedLock)==pIter->mExclLock );
          125  +      if( pIter!=p ){
          126  +        assert( (pIter->mExclLock & p->mSharedLock)==0 );
          127  +        assert( (pIter->mSharedLock & p->mExclLock)==0 );
          128  +        if( mask & pIter->mExclLock ){
          129  +          nExcl++;
          130  +        }else if( mask & pIter->mSharedLock ){
          131  +          nShared++;
          132  +        }
          133  +      }
          134  +    }
          135  +    assert( nExcl==0 || nExcl==1 );
          136  +    assert( nExcl==0 || nShared==0 );
          137  +
          138  +    switch( eOp ){
          139  +      case BT_LOCK_UNLOCK:
          140  +        if( nShared==0 ){
          141  +#if 0
          142  +          lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_UNLOCK);
          143  +#endif
          144  +        }
          145  +        p->mExclLock &= ~mask;
          146  +        p->mSharedLock &= ~mask;
          147  +        break;
          148  +
          149  +      case BT_LOCK_SHARED:
          150  +        if( nExcl ){
          151  +          rc = SQLITE4_BUSY;
          152  +        }else{
          153  +          if( nShared==0 ){
          154  +#if 0
          155  +            rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_SHARED);
          156  +#endif
          157  +          }
          158  +          if( rc==SQLITE4_OK ){
          159  +            p->mSharedLock |= mask;
          160  +            p->mExclLock &= ~mask;
          161  +          }
          162  +        }
          163  +        break;
          164  +
          165  +      default:
          166  +        assert( eOp==BT_LOCK_EXCL );
          167  +        if( nExcl || nShared ){
          168  +          rc = SQLITE4_BUSY;
          169  +        }else{
          170  +#if 0
          171  +          rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_EXCL);
          172  +#endif
          173  +          if( rc==SQLITE4_OK ){
          174  +            p->mSharedLock |= mask;
          175  +            p->mExclLock |= mask;
          176  +          }
          177  +        }
          178  +        break;
          179  +    }
          180  +
          181  +    sqlite4_mutex_leave(p->pClientMutex);
          182  +  }
          183  +
          184  +  return rc;
          185  +}
          186  +
    76    187   
    77    188   /*
    78    189   ** Connect to the database as a read/write connection. If recovery
    79    190   ** is required (i.e. if this is the first connection to the db), invoke 
    80    191   ** the xRecover() method.
    81    192   **
    82    193   ** Return SQLITE4_OK if successful, or an SQLite4 error code if an
................................................................................
   131    242       sqlite4_mutex_enter(pShared->pClientMutex);
   132    243       p->pNext = pShared->pLock;
   133    244       pShared->pLock = p;
   134    245       sqlite4_mutex_leave(pShared->pClientMutex);
   135    246       p->pShared = pShared;
   136    247     }
   137    248   
   138         -  if( rc==SQLITE4_OK && pShared->nRef==1 ){
   139         -    rc = xRecover(p);
          249  +  if( rc==SQLITE4_OK ){
          250  +    rc = btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_EXCL, 1);
          251  +    if( rc==SQLITE4_OK ){
          252  +      rc = btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_EXCL, 0);
          253  +      if( rc==SQLITE4_OK ){
          254  +        rc = btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_EXCL, 0);
          255  +      }
          256  +      if( rc==SQLITE4_OK ){
          257  +        rc = xRecover(p);
          258  +      }
          259  +      btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_UNLOCK, 0);
          260  +      btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_UNLOCK, 0);
          261  +      if( rc==SQLITE4_OK || rc==SQLITE4_BUSY ){
          262  +        rc = btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_SHARED, 0);
          263  +      }
          264  +      btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_UNLOCK, 0);
          265  +    }
   140    266     }
   141    267   
   142    268     return rc;
   143    269   }
   144    270   
   145    271   /*
   146    272   ** Disconnect the read/write connection passed as the first argument
................................................................................
   161    287     BtLock *p,                      /* Locker handle */
   162    288     int (*xCkpt)(BtLock*),          /* Callback to checkpoint database */
   163    289     int (*xDel)(BtLock*)            /* Callback to delete wal+shm files */
   164    290   ){
   165    291     BtShared *pShared = p->pShared;
   166    292     BtLock **pp;
   167    293     int rc;                         /* Return code */
   168         -  rc = xCkpt(p);
   169         -  if( rc==SQLITE4_OK ){
   170         -    rc = xDel(p);
   171         -  }
   172    294   
   173    295     sqlite4_mutex_enter(pShared->pClientMutex);
   174    296     for(pp=&p->pShared->pLock; *pp!=p; pp=&(*pp)->pNext);
   175    297     *pp = (*pp)->pNext;
   176    298     sqlite4_mutex_leave(pShared->pClientMutex);
          299  +
          300  +  rc = btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_EXCL, 1);
          301  +  if( rc==SQLITE4_OK ){
          302  +    rc = btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_EXCL, 0);
          303  +    if( rc==SQLITE4_OK ){
          304  +      rc = xCkpt(p);
          305  +    }
          306  +    if( rc==SQLITE4_OK ){
          307  +      rc = btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_EXCL, 0);
          308  +    }
          309  +    if( rc==SQLITE4_OK ){
          310  +      rc = xDel(p);
          311  +    }
          312  +    if( rc==SQLITE4_BUSY ) rc = SQLITE4_OK;
          313  +    btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_UNLOCK, 0);
          314  +    btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_UNLOCK, 0);
          315  +    btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_UNLOCK, 0);
          316  +  }
   177    317   
   178    318     btLockMutexEnter();
   179    319     pShared->nRef--;
   180    320     if( pShared->nRef==0 ){
   181    321       int i;
   182    322       BtShared **ppS;
   183    323       for(ppS=&gShared.pDatabase; *ppS!=pShared; ppS=&(*ppS)->pNext);

Changes to src/bt_log.c.

   236    236   }
   237    237   
   238    238   static void btLogZeroSnapshot(BtLog *pLog){
   239    239     bt_env *pVfs = pLog->pLock->pVfs;
   240    240     memset(&pLog->snapshot, 0, sizeof(BtShmHdr));
   241    241     pLog->snapshot.nSector = pVfs->xSectorSize(pLog->pFd);
   242    242   }
          243  +
          244  +/*
          245  +** Run log recovery. In other words, read the log file from disk and 
          246  +** initialize the shared-memory accordingly.
          247  +*/
          248  +static int btLogRecover(BtLog *pLog){
          249  +  return SQLITE4_OK;
          250  +}
   243    251   
   244    252   /*
   245    253   ** Open the log file for pager pPager. If successful, return the BtLog* 
   246    254   ** handle via output variable *ppLog. If parameter bRecover is true, then
   247    255   ** also run database recovery before returning. In this case, the caller
   248    256   ** has already obtained the required locks.
   249    257   */
................................................................................
   263    271     memset(pLog, 0, sizeof(BtLog));
   264    272     pLog->pLock = (BtLock*)pPager;
   265    273   
   266    274     zWal = sqlite4BtPagerFilename(pPager, BT_PAGERFILE_LOG);
   267    275     rc = pVfs->xOpen(pEnv, pVfs, zWal, 0, &pLog->pFd);
   268    276   
   269    277     if( rc==SQLITE4_OK && bRecover ){
   270         -    /* TODO: Run real recovery... */
   271         -
   272    278       rc = btLogMapShm(pLog, 0);
   273    279       if( rc==SQLITE4_OK ){
   274    280         btLogZeroSnapshot(pLog);
          281  +      rc = btLogRecover(pLog);
          282  +    }
          283  +    if( rc==SQLITE4_OK ){
   275    284         rc = btLogUpdateSharedHdr(pLog);
   276    285       }
   277    286     }
   278    287   
   279    288    open_out:
   280    289     if( rc!=SQLITE4_OK ){
   281    290       sqlite4_free(pEnv, pLog);