📄 os_unix.c
字号:
int *aNew; struct unixOpenCnt *pOpen = pFile->pOpen; aNew = sqlite3_realloc(pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; pOpen->aPending[pOpen->nPending] = pFile->h; pOpen->nPending++; pFile->h = -1; } } releaseLockInfo(pFile->pLock); releaseOpenCnt(pFile->pOpen); rc = closeUnixFile(id); unixLeaveMutex(); } return rc;}/************** End of the posix advisory lock implementation ***********************************************************************************************//************************************************************************************************************ No-op Locking ************************************** Of the various locking implementations available, this is by far the** simplest: locking is ignored. No attempt is made to lock the database** file for reading or writing.**** This locking mode is appropriate for use on read-only databases** (ex: databases that are burned into CD-ROM, for example.) It can** also be used if the application employs some external mechanism to** prevent simultaneous access of the same database by two or more** database connections. But there is a serious risk of database** corruption if this locking mode is used in situations where multiple** database connections are accessing the same database file at the same** time and one or more of those connections are writing.*/static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){ UNUSED_PARAMETER(NotUsed); *pResOut = 0; return SQLITE_OK;}static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return SQLITE_OK;}static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return SQLITE_OK;}/*** Close the file.*/static int nolockClose(sqlite3_file *id) { return closeUnixFile(id);}/******************* End of the no-op lock implementation ***************************************************************************************************//******************************************************************************************************* Begin dot-file Locking ********************************** The dotfile locking implementation uses the existing of separate lock** files in order to control access to the database. This works on just** about every filesystem imaginable. But there are serious downsides:**** (1) There is zero concurrency. A single reader blocks all other** connections from reading or writing the database.**** (2) An application crash or power loss can leave stale lock files** sitting around that need to be cleared manually.**** Nevertheless, a dotlock is an appropriate locking mode for use if no** other locking strategy is available.**** Dotfile locking works by creating a file in the same directory as the** database and with the same name but with a ".lock" extension added.** The existance of a lock file implies an EXCLUSIVE lock. All other lock** types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.*//*** The file suffix added to the data base filename in order to create the** lock file.*/#define DOTLOCK_SUFFIX ".lock"/*** This routine checks if there is a RESERVED lock held on the specified** file by this or any other process. If such a lock is held, set *pResOut** to a non-zero value otherwise *pResOut is set to zero. The return value** is set to SQLITE_OK unless an I/O error occurs during lock checking.**** In dotfile locking, either a lock exists or it does not. So in this** variation of CheckReservedLock(), *pResOut is set to true if any lock** is held on the file and false if the file is unlocked.*/static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); /* Check if a thread in this process holds such a lock */ if( pFile->locktype>SHARED_LOCK ){ /* Either this connection or some other connection in the same process ** holds a lock on the file. No need to check further. */ reserved = 1; }else{ /* The lock is held if and only if the lockfile exists */ const char *zLockFile = (const char*)pFile->lockingContext; reserved = access(zLockFile, 0)==0; } OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved); *pResOut = reserved; return rc;}/*** Lock the file with the lock specified by parameter locktype - one** of the following:**** (1) SHARED_LOCK** (2) RESERVED_LOCK** (3) PENDING_LOCK** (4) EXCLUSIVE_LOCK**** Sometimes when requesting one lock state, additional lock states** are inserted in between. The locking might fail on one of the later** transitions leaving the lock state different from what it started but** still short of its goal. The following chart shows the allowed** transitions and the inserted intermediate states:**** UNLOCKED -> SHARED** SHARED -> RESERVED** SHARED -> (PENDING) -> EXCLUSIVE** RESERVED -> (PENDING) -> EXCLUSIVE** PENDING -> EXCLUSIVE**** This routine will only increase a lock. Use the sqlite3OsUnlock()** routine to lower a locking level.**** With dotfile locking, we really only support state (4): EXCLUSIVE.** But we track the other locking levels internally.*/static int dotlockLock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; int fd; char *zLockFile = (char *)pFile->lockingContext; int rc = SQLITE_OK; /* If we have any lock, then the lock file already exists. All we have ** to do is adjust our internal record of the lock level. */ if( pFile->locktype > NO_LOCK ){ pFile->locktype = locktype;#if !OS_VXWORKS /* Always update the timestamp on the old file */ utimes(zLockFile, NULL);#endif return SQLITE_OK; } /* grab an exclusive lock */ fd = open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600); if( fd<0 ){ /* failed to open/create the file, someone else may have stolen the lock */ int tErrno = errno; if( EEXIST == tErrno ){ rc = SQLITE_BUSY; } else { rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } return rc; } if( close(fd) ){ pFile->lastErrno = errno; rc = SQLITE_IOERR_CLOSE; } /* got it, set the type and return ok */ pFile->locktype = locktype; return rc;}/*** Lower the locking level on file descriptor pFile to locktype. locktype** must be either NO_LOCK or SHARED_LOCK.**** If the locking level of the file descriptor is already at or below** the requested locking level, this routine is a no-op.**** When the locking level reaches NO_LOCK, delete the lock file.*/static int dotlockUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; char *zLockFile = (char *)pFile->lockingContext; assert( pFile ); OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype, pFile->locktype, getpid()); assert( locktype<=SHARED_LOCK ); /* no-op if possible */ if( pFile->locktype==locktype ){ return SQLITE_OK; } /* To downgrade to shared, simply update our internal notion of the ** lock state. No need to mess with the file on disk. */ if( locktype==SHARED_LOCK ){ pFile->locktype = SHARED_LOCK; return SQLITE_OK; } /* To fully unlock the database, delete the lock file */ assert( locktype==NO_LOCK ); if( unlink(zLockFile) ){ int rc, tErrno = errno; if( ENOENT != tErrno ){ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); } if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } return rc; } pFile->locktype = NO_LOCK; return SQLITE_OK;}/*** Close a file. Make sure the lock has been released before closing.*/static int dotlockClose(sqlite3_file *id) { int rc; if( id ){ unixFile *pFile = (unixFile*)id; dotlockUnlock(id, NO_LOCK); sqlite3_free(pFile->lockingContext); } rc = closeUnixFile(id); return rc;}/****************** End of the dot-file lock implementation *************************************************************************************************//******************************************************************************************************** Begin flock Locking ************************************ Use the flock() system call to do file locking.**** flock() locking is like dot-file locking in that the various** fine-grain locking levels supported by SQLite are collapsed into** a single exclusive lock. In other words, SHARED, RESERVED, and** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite** still works when you do this, but concurrency is reduced since** only a single process can be reading the database at a time.**** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if** compiling for VXWORKS.*/#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS/*** This routine checks if there is a RESERVED lock held on the specified** file by this or any other process. If such a lock is held, set *pResOut** to a non-zero value otherwise *pResOut is set to zero. The return value** is set to SQLITE_OK unless an I/O error occurs during lock checking.*/static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); /* Check if a thread in this process holds such a lock */ if( pFile->locktype>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ int lrc = flock(pFile->h, LOCK_EX | LOCK_NB); if( !lrc ){ /* got the lock, unlock it */ lrc = flock(pFile->h, LOCK_UN); if ( lrc ) { int tErrno = errno; /* unlock failed with an error */ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(lrc) ){ pFile->lastErrno = tErrno; rc = lrc; } } } else { int tErrno = errno; reserved = 1; /* someone else might have it reserved */ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(lrc) ){ pFile->lastErrno = tErrno; rc = lrc; } } } OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved);#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ rc = SQLITE_OK; reserved=1; }#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ *pResOut = reserved; return rc;}/*** Lock the file with the lock specified by parameter locktype - one** of the following:**** (1) SHARED_LOCK** (2) RESERVED_LOCK** (3) PENDING_LOCK** (4) EXCLUSIVE_LOCK**** Sometimes when requesting one lock state, additional lock states** are inserted in between. The locking might fail on one of the later** transitions leaving the lock state different from what it started but** still short of its goal. The following chart shows the allowed** transitions and the inserted intermediate states:**** UNLOCKED -> SHARED** SHARED -> RESERVED** SHARED -> (PENDING) -> EXCLUSIVE** RESERVED -> (PENDING) -> EXCLUSIVE** PENDING -> EXCLUSIVE**** flock() only really support EXCLUSIVE locks. We track intermediate** lock states in the sqlite3_file structure, but all locks SHARED or** above are really EXCLUSIVE locks and exclude all other processes from** access the file.**** This routine will only increase a lock. Use the sqlite3OsUnlock()** routine to lower a locking level.*/static int flockLock(sqlite3_file *id, int locktype) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( pFile ); /* if we already have a lock, it is exclusive. ** Just adjust level and punt on outta here. */ if (pFile->locktype > NO_LOCK) { pFile->locktype = locktype; return SQLITE_OK; } /* grab an exclusive lock */ if (flock(pFile->h, LOCK_EX | LOCK_NB)) { int tErrno = errno; /* didn't get, must be busy */ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } else { /* got it, set the type and return ok */ pFile->locktype = locktype; } OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -