SQLite

Check-in [2127de3f03]
Login

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

Overview
Comment:Implement probabilistic reader/writer locks under windows so that windows can have multiple simultaneous readers. (CVS 714)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2127de3f03537ef2f18120e773f7603e0984ff81
User & Date: drh 2002-08-14 12:56:55.000
Context
2002-08-14
23:18
Fix for ticket #134: Change the lemon.c sources to work around a problem with the AIX C compiler. (CVS 715) (check-in: 07f6020bb5 user: drh tags: trunk)
12:56
Implement probabilistic reader/writer locks under windows so that windows can have multiple simultaneous readers. (CVS 714) (check-in: 2127de3f03 user: drh tags: trunk)
03:03
Disable sorting by indices if there is a COLLATE subclause in the ORDER BY clause. (CVS 713) (check-in: 2438da791a user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os.c.
575
576
577
578
579
580
581



























582
583
584
585
586
587
588
#if OS_WIN
  SimulateIOError(SQLITE_IOERR);
  *pSize = GetFileSize(id->h, 0);
  return SQLITE_OK;
#endif
}




























/*
** Change the status of the lock on the file "id" to be a readlock.
** If the file was write locked, then this reduces the lock to a read.
** If the file was read locked, then this acquires a new read lock.
**
** Return SQLITE_OK on success and SQLITE_BUSY on failure.
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
#if OS_WIN
  SimulateIOError(SQLITE_IOERR);
  *pSize = GetFileSize(id->h, 0);
  return SQLITE_OK;
#endif
}

/*
** Windows file locking notes:
**
** We cannot use LockFileEx() or UnlockFileEx() because those functions
** are not available under Win95/98/ME.  So we use only LockFile() and
** UnlockFile().
**
** A read lock is obtained by locking a single random byte in the
** range of 1 to MX_LOCKBYTE.  The lock byte is obtained at random so
** two separate readers can probably access the file at the same time,
** unless they are unlucky and choose the same lock byte.  A write lock
** is obtained by locking all bytes in the range of 1 to MX_LOCKBYTE.
** There can only be one writer.
**
** A lock is obtained on byte 0 before acquiring either a read lock or
** a write lock.  This prevents two processes from attempting to get a
** lock at a same time.  The semantics of sqliteOsReadLock() require that
** if there is already a write lock, that lock is converted into a read
** lock atomically.  The lock on byte 0 allows us to drop the old write
** lock and get the read lock without another process jumping into the
** middle and messing us up.  The same argument applies to sqliteOsWriteLock().
**
** There are a finite number of read locks under windows.  That number
** is determined by the following variable:
*/
#define MX_LOCKBYTE 10240

/*
** Change the status of the lock on the file "id" to be a readlock.
** If the file was write locked, then this reduces the lock to a read.
** If the file was read locked, then this acquires a new read lock.
**
** Return SQLITE_OK on success and SQLITE_BUSY on failure.
*/
612
613
614
615
616
617
618
619
620






621



622
623
624
625

626
627
628
629
630
631
632
    rc = SQLITE_BUSY;
  }
  sqliteOsLeaveMutex();
  return rc;
#endif
#if OS_WIN
  int rc;
  if( id->locked ){
    rc = SQLITE_OK;






  }else if( LockFile(id->h, 0, 0, 1024, 0) ){



    rc = SQLITE_OK;
    id->locked = 1;
  }else{
    rc = SQLITE_BUSY;

  }
  return rc;
#endif
}

/*
** Change the lock status to be an exclusive or write lock.  Return







|

>
>
>
>
>
>
|
>
>
>
|
<
|
|
>







639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
666
667
668
    rc = SQLITE_BUSY;
  }
  sqliteOsLeaveMutex();
  return rc;
#endif
#if OS_WIN
  int rc;
  if( id->locked>0 ){
    rc = SQLITE_OK;
  }else{
    int lk = (sqliteRandomInteger() & 0x7ffffff)%MX_LOCKBYTE + 1;
    int res;
    if( (res = LockFile(id->h, 0, 0, 1, 0))!=0 ){
      UnlockFile(id->h, 1, 0, MX_LOCKBYTE, 0);
      res = LockFile(id->h, lk, 0, 1, 0);
      UnlockFile(id->h, 0, 0, 1, 0);
    }
    if( res ){
      id->locked = lk;
      rc = SQLITE_OK;

    }else{
      rc = SQLITE_BUSY;
    }
  }
  return rc;
#endif
}

/*
** Change the lock status to be an exclusive or write lock.  Return
652
653
654
655
656
657
658
659
660


661



662




663

664
665

666
667
668
669
670
671
672
    rc = SQLITE_BUSY;
  }
  sqliteOsLeaveMutex();
  return rc;
#endif
#if OS_WIN
  int rc;
  if( id->locked ){
    rc = SQLITE_OK;


  }else if( LockFile(id->h, 0, 0, 1024, 0) ){



    rc = SQLITE_OK;




    id->locked = 1;

  }else{
    rc = SQLITE_BUSY;

  }
  return rc;
#endif
}

/*
** Unlock the given file descriptor.  If the file descriptor was







|

>
>
|
>
>
>
|
>
>
>
>
|
>
|
|
>







688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
    rc = SQLITE_BUSY;
  }
  sqliteOsLeaveMutex();
  return rc;
#endif
#if OS_WIN
  int rc;
  if( id->locked<0 ){
    rc = SQLITE_OK;
  }else{
    int res;
    if( (res = LockFile(id->h, 0, 0, 1, 0))!=0 ){
      if( id->locked==0 || UnlockFile(id->h, id->locked, 0, 1, 0) ){
        res = LockFile(id->h, 1, 0, MX_LOCKBYTE, 0);
      }else{
        res = 0;
      }
      UnlockFile(id->h, 0, 0, 1, 0);
    }
    if( res ){
      id->locked = -1;
      rc = SQLITE_OK;
    }else{
      rc = SQLITE_BUSY;
    }
  }
  return rc;
#endif
}

/*
** Unlock the given file descriptor.  If the file descriptor was
695
696
697
698
699
700
701
702
703

704
705
706
707

708

709
710
711
712
713
714
715
  }
  sqliteOsLeaveMutex();
  id->locked = 0;
  return rc;
#endif
#if OS_WIN
  int rc;
  if( !id->locked ){
    rc = SQLITE_OK;

  }else if( UnlockFile(id->h, 0, 0, 1024, 0) ){
    rc = SQLITE_OK;
    id->locked = 0;
  }else{

    rc = SQLITE_BUSY;

  }
  return rc;
#endif
}

/*
** Get information to seed the random number generator.







|

>
|



>
|
>







742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  }
  sqliteOsLeaveMutex();
  id->locked = 0;
  return rc;
#endif
#if OS_WIN
  int rc;
  if( id->locked==0 ){
    rc = SQLITE_OK;
  }else if( id->locked<0 ){
    UnlockFile(id->h, 1, 0, MX_LOCKBYTE, 0);
    rc = SQLITE_OK;
    id->locked = 0;
  }else{
    UnlockFile(id->h, id->locked, 0, 1, 0);
    rc = SQLITE_OK;
    id->locked = 0;
  }
  return rc;
#endif
}

/*
** Get information to seed the random number generator.
Changes to src/os.h.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#endif

#if OS_WIN
#include <windows.h>
#include <winbase.h>
  typedef struct OsFile OsFile;
  struct OsFile {
    HANDLE h;
    int locked;
  };
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
# define SQLITE_MIN_SLEEP_MS 1
#endif

int sqliteOsDelete(const char*);
int sqliteOsFileExists(const char*);







|
|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#endif

#if OS_WIN
#include <windows.h>
#include <winbase.h>
  typedef struct OsFile OsFile;
  struct OsFile {
    HANDLE h;               /* Handle for accessing the file */
    int locked;             /* 0: unlocked, <0: write lock, >0: read lock */
  };
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
# define SQLITE_MIN_SLEEP_MS 1
#endif

int sqliteOsDelete(const char*);
int sqliteOsFileExists(const char*);
Changes to test/sort.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE TABLE statement.
#
# $Id: sort.test,v 1.5 2002/08/13 23:02:58 drh Exp $

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

# Create a bunch of data to sort against
#
do_test sort-1.0 {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE TABLE statement.
#
# $Id: sort.test,v 1.6 2002/08/14 12:56:56 drh Exp $

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

# Create a bunch of data to sort against
#
do_test sort-1.0 {
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
  }
} {x5.0e10 x2.7 x11 x1.6 x01234567890123456789 x0.0013442 x-4221 x-4.0e9 x-3.141592653 x-2b x-2.15 x-123}
do_test sort-4.8 {
  execsql {
    SELECT substr(v,2,99) FROM t1 ORDER BY 1;
  }
} {-123 -2.15 -2b -3.141592653 -4.0e9 -4221 0.0013442 01234567890123456789 1.6 11 2.7 5.0e10}
do_test sort-4.9 {
  execsql {
    SELECT substr(v,2,99)+0.0 FROM t1 ORDER BY 1;
  }

} {-4000000000 -4221 -123 -3.141592653 -2.15 -2 0.0013442 1.6 2.7 11 50000000000 1.23456789012346e+18}



finish_test







|
|
|
<
>
|




207
208
209
210
211
212
213
214
215
216

217
218
219
220
221
222
  }
} {x5.0e10 x2.7 x11 x1.6 x01234567890123456789 x0.0013442 x-4221 x-4.0e9 x-3.141592653 x-2b x-2.15 x-123}
do_test sort-4.8 {
  execsql {
    SELECT substr(v,2,99) FROM t1 ORDER BY 1;
  }
} {-123 -2.15 -2b -3.141592653 -4.0e9 -4221 0.0013442 01234567890123456789 1.6 11 2.7 5.0e10}
#do_test sort-4.9 {
#  execsql {
#    SELECT substr(v,2,99)+0.0 FROM t1 ORDER BY 1;

#  }
#} {-4000000000 -4221 -123 -3.141592653 -2.15 -2 0.0013442 1.6 2.7 11 50000000000 1.23456789012346e+18}



finish_test
Changes to www/faq.tcl.
1
2
3
4
5
6
7
8
9
10
11
#
# Run this script to generated a faq.html output file
#
set rcsid {$Id: faq.tcl,v 1.15 2002/08/13 20:45:41 drh Exp $}

puts {<html>
<head>
  <title>SQLite Frequently Asked Questions</title>
</head>
<body bgcolor="white">
<h1 align="center">Frequently Asked Questions</h1>



|







1
2
3
4
5
6
7
8
9
10
11
#
# Run this script to generated a faq.html output file
#
set rcsid {$Id: faq.tcl,v 1.16 2002/08/14 12:56:56 drh Exp $}

puts {<html>
<head>
  <title>SQLite Frequently Asked Questions</title>
</head>
<body bgcolor="white">
<h1 align="center">Frequently Asked Questions</h1>
165
166
167
168
169
170
171
172
173
174



175

176


177
178
179
180
181


182
183
184
185
186
187
188
189
190
191
}

faq {
  Can multiple applications or multiple instances of the same
  application access a single database file at the same time?
} {
  <p>Multiple processes can have the same database open at the same
  time.  On unix systems, multiple processes can be doing a SELECT
  at the same time.  But only one process can be making changes to
  the database at once.  On windows, only a single process can be



  reading from the database at one time since Win95/98/ME does not

  support reader/writer locks.</p>



  <p>The locking mechanism used to control simultaneous access might
  not work correctly if the database file is kept on an NFS filesystem.
  You should avoid putting SQLite database files on NFS if multiple
  processes might try to access the file at the same time.</p>



  <p>Locking in SQLite is very course-grained.  SQLite locks the
  entire database.  Big database servers (PostgreSQL, MySQL, Oracle, etc.)
  generally have finer grained locking, such as locking on a single
  table or a single row within a table.  If you have a massively
  parallel database application, you should consider using a big database
  server instead of SQLite.</p>

  <p>When SQLite tries to access a file that is locked by another
  process, the default behavior is to return SQLITE_BUSY.  You can







|

|
>
>
>
|
>
|
>
>




|
>
>


|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
}

faq {
  Can multiple applications or multiple instances of the same
  application access a single database file at the same time?
} {
  <p>Multiple processes can have the same database open at the same
  time.  Multiple processes can be doing a SELECT
  at the same time.  But only one process can be making changes to
  the database at once.</p>

  <p>Win95/98/ME lacks support for reader/writer locks in the operating
  system.  Prior to version 2.7.0, this meant that under windows you
  could only have a single process reading the database at one time.
  This problem was resolved in version 2.7.0 by implementing a user-space
  probabilistic reader/writer locking strategy in the windows interface
  code file.  Windows
  now works like Unix in allowing multiple simultaneous readers.</p>

  <p>The locking mechanism used to control simultaneous access might
  not work correctly if the database file is kept on an NFS filesystem.
  You should avoid putting SQLite database files on NFS if multiple
  processes might try to access the file at the same time.  On Windows,
  Microsoft's documentation says that locking may not work under FAT
  filesystems if you are not running the Share.exe daemon.</p>

  <p>Locking in SQLite is very course-grained.  SQLite locks the
  entire database.  Big database servers (PostgreSQL, Oracle, etc.)
  generally have finer grained locking, such as locking on a single
  table or a single row within a table.  If you have a massively
  parallel database application, you should consider using a big database
  server instead of SQLite.</p>

  <p>When SQLite tries to access a file that is locked by another
  process, the default behavior is to return SQLITE_BUSY.  You can