diff --git a/manifest b/manifest index 743a360b23..788f2e06a1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\s"table_info"\spragma\sreports\sunspecified\scolumn\stypes\sas\s"numeric"\sinstead\nof\s"text".\s\sFix\sfor\sticket\s#174.\s(CVS\s767) -D 2002-10-20T16:00:28 +C Rework\sthe\schanges\sfor\sticket\s#176\s(check-ins\s(760)\sand\s(761))\sto\sbe\nmore\sconsistent\swith\sthe\srest\sof\sthe\ssource\scode.\s(CVS\s768) +D 2002-10-20T18:19:45 F Makefile.in d6c9a85c2a5e696843201d090dcf8bf2f8716f2a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -30,7 +30,7 @@ F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c 764300a0bd8074a2174946c0bf8a550bd833397a F src/main.c ff7c05ef88fa1374e5540ce20173ae8e1836f8a4 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 -F src/os.c c045297aae5a99710222baf939985498c5bb76d4 +F src/os.c ede7346dffdbab40c6de20d2f325981f3f1168fd F src/os.h 3009379b06941e7796a9812d1b6cbc59b26248c8 F src/pager.c 592e5931fdc65e952a6c3e152bc822580856532a F src/pager.h 6991c9c2dc5e4c7f2df4d4ba47d1c6458f763a32 @@ -149,7 +149,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P d5470dfe102ef9b1dac3b15a2f5cc225e3c26129 -R 7ecb20627c80bbfd79b6dbcc45bd92d1 +P 395ab5fac201a37d6eca833ffd6f58ac8a0121a2 +R 839af7b0330753291020e1f24ae79a14 U drh -Z fbad8ba3d35f7e19e8e9a6b0f6544aa0 +Z 224ddb64edfd2ea0e4f95e777cac97ff diff --git a/manifest.uuid b/manifest.uuid index e41c3bde31..8aed6c306d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -395ab5fac201a37d6eca833ffd6f58ac8a0121a2 \ No newline at end of file +f50a177b4239bc7a83563ac9361e830ec04e81fb \ No newline at end of file diff --git a/src/os.c b/src/os.c index ae29b37b6d..42dc89dd6b 100644 --- a/src/os.c +++ b/src/os.c @@ -90,14 +90,14 @@ static int last_page = 0; ** cnt>0 means there are cnt shared locks on the file. ** ** Any attempt to lock or unlock a file first checks the locking -** structure. The fcntl() system call is only invoked to set a +** structure. The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between ** a locked and an unlocked state. */ /* ** An instance of the following structure serves as the key used -** to locate a particular lockInfo structure given its inode. +** to locate a particular lockInfo structure given its inode. */ struct inodeKey { dev_t dev; /* Device number */ @@ -116,7 +116,7 @@ struct lockInfo { int nRef; /* Number of pointers to this structure */ }; -/* +/* ** This hash table maps inodes (in the form of inodeKey structures) into ** pointers to lockInfo structures. */ @@ -236,7 +236,7 @@ int sqliteOsOpenReadWrite( if( id->fd<0 ){ id->fd = open(zFilename, O_RDONLY); if( id->fd<0 ){ - return SQLITE_CANTOPEN; + return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ @@ -328,7 +328,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ HANDLE h; int fileflags; if( delFlag ){ - fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS + fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE; }else{ fileflags = FILE_FLAG_RANDOM_ACCESS; @@ -448,7 +448,7 @@ int sqliteOsTempFileName(char *zBuf){ if( !sqliteOsFileExists(zBuf) ) break; } #endif - return SQLITE_OK; + return SQLITE_OK; } /* @@ -492,7 +492,7 @@ int sqliteOsRead(OsFile *id, void *pBuf, int amt){ if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ got = 0; } - if( (int)got==amt ){ + if( got==(DWORD)amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; @@ -605,6 +605,23 @@ int sqliteOsFileSize(OsFile *id, int *pSize){ #endif } +#if OS_WIN +/* +** Return true (non-zero) if we are running under WinNT, Win2K or WinXP. +** Return false (zero) for Win95, Win98, or WinME. +*/ +int isNT(void){ + static osType = 0; /* 0=unknown 1=win95 2=winNT */ + if( osType==0 ){ + OSVERSIONINFO sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + GetVersionEx(&sInfo); + osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; + } + return osType==2; +} +#endif + /* ** Windows file locking notes: ** @@ -612,84 +629,36 @@ int sqliteOsFileSize(OsFile *id, int *pSize){ ** 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. +** LockFile() prevents not just writing but also reading by other processes. +** (This is a design error on the part of Windows, but there is nothing +** we can do about that.) So the region used for locking is at the +** end of the file where it is unlikely to ever interfere with an +** actual read attempt. +** +** A database read lock is obtained by locking a single randomly-chosen +** byte out of a specific range of bytes. 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 database write lock is obtained by locking all bytes in the range. ** 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(). +** A lock is obtained on the first byte of the lock range 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 the first +** byte 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(). ** -** Locks must be obtained in an area that does not overlap the "real data area" -** otherwise read/write operations will conflict with lock operations. Locking beyond EOF -** is allowed in windows. -** -** There are a finite number of read locks under windows. That number -** is determined by the following variable: +** The following #defines specify the range of bytes used for locking. +** N_LOCKBYTE is the number of bytes available for doing the locking. +** The first byte used to hold the lock while the lock is changing does +** not count toward this number. FIRST_LOCKBYTE is the address of +** the first byte in the range of bytes used for locking. */ - -#define MX_LOCKBYTE 0xFFF0 - -#if OS_WIN - -// get the platform id to decide how to calculate the lock offset - -int mkPlatformId(void){ - - static long init=0; - static long lock=0; - - static int pid=VER_PLATFORM_WIN32_WINDOWS; - OSVERSIONINFOA info; - - while (!init) { - if (InterlockedIncrement(&lock)==1) - { - info.dwOSVersionInfoSize=sizeof(info); - if (GetVersionEx(&info)) pid=info.dwPlatformId; - init=1; - } - else - Sleep(1); - } - return pid; -} - -// locks and unlocks beyond eof. uses platformid to move the lock as far as possible. -int mklock(HANDLE h, WORD base, WORD size) -{ - if (mkPlatformId()==VER_PLATFORM_WIN32_WINDOWS) - return LockFile(h,0xFFFF0000+base,0,size,0); - else - return LockFile(h,base,0xFFFFFFFF,size,0); -} - -int mkunlock(HANDLE h, WORD base, WORD size) -{ - if (mkPlatformId()==VER_PLATFORM_WIN32_WINDOWS) - return UnlockFile(h,0xFFFF0000+base,0,size,0); - else - return UnlockFile(h,base,0xFFFFFFFF,size,0); -} - -//obtain the sync lock on a handle - -void synclock(HANDLE h){ - while (!mklock(h,0,1)) Sleep(1); -} - -void syncunlock(HANDLE h){ - mkunlock(h,0,1); -} - -#endif +#define N_LOCKBYTE 10239 +#define FIRST_LOCKBYTE (0xffffffff - N_LOCKBYTE) /* ** Change the status of the lock on the file "id" to be a readlock. @@ -698,7 +667,6 @@ void syncunlock(HANDLE h){ ** ** Return SQLITE_OK on success and SQLITE_BUSY on failure. */ - int sqliteOsReadLock(OsFile *id){ #if OS_UNIX int rc; @@ -732,14 +700,18 @@ int sqliteOsReadLock(OsFile *id){ if( id->locked>0 ){ rc = SQLITE_OK; }else{ - int lk = (sqliteRandomInteger() & 0x7ffffff)%MX_LOCKBYTE + 1; + int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1; int res; - - synclock(id->h); - if (id->locked<0) mkunlock(id->h,1,MX_LOCKBYTE); // release write lock if we have it - res=mklock(id->h,lk,1); - syncunlock(id->h); - + int cnt = 100; + int page = isNT() ? 0xffffffff : 0; + while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, page, 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); + } if( res ){ id->locked = lk; rc = SQLITE_OK; @@ -783,13 +755,21 @@ int sqliteOsWriteLock(OsFile *id){ rc = SQLITE_OK; }else{ int res; - - synclock(id->h); - if (id->locked>0) mkunlock(id->h,id->locked,1); // release read lock - res=mklock(id->h,1,MX_LOCKBYTE); - syncunlock(id->h); - - if(res){ + int cnt = 100; + int page = isNT() ? 0xffffffff : 0; + while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, page, 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); + }else{ + res = 0; + } + UnlockFile(id->h, FIRST_LOCKBYTE, page, 1, 0); + } + if( res ){ id->locked = -1; rc = SQLITE_OK; }else{ @@ -831,13 +811,19 @@ int sqliteOsUnlock(OsFile *id){ #endif #if OS_WIN int rc; - if(id->locked<0 ) { - mkunlock(id->h,1,MX_LOCKBYTE); - }else if (id->locked>0) { - mkunlock(id->h,id->locked,1); + 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); + rc = SQLITE_OK; + id->locked = 0; + }else{ + UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, page, 1, 0); + rc = SQLITE_OK; + id->locked = 0; } - id->locked = 0; - return SQLITE_OK; + return rc; #endif }