SQLite

Check-in [dcad244f58]
Login

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

Overview
Comment:Bug fix in the unix locking code. (CVS 1574)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: dcad244f58453d23f2bcb749dcea077434bbd08c
User & Date: drh 2004-06-12 02:17:15.000
Context
2004-06-12
09:25
(1) Modifications to the user-function interface and (2) Internal changes to automatically created indices. (CVS 1575) (check-in: 5903f53828 user: danielk1977 tags: trunk)
02:17
Bug fix in the unix locking code. (CVS 1574) (check-in: dcad244f58 user: drh tags: trunk)
01:43
Change prototype for busy callbacks to "int xBusy(void *, int);" (CVS 1573) (check-in: 4f1cfca5ca user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  sqlite3OsEnterMutex();

  /* If some thread using this PID has a lock via a different OsFile*
  ** handle that precludes the requested lock, return BUSY.
  */
  if( (id->locktype!=pLock->locktype && 
          (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
   || (locktype==EXCLUSIVE_LOCK && pLock->cnt>1)
  ){
    rc = SQLITE_BUSY;
    goto end_lock;
  }

  /* If a SHARED lock is requested, and some thread using this PID already
  ** has a SHARED or RESERVED lock, then increment reference counts and







<







729
730
731
732
733
734
735

736
737
738
739
740
741
742
  sqlite3OsEnterMutex();

  /* If some thread using this PID has a lock via a different OsFile*
  ** handle that precludes the requested lock, return BUSY.
  */
  if( (id->locktype!=pLock->locktype && 
          (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))

  ){
    rc = SQLITE_BUSY;
    goto end_lock;
  }

  /* If a SHARED lock is requested, and some thread using this PID already
  ** has a SHARED or RESERVED lock, then increment reference counts and
753
754
755
756
757
758
759
760
761

762
763
764
765
766
767
768
769
770
771
772
773
774
775
776









777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794




795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824



825
826
827
828
829
830
831
    id->pOpen->nLock++;
    goto end_lock;
  }

  lock.l_len = 1L;
  lock.l_whence = SEEK_SET;

  /* If control gets to this point, then actually go ahead and make
  ** operating system calls for the specified lock.

  */
  if( locktype==SHARED_LOCK ){
    assert( pLock->cnt==0 );
    assert( pLock->locktype==0 );
  
    /* Temporarily grab a PENDING lock.  This prevents new SHARED locks from
    ** being formed if a PENDING lock is already held.
    */
    lock.l_type = F_RDLCK;
    lock.l_start = PENDING_BYTE;
    s = fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
      goto end_lock;
    }










    /* Now get the read-lock */
    lock.l_start = SHARED_FIRST;
    lock.l_len = SHARED_SIZE;
    s = fcntl(id->h, F_SETLK, &lock);

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      id->locktype = SHARED_LOCK;
      id->pOpen->nLock++;
      pLock->cnt = 1;
    }




  }else{
    /* The request was for a RESERVED, PENDING or EXCLUSIVE lock.  It is
    ** assumed that there is a SHARED or greater lock on the file
    ** already.
    */
    assert( 0!=id->locktype );
    lock.l_type = F_WRLCK;
    switch( locktype ){
      case RESERVED_LOCK:
        lock.l_start = RESERVED_BYTE;
        break;
      case PENDING_LOCK:
        lock.l_start = PENDING_BYTE;
        break;
      case EXCLUSIVE_LOCK:
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        break;
      default:
        assert(0);
    }
    s = fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }
  }
  
  if( rc==SQLITE_OK ){
    id->locktype = locktype;
    pLock->locktype = locktype;



  }

end_lock:
  sqlite3OsLeaveMutex();
  TRACE4("LOCK %d %d %s\n", id->h, locktype, rc==SQLITE_OK ? "ok" : "failed");
  return rc;
}







|
|
>

|
<
|
|
<
<
<







>
>
>
>
>
>
>
>
>


















>
>
>
>

|









<
<
<
















>
>
>







752
753
754
755
756
757
758
759
760
761
762
763

764
765



766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814



815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
    id->pOpen->nLock++;
    goto end_lock;
  }

  lock.l_len = 1L;
  lock.l_whence = SEEK_SET;

  /* A PENDING lock is needed before acquiring a SHARED lock and before
  ** acquiring an EXCLUSIVE lock.  For the SHARED lock, the PENDING will
  ** be released.
  */
  if( locktype==SHARED_LOCK 

      || (locktype==EXCLUSIVE_LOCK && id->locktype<PENDING_LOCK)
  ){



    lock.l_type = F_RDLCK;
    lock.l_start = PENDING_BYTE;
    s = fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
      goto end_lock;
    }
  }


  /* If control gets to this point, then actually go ahead and make
  ** operating system calls for the specified lock.
  */
  if( locktype==SHARED_LOCK ){
    assert( pLock->cnt==0 );
    assert( pLock->locktype==0 );

    /* Now get the read-lock */
    lock.l_start = SHARED_FIRST;
    lock.l_len = SHARED_SIZE;
    s = fcntl(id->h, F_SETLK, &lock);

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      id->locktype = SHARED_LOCK;
      id->pOpen->nLock++;
      pLock->cnt = 1;
    }
  }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
    /* We are trying for an exclusive lock but another thread in this
    ** same process is still holding a shared lock. */
    rc = SQLITE_BUSY;
  }else{
    /* The request was for a RESERVED or EXCLUSIVE lock.  It is
    ** assumed that there is a SHARED or greater lock on the file
    ** already.
    */
    assert( 0!=id->locktype );
    lock.l_type = F_WRLCK;
    switch( locktype ){
      case RESERVED_LOCK:
        lock.l_start = RESERVED_BYTE;
        break;



      case EXCLUSIVE_LOCK:
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        break;
      default:
        assert(0);
    }
    s = fcntl(id->h, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }
  }
  
  if( rc==SQLITE_OK ){
    id->locktype = locktype;
    pLock->locktype = locktype;
  }else if( locktype==EXCLUSIVE_LOCK ){
    id->locktype = PENDING_LOCK;
    pLock->locktype = PENDING_LOCK;
  }

end_lock:
  sqlite3OsLeaveMutex();
  TRACE4("LOCK %d %d %s\n", id->h, locktype, rc==SQLITE_OK ? "ok" : "failed");
  return rc;
}
Changes to src/os_win.c.
416
417
418
419
420
421
422

423
424
425
426
427
428
429
  assert( locktype!=PENDING_LOCK );
  assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );

  /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
  ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
  ** the PENDING_LOCK byte is temporary.
  */

  if( id->locktype==NO_LOCK
   || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
  ){
    int cnt = 3;
    while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
      /* Try 3 times to get the pending lock.  The pending lock might be
      ** held by another reader process who will release it momentarily.







>







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  assert( locktype!=PENDING_LOCK );
  assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );

  /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
  ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
  ** the PENDING_LOCK byte is temporary.
  */
  newLocktype = id->locktype;
  if( id->locktype==NO_LOCK
   || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
  ){
    int cnt = 3;
    while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
      /* Try 3 times to get the pending lock.  The pending lock might be
      ** held by another reader process who will release it momentarily.
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
** the requested locking level, this routine is a no-op.
**
** It is not possible for this routine to fail.
*/
int sqlite3OsUnlock(OsFile *id, int locktype){
  int rc, type;
  assert( locktype<=SHARED_LOCK );
  TRACE4("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
          id->locktype, id->sharedLockByte);
  type = id->locktype;
  if( type>=EXCLUSIVE_LOCK ){
    UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
  }
  if( type>=RESERVED_LOCK ){
    UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);







|







533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
** the requested locking level, this routine is a no-op.
**
** It is not possible for this routine to fail.
*/
int sqlite3OsUnlock(OsFile *id, int locktype){
  int rc, type;
  assert( locktype<=SHARED_LOCK );
  TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
          id->locktype, id->sharedLockByte);
  type = id->locktype;
  if( type>=EXCLUSIVE_LOCK ){
    UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
  }
  if( type>=RESERVED_LOCK ){
    UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
Changes to test/attach2.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.15 2004/06/09 21:01:12 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Ticket #354







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.16 2004/06/12 02:17:15 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Ticket #354
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275


276
277
278
279
280
281
282
283
284
285
286
287
288
289
    INSERT INTO t1 VALUES(1, 2)
  }
} {1 {database is locked}}

lock_status 4.9.1 db {main shared temp reserved file2 shared}
lock_status 4.9.2 db2 {main reserved temp reserved file2 reserved}

set sqlite_os_trace 0
btree_breakpoint
do_test attach2-4.10 {
  # We cannot commit db2 while db is holding a read-lock
  catchsql {COMMIT} db2
} {1 {database is locked}}

lock_status 4.10.1 db {main shared temp reserved file2 shared}
lock_status 4.10.2 db2 {main reserved temp reserved file2 reserved}



do_test attach2-4.11 {
  # db is able to commit.
  catchsql {COMMIT}
} {0 {}}

lock_status 4.11.1 db {main unlocked temp unlocked file2 unlocked}
lock_status 4.11.2 db2 {main reserved temp reserved file2 reserved}

do_test attach2-4.12 {
  # Now we can commit db2
  catchsql {COMMIT} db2
} {0 {}}

lock_status 4.12.1 db {main unlocked temp unlocked file2 unlocked}







<







|

>
>






|







259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    INSERT INTO t1 VALUES(1, 2)
  }
} {1 {database is locked}}

lock_status 4.9.1 db {main shared temp reserved file2 shared}
lock_status 4.9.2 db2 {main reserved temp reserved file2 reserved}


btree_breakpoint
do_test attach2-4.10 {
  # We cannot commit db2 while db is holding a read-lock
  catchsql {COMMIT} db2
} {1 {database is locked}}

lock_status 4.10.1 db {main shared temp reserved file2 shared}
lock_status 4.10.2 db2 {main pending temp reserved file2 reserved}

set sqlite_os_trace 0
btree_breakpoint
do_test attach2-4.11 {
  # db is able to commit.
  catchsql {COMMIT}
} {0 {}}

lock_status 4.11.1 db {main unlocked temp unlocked file2 unlocked}
lock_status 4.11.2 db2 {main pending temp reserved file2 reserved}

do_test attach2-4.12 {
  # Now we can commit db2
  catchsql {COMMIT} db2
} {0 {}}

lock_status 4.12.1 db {main unlocked temp unlocked file2 unlocked}