/ Check-in [9de05bfb]
Login

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

Overview
Comment:Simplifications to the SHM locking implementation in os_unix.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9de05bfb09e29bafdf5782263330fe8eefcfaba3
User & Date: drh 2010-05-05 18:20:07
Context
2010-05-05
18:46
Do not compare page sizes on source and destination of backup until transactions are started and the page sizes are locked. This is a fix to check-in [7bd44794c4]. check-in: ec715778 user: drh tags: trunk
18:20
Simplifications to the SHM locking implementation in os_unix.c. check-in: 9de05bfb user: drh tags: trunk
16:23
Prohibit backup if the destination is using WAL and has a different page size from the source. check-in: 7bd44794 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
....
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
....
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
....
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
....
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
....
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
....
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
....
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
** The unixShm.pFile element is initialized when the object is created
** and is read-only thereafter.
*/
struct unixShm {
  unixShmFile *pFile;        /* The underlying unixShmFile object */
  unixShm *pNext;            /* Next unixShm with the same unixShmFile */
  u8 lockState;              /* Current lock state */
  u8 readLock;               /* Which of the two read-lock states to use */
  u8 hasMutex;               /* True if holding the unixShmFile mutex */
  u8 hasMutexBuf;            /* True if holding pFile->mutexBuf */
  u8 sharedMask;             /* Mask of shared locks held */
  u8 exclMask;               /* Mask of exclusive locks held */
#ifdef SQLITE_DEBUG
  u8 id;                     /* Id of this connection with its unixShmFile */
#endif
................................................................................
*/
#define SQLITE_UNIX_SHM_INCR  4096

/*
** Constants used for locking
*/
#define UNIX_SHM_BASE      32        /* Byte offset of the first lock byte */
#define UNIX_SHM_MUTEX     0x01      /* Mask for MUTEX lock */
#define UNIX_SHM_DMS       0x04      /* Mask for Dead-Man-Switch lock */
#define UNIX_SHM_A         0x10      /* Mask for region locks... */
#define UNIX_SHM_B         0x20
#define UNIX_SHM_C         0x40
#define UNIX_SHM_D         0x80

#ifdef SQLITE_DEBUG
/*
................................................................................
  static int iBuf = 0;
  char *z;

  z = &zBuf[iBuf];
  iBuf += 8;
  if( iBuf>=sizeof(zBuf) ) iBuf = 0;

  z[0] = (mask & UNIX_SHM_MUTEX) ? 'M' : '.';
  z[1] = (mask & UNIX_SHM_DMS)   ? 'S' : '.';
  z[2] = (mask & UNIX_SHM_A)     ? 'A' : '.';
  z[3] = (mask & UNIX_SHM_B)     ? 'B' : '.';
  z[4] = (mask & UNIX_SHM_C)     ? 'C' : '.';
  z[5] = (mask & UNIX_SHM_D)     ? 'D' : '.';
  z[6] = 0;
  return z;
}
#endif /* SQLITE_DEBUG */

/*
** Apply posix advisory locks for all bytes identified in lockMask.
**
** lockMask might contain multiple bits but all bits are guaranteed
** to be contiguous.
**
** Locks block if the UNIX_SHM_MUTEX bit is set and are non-blocking
** otherwise.
*/
static int unixShmSystemLock(
  unixShmFile *pFile,   /* Apply locks to this open shared-memory segment */
  int lockType,         /* F_UNLCK, F_RDLCK, or F_WRLCK */
  u8 lockMask           /* Which bytes to lock or unlock */
){
................................................................................
  /* Access to the unixShmFile object is serialized by the caller */
  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );

  /* Initialize the locking parameters */
  memset(&f, 0, sizeof(f));
  f.l_type = lockType;
  f.l_whence = SEEK_SET;
  if( (lockMask & UNIX_SHM_MUTEX)!=0 && lockType!=F_UNLCK ){
    lockOp = F_SETLKW;
    OSTRACE(("SHM-LOCK requesting blocking lock\n"));
  }else{
    lockOp = F_SETLK;
  }

  /* Find the first bit in lockMask that is set */
................................................................................
    }
    pFile->fid.dev = sStat.st_dev;
    pFile->fid.ino = sStat.st_ino;

    /* Check to see if another process is holding the dead-man switch.
    ** If not, truncate the file to zero length. 
    */
    if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_MUTEX) ){
      rc = SQLITE_IOERR_LOCK;
      goto shm_open_err;
    }
    if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
      if( ftruncate(pFile->h, 0) ){
        rc = SQLITE_IOERR;
      }
    }
    if( rc==SQLITE_OK ){
      rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
    }
    unixShmSystemLock(pFile, F_UNLCK, UNIX_SHM_MUTEX);
    if( rc ) goto shm_open_err;
  }

  /* Make the new connection a child of the unixShmFile */
  p->pFile = pFile;
  p->pNext = pFile->pFirst;
#ifdef SQLITE_DEBUG
................................................................................
        rc = SQLITE_BUSY;
        assert( p->lockState==SQLITE_SHM_UNLOCK );
        for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
          rc = unixShmSharedLock(pFile, p, UNIX_SHM_A|UNIX_SHM_B);
          if( rc==SQLITE_BUSY ){
            rc = unixShmSharedLock(pFile, p, UNIX_SHM_D);
            if( rc==SQLITE_OK ){
              p->lockState = p->readLock = SQLITE_SHM_READ_FULL;
            }
          }else{
            unixShmUnlock(pFile, p, UNIX_SHM_B);
            p->lockState = p->readLock = SQLITE_SHM_READ;
          }
        }
      }else if( p->lockState==SQLITE_SHM_WRITE ){
        rc = unixShmSharedLock(pFile, p, UNIX_SHM_A);
        unixShmUnlock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
        p->lockState = p->readLock = SQLITE_SHM_READ;
      }else{
        assert( p->lockState==SQLITE_SHM_RECOVER );
        unixShmUnlock(pFile, p, UNIX_SHM_MUTEX);
        p->lockState = p->readLock;
        rc = SQLITE_OK;
      }
      break;
    }
    case SQLITE_SHM_WRITE: {
      assert( p->lockState==SQLITE_SHM_READ 
              || p->lockState==SQLITE_SHM_READ_FULL );
................................................................................
      break;
    }
    case SQLITE_SHM_CHECKPOINT: {
      assert( p->lockState==SQLITE_SHM_UNLOCK
           || p->lockState==SQLITE_SHM_PENDING
           || p->lockState==SQLITE_SHM_RECOVER );
      if( p->lockState==SQLITE_SHM_RECOVER ){
        unixShmUnlock(pFile, p, UNIX_SHM_MUTEX);
        p->lockState = SQLITE_SHM_CHECKPOINT;
        rc = SQLITE_OK;
      }
      if( p->lockState==SQLITE_SHM_UNLOCK ){
        rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_B|UNIX_SHM_C);
        if( rc==SQLITE_OK ){
          p->lockState = SQLITE_SHM_PENDING;
................................................................................
    }
    default: {
      assert( desiredLock==SQLITE_SHM_RECOVER );
      assert( p->lockState==SQLITE_SHM_READ
           || p->lockState==SQLITE_SHM_READ_FULL
           || p->lockState==SQLITE_SHM_CHECKPOINT );
      assert( sqlite3_mutex_held(pFile->mutexBuf) );
      rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_MUTEX);
      if( rc==SQLITE_OK ){
        p->lockState = SQLITE_SHM_RECOVER;
      }
      break;
    }
  }
  sqlite3_mutex_leave(pFile->mutex);







<







 







<
|







 







<
|
|
|
|
|
|










|







 







|







 







<
<
<
<








<







 







|



|





|


|
|







 







|







 







|







4644
4645
4646
4647
4648
4649
4650

4651
4652
4653
4654
4655
4656
4657
....
4662
4663
4664
4665
4666
4667
4668

4669
4670
4671
4672
4673
4674
4675
4676
....
4689
4690
4691
4692
4693
4694
4695

4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
....
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
....
5022
5023
5024
5025
5026
5027
5028




5029
5030
5031
5032
5033
5034
5035
5036

5037
5038
5039
5040
5041
5042
5043
....
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
....
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
....
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
** The unixShm.pFile element is initialized when the object is created
** and is read-only thereafter.
*/
struct unixShm {
  unixShmFile *pFile;        /* The underlying unixShmFile object */
  unixShm *pNext;            /* Next unixShm with the same unixShmFile */
  u8 lockState;              /* Current lock state */

  u8 hasMutex;               /* True if holding the unixShmFile mutex */
  u8 hasMutexBuf;            /* True if holding pFile->mutexBuf */
  u8 sharedMask;             /* Mask of shared locks held */
  u8 exclMask;               /* Mask of exclusive locks held */
#ifdef SQLITE_DEBUG
  u8 id;                     /* Id of this connection with its unixShmFile */
#endif
................................................................................
*/
#define SQLITE_UNIX_SHM_INCR  4096

/*
** Constants used for locking
*/
#define UNIX_SHM_BASE      32        /* Byte offset of the first lock byte */

#define UNIX_SHM_DMS       0x01      /* Mask for Dead-Man-Switch lock */
#define UNIX_SHM_A         0x10      /* Mask for region locks... */
#define UNIX_SHM_B         0x20
#define UNIX_SHM_C         0x40
#define UNIX_SHM_D         0x80

#ifdef SQLITE_DEBUG
/*
................................................................................
  static int iBuf = 0;
  char *z;

  z = &zBuf[iBuf];
  iBuf += 8;
  if( iBuf>=sizeof(zBuf) ) iBuf = 0;


  z[0] = (mask & UNIX_SHM_DMS)   ? 'S' : '.';
  z[1] = (mask & UNIX_SHM_A)     ? 'A' : '.';
  z[2] = (mask & UNIX_SHM_B)     ? 'B' : '.';
  z[3] = (mask & UNIX_SHM_C)     ? 'C' : '.';
  z[4] = (mask & UNIX_SHM_D)     ? 'D' : '.';
  z[5] = 0;
  return z;
}
#endif /* SQLITE_DEBUG */

/*
** Apply posix advisory locks for all bytes identified in lockMask.
**
** lockMask might contain multiple bits but all bits are guaranteed
** to be contiguous.
**
** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
** otherwise.
*/
static int unixShmSystemLock(
  unixShmFile *pFile,   /* Apply locks to this open shared-memory segment */
  int lockType,         /* F_UNLCK, F_RDLCK, or F_WRLCK */
  u8 lockMask           /* Which bytes to lock or unlock */
){
................................................................................
  /* Access to the unixShmFile object is serialized by the caller */
  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );

  /* Initialize the locking parameters */
  memset(&f, 0, sizeof(f));
  f.l_type = lockType;
  f.l_whence = SEEK_SET;
  if( lockMask==UNIX_SHM_C && lockType!=F_UNLCK ){
    lockOp = F_SETLKW;
    OSTRACE(("SHM-LOCK requesting blocking lock\n"));
  }else{
    lockOp = F_SETLK;
  }

  /* Find the first bit in lockMask that is set */
................................................................................
    }
    pFile->fid.dev = sStat.st_dev;
    pFile->fid.ino = sStat.st_ino;

    /* Check to see if another process is holding the dead-man switch.
    ** If not, truncate the file to zero length. 
    */




    if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
      if( ftruncate(pFile->h, 0) ){
        rc = SQLITE_IOERR;
      }
    }
    if( rc==SQLITE_OK ){
      rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
    }

    if( rc ) goto shm_open_err;
  }

  /* Make the new connection a child of the unixShmFile */
  p->pFile = pFile;
  p->pNext = pFile->pFirst;
#ifdef SQLITE_DEBUG
................................................................................
        rc = SQLITE_BUSY;
        assert( p->lockState==SQLITE_SHM_UNLOCK );
        for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
          rc = unixShmSharedLock(pFile, p, UNIX_SHM_A|UNIX_SHM_B);
          if( rc==SQLITE_BUSY ){
            rc = unixShmSharedLock(pFile, p, UNIX_SHM_D);
            if( rc==SQLITE_OK ){
              p->lockState = SQLITE_SHM_READ_FULL;
            }
          }else{
            unixShmUnlock(pFile, p, UNIX_SHM_B);
            p->lockState = SQLITE_SHM_READ;
          }
        }
      }else if( p->lockState==SQLITE_SHM_WRITE ){
        rc = unixShmSharedLock(pFile, p, UNIX_SHM_A);
        unixShmUnlock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
        p->lockState = SQLITE_SHM_READ;
      }else{
        assert( p->lockState==SQLITE_SHM_RECOVER );
        unixShmUnlock(pFile, p, UNIX_SHM_C);
        p->lockState = SQLITE_SHM_READ;
        rc = SQLITE_OK;
      }
      break;
    }
    case SQLITE_SHM_WRITE: {
      assert( p->lockState==SQLITE_SHM_READ 
              || p->lockState==SQLITE_SHM_READ_FULL );
................................................................................
      break;
    }
    case SQLITE_SHM_CHECKPOINT: {
      assert( p->lockState==SQLITE_SHM_UNLOCK
           || p->lockState==SQLITE_SHM_PENDING
           || p->lockState==SQLITE_SHM_RECOVER );
      if( p->lockState==SQLITE_SHM_RECOVER ){
        unixShmUnlock(pFile, p, UNIX_SHM_C);
        p->lockState = SQLITE_SHM_CHECKPOINT;
        rc = SQLITE_OK;
      }
      if( p->lockState==SQLITE_SHM_UNLOCK ){
        rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_B|UNIX_SHM_C);
        if( rc==SQLITE_OK ){
          p->lockState = SQLITE_SHM_PENDING;
................................................................................
    }
    default: {
      assert( desiredLock==SQLITE_SHM_RECOVER );
      assert( p->lockState==SQLITE_SHM_READ
           || p->lockState==SQLITE_SHM_READ_FULL
           || p->lockState==SQLITE_SHM_CHECKPOINT );
      assert( sqlite3_mutex_held(pFile->mutexBuf) );
      rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_C);
      if( rc==SQLITE_OK ){
        p->lockState = SQLITE_SHM_RECOVER;
      }
      break;
    }
  }
  sqlite3_mutex_leave(pFile->mutex);