📄 os_unix.c
字号:
static int _AFPFSSetLock( const char *path, unixFile *pFile, unsigned long long offset, unsigned long long length, int setLockFlag){ struct ByteRangeLockPB2 pb; int err; pb.unLockFlag = setLockFlag ? 0 : 1; pb.startEndFlag = 0; pb.offset = offset; pb.length = length; pb.fd = pFile->h; OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n", (setLockFlag?"ON":"OFF"), pFile->h, offset, length); err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); if ( err==-1 ) { int rc; int tErrno = errno; OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, tErrno, strerror(tErrno)); rc = sqliteErrorFromPosixError(tErrno, setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK); /* error */ if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } return rc; } else { return SQLITE_OK; }}/* AFP-style reserved lock checking following the behavior of ** unixCheckReservedLock, see the unixCheckReservedLock function comments */static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; /* 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 ){ /* lock the RESERVED byte */ int lrc = _AFPFSSetLock(context->filePath, pFile, RESERVED_BYTE, 1,1); if( SQLITE_OK==lrc ){ /* if we succeeded in taking the reserved lock, unlock it to restore ** the original state */ lrc = _AFPFSSetLock(context->filePath, pFile, RESERVED_BYTE, 1, 0); } else { /* if we failed to get the lock then someone else must have it */ reserved = 1; } if( IS_LOCK_ERROR(lrc) ){ rc=lrc; } } OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved); *pResOut = reserved; return rc;}/* AFP-style locking following the behavior of unixLock, see the unixLock ** function comments for details of lock management. */static int afpLock(sqlite3_file *id, int locktype){ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; assert( pFile ); OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h, locktypeName(locktype), locktypeName(pFile->locktype), getpid()); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as ** enterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, locktypeName(locktype)); return SQLITE_OK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* This mutex is needed because pFile->pLock is shared across threads */ enterMutex(); /* Make sure the current thread owns the pFile. */ rc = transferOwnership(pFile); if( rc!=SQLITE_OK ){ leaveMutex(); return rc; } /* 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 && pFile->locktype<PENDING_LOCK) ){ int failed; failed = _AFPFSSetLock(context->filePath, pFile, PENDING_BYTE, 1, 1); if (failed) { rc = failed; goto afp_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 ){ int lk, lrc1, lrc2, lrc1Errno; /* Now get the read-lock SHARED_LOCK */ /* note that the quality of the randomness doesn't matter that much */ lk = random(); context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); lrc1 = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST+context->sharedLockByte, 1, 1); if( IS_LOCK_ERROR(lrc1) ){ lrc1Errno = pFile->lastErrno; } /* Drop the temporary PENDING lock */ lrc2 = _AFPFSSetLock(context->filePath, pFile, PENDING_BYTE, 1, 0); if( IS_LOCK_ERROR(lrc1) ) { pFile->lastErrno = lrc1Errno; rc = lrc1; goto afp_end_lock; } else if( IS_LOCK_ERROR(lrc2) ){ rc = lrc2; goto afp_end_lock; } else if( lrc1 != SQLITE_OK ) { rc = lrc1; } else { pFile->locktype = SHARED_LOCK; } }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. */ int failed = 0; assert( 0!=pFile->locktype ); if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) { /* Acquire a RESERVED lock */ failed = _AFPFSSetLock(context->filePath, pFile, RESERVED_BYTE, 1,1); } if (!failed && locktype == EXCLUSIVE_LOCK) { /* Acquire an EXCLUSIVE lock */ /* Remove the shared lock before trying the range. we'll need to ** reestablish the shared lock if we can't get the afpUnlock */ if (!(failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST + context->sharedLockByte, 1, 0))) { /* now attemmpt to get the exclusive lock range */ failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST, SHARED_SIZE, 1); if (failed && (failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST + context->sharedLockByte, 1, 1))) { rc = failed; } } else { rc = failed; } } if( failed ){ rc = failed; } } if( rc==SQLITE_OK ){ pFile->locktype = locktype; }else if( locktype==EXCLUSIVE_LOCK ){ pFile->locktype = PENDING_LOCK; } afp_end_lock: leaveMutex(); OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); 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.*/static int afpUnlock(sqlite3_file *id, int locktype) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; assert( pFile ); OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype, pFile->locktype, getpid()); assert( locktype<=SHARED_LOCK ); if( pFile->locktype<=locktype ){ return SQLITE_OK; } if( CHECK_THREADID(pFile) ){ return SQLITE_MISUSE; } enterMutex(); int failed = SQLITE_OK; if( pFile->locktype>SHARED_LOCK ){ if( locktype==SHARED_LOCK ){ /* unlock the exclusive range - then re-establish the shared lock */ if (pFile->locktype==EXCLUSIVE_LOCK) { failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST, SHARED_SIZE, 0); if (!failed) { /* successfully removed the exclusive lock */ if ((failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST+ context->sharedLockByte, 1, 1))) { /* failed to re-establish our shared lock */ rc = failed; } } else { rc = failed; } } } if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) { if ((failed = _AFPFSSetLock(context->filePath, pFile, PENDING_BYTE, 1, 0))){ /* failed to release the pending lock */ rc = failed; } } if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) { if ((failed = _AFPFSSetLock(context->filePath, pFile, RESERVED_BYTE, 1, 0))) { /* failed to release the reserved lock */ rc = failed; } } } if( locktype==NO_LOCK ){ int failed = _AFPFSSetLock(context->filePath, pFile, SHARED_FIRST + context->sharedLockByte, 1, 0); if (failed) { rc = failed; } } if (rc == SQLITE_OK) pFile->locktype = locktype; leaveMutex(); return rc;}/*** Close a file & cleanup AFP specific locking context */static int afpClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; afpUnlock(id, NO_LOCK); sqlite3_free(pFile->lockingContext); } return closeUnixFile(id);}#pragma mark flock() style locking/*** The flockLockingContext is not used*/typedef void flockLockingContext;/* flock-style reserved lock checking following the behavior of ** unixCheckReservedLock, see the unixCheckReservedLock function comments */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); *pResOut = reserved; return rc;}static int flockLock(sqlite3_file *id, int locktype) { int rc = SQLITE_OK; int lrc; 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(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc;}static int flockUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; 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; } /* shared can just be set because we always have an exclusive */ if (locktype==SHARED_LOCK) { pFile->locktype = locktype; return SQLITE_OK; } /* no, really, unlock. */ int rc = flock(pFile->h, LOCK_UN); if (rc) { int r, tErrno = errno; r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(r) ){ pFile->lastErrno = tErrno; } return r; } else { pFile->locktype = NO_LOCK; return SQLITE_OK; }}/*** Close a file.*/static int flockClose(sqlite3_file *id) { if( id ){ flockUnlock(id, NO_LOCK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -