📄 os_unix.c
字号:
}else{ pOpen->aPending = aNew; pOpen->aPending[pOpen->nPending] = id->h; pOpen->nPending++; } }else{ /* There are no outstanding locks so we can close the file immediately */ close(id->h); } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); sqlite3OsLeaveMutex(); id->isOpen = 0; OSTRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); sqlite3ThreadSafeFree(id); *pId = 0; return SQLITE_OK;}#ifdef SQLITE_ENABLE_LOCKING_STYLE#pragma mark AFP Support/* ** The afpLockingContext structure contains all afp lock specific state */typedef struct afpLockingContext afpLockingContext;struct afpLockingContext { unsigned long long sharedLockByte; char *filePath;};struct ByteRangeLockPB2{ unsigned long long offset; /* offset to first byte to lock */ unsigned long long length; /* nbr of bytes to lock */ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ int fd; /* file desc to assoc this lock with */};#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)/* return 0 on success, 1 on failure. To match the behavior of the normal posix file locking (used in unixLock for example), we should provide 'richer' return codes - specifically to differentiate between 'file busy' and 'file system error' results */static int _AFPFSSetLock(const char *path, int fd, 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 = fd; OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n", (setLockFlag?"ON":"OFF"), fd, offset, length); err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); if ( err==-1 ) { OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno, strerror(errno)); return 1; /* error */ } else { return 0; }}/* ** 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, return ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */static int afpUnixCheckReservedLock(OsFile *id){ int r = 0; unixFile *pFile = (unixFile*)id; assert( pFile ); afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; /* Check if a thread in this process holds such a lock */ if( pFile->locktype>SHARED_LOCK ){ r = 1; } /* Otherwise see if some other process holds it. */ if ( !r ) { /* lock the byte */ int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1); if (failed) { /* if we failed to get the lock then someone else must have it */ r = 1; } else { /* if we succeeded in taking the reserved lock, unlock it to restore ** the original state */ _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0); } } OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); return r;}/* AFP-style locking following the behavior of unixLock, see the unixLock ** function comments for details of lock management. */static int afpUnixLock(OsFile *id, int locktype){ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; int gotPendingLock = 0; 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 ** OsFile, do nothing. Don't use the afp_end_lock: exit path, as ** sqlite3OsEnterMutex() 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 */ sqlite3OsEnterMutex(); /* Make sure the current thread owns the pFile. */ rc = transferOwnership(pFile); if( rc!=SQLITE_OK ){ sqlite3OsLeaveMutex(); 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 = _AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 1); if (failed) { rc = SQLITE_BUSY; 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, failed; int tries = 0; /* Now get the read-lock */ /* note that the quality of the randomness doesn't matter that much */ lk = random(); context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+context->sharedLockByte, 1, 1); /* Drop the temporary PENDING lock */ if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) { rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ goto afp_end_lock; } if( failed ){ rc = SQLITE_BUSY; } 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->h, 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 afpUnixUnlock */ if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + context->sharedLockByte, 1, 0)) { /* now attemmpt to get the exclusive lock range */ failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, SHARED_SIZE, 1); if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + context->sharedLockByte, 1, 1)) { rc = SQLITE_IOERR_RDLOCK; /* this should never happen */ } } else { /* */ rc = SQLITE_IOERR_UNLOCK; /* this should never happen */ } } if( failed && rc == SQLITE_OK){ rc = SQLITE_BUSY; } } if( rc==SQLITE_OK ){ pFile->locktype = locktype; }else if( locktype==EXCLUSIVE_LOCK ){ pFile->locktype = PENDING_LOCK; } afp_end_lock: sqlite3OsLeaveMutex(); 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 afpUnixUnlock(OsFile *id, int locktype) { struct flock lock; 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; } sqlite3OsEnterMutex(); if( pFile->locktype>SHARED_LOCK ){ if( locktype==SHARED_LOCK ){ int failed = 0; /* unlock the exclusive range - then re-establish the shared lock */ if (pFile->locktype==EXCLUSIVE_LOCK) { failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, SHARED_SIZE, 0); if (!failed) { /* successfully removed the exclusive lock */ if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+ context->sharedLockByte, 1, 1)) { /* failed to re-establish our shared lock */ rc = SQLITE_IOERR_RDLOCK; /* This should never happen */ } } else { /* This should never happen - failed to unlock the exclusive range */ rc = SQLITE_IOERR_UNLOCK; } } } if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) { if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){ /* failed to release the pending lock */ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ } } if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) { if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) { /* failed to release the reserved lock */ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ } } } if( locktype==NO_LOCK ){ int failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + context->sharedLockByte, 1, 0); if (failed) { rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ } } if (rc == SQLITE_OK) pFile->locktype = locktype; sqlite3OsLeaveMutex(); return rc;}/* ** Close a file & cleanup AFP specific locking context */static int afpUnixClose(OsFile **pId) { unixFile *id = (unixFile*)*pId; if( !id ) return SQLITE_OK; afpUnixUnlock(*pId, NO_LOCK); /* free the AFP locking structure */ if (id->lockingContext != NULL) { if (((afpLockingContext *)id->lockingContext)->filePath != NULL) sqlite3ThreadSafeFree(((afpLockingContext*)id->lockingContext)->filePath); sqlite3ThreadSafeFree(id->lockingContext); } if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; close(id->h); id->isOpen = 0; OSTRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); sqlite3ThreadSafeFree(id); *pId = 0; return SQLITE_OK;}#pragma mark flock() style locking/* ** The flockLockingContext is not used */typedef void flockLockingContext;static int flockUnixCheckReservedLock(OsFile *id) { unixFile *pFile = (unixFile*)id; if (pFile->locktype == RESERVED_LOCK) { return 1; /* already have a reserved lock */ } else { /* attempt to get the lock */ int rc = flock(pFile->h, LOCK_EX | LOCK_NB); if (!rc) { /* got the lock, unlock it */ flock(pFile->h, LOCK_UN); return 0; /* no one has it reserved */ } return 1; /* someone else might have it reserved */ }}static int flockUnixLock(OsFile *id, int locktype) { unixFile *pFile = (unixFile*)id; /* 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 */ int rc = flock(pFile->h, LOCK_EX | LOCK_NB); if (rc) { /* didn't get, must be busy */ return SQLITE_BUSY; } else { /* got it, set the type and return ok */ pFile->locktype = locktype; return SQLITE_OK; }}static int flockUnixUnlock(OsFile *id, int locktype) { unixFile *pFile = (unixFile*)id; 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) return SQLITE_IOERR_UNLOCK; else { pFile->locktype = NO_LOCK; return SQLITE_OK; }}/* ** Close a file. */static int flockUnixClose(OsFile **pId) { unixFile *id = (unixFile*)*pId; if( !id ) return SQLITE_OK; flockUnixUnlock(*pId, NO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -