1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Modify the windows locking code so that it works correctly for a database

being shared between Win95/98/ME and WinNT/2K/XP systems.  Ticket #310. (CVS 988)

FossilOrigin-Name: 8c402db7e0745622d9950e5ca5d4d8e933da436c
This commit is contained in:
drh
2003-05-29 17:43:08 +00:00
parent 124e74e685
commit 9ac717d7f6
5 changed files with 70 additions and 32 deletions

View File

@@ -992,10 +992,18 @@ int sqliteOsFileSize(OsFile *id, off_t *pSize){
/*
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
** Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
int isNT(void){
static osType = 0; /* 0=unknown 1=win95 2=winNT */
if( osType==0 ){
int tmpOsType;
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
@@ -1006,10 +1014,10 @@ int isNT(void){
#endif
/*
** Windows file locking notes: [the same/equivalent applies to MacOS]
** Windows file locking notes: [similar issues apply to MacOS]
**
** We cannot use LockFileEx() or UnlockFileEx() because those functions
** are not available under Win95/98/ME. So we use only LockFile() and
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available. So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
@@ -1034,6 +1042,14 @@ int isNT(void){
** another process jumping into the middle and messing us up. The same
** argument applies to sqliteOsWriteLock().
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks. When reader writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** Note: On MacOS we use the resource fork for locking.
**
** The following #defines specify the range of bytes used for locking.
@@ -1096,14 +1112,22 @@ int sqliteOsReadLock(OsFile *id){
int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1;
int res;
int cnt = 100;
int page = isNT() ? 0xffffffff : 0;
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, page, 1, 0))==0 ){
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
Sleep(1);
}
if( res ){
UnlockFile(id->h, FIRST_LOCKBYTE+1, page, N_LOCKBYTE, 0);
res = LockFile(id->h, FIRST_LOCKBYTE+lk, page, 1, 0);
UnlockFile(id->h, FIRST_LOCKBYTE, page, 1, 0);
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = FIRST_LOCKBYTE+1;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY,
0, N_LOCKBYTE, 0, &ovlp);
}else{
res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0);
}
UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
}
if( res ){
id->locked = lk;
@@ -1191,18 +1215,23 @@ int sqliteOsWriteLock(OsFile *id){
}else{
int res;
int cnt = 100;
int page = isNT() ? 0xffffffff : 0;
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, page, 1, 0))==0 ){
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
Sleep(1);
}
if( res ){
if( id->locked==0
|| UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, page, 1, 0) ){
res = LockFile(id->h, FIRST_LOCKBYTE+1, page, N_LOCKBYTE, 0);
if( id->locked>0 ){
if( isNT() ){
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
}else{
res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0);
}
}
if( res ){
res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
}else{
res = 0;
}
UnlockFile(id->h, FIRST_LOCKBYTE, page, 1, 0);
UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
}
if( res ){
id->locked = -1;
@@ -1291,15 +1320,14 @@ int sqliteOsUnlock(OsFile *id){
#endif
#if OS_WIN
int rc;
int page = isNT() ? 0xffffffff : 0;
if( id->locked==0 ){
rc = SQLITE_OK;
}else if( id->locked<0 ){
UnlockFile(id->h, FIRST_LOCKBYTE+1, page, N_LOCKBYTE, 0);
}else if( isNT() || id->locked<0 ){
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
rc = SQLITE_OK;
id->locked = 0;
}else{
UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, page, 1, 0);
UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0);
rc = SQLITE_OK;
id->locked = 0;
}