📄 os_unix.c
字号:
struct lockInfo **ppLock, /* Return the lockInfo structure here */ struct openCnt **ppOpen /* Return the openCnt structure here */){ int rc; struct lockKey key1; struct openKey key2; struct stat statbuf; struct lockInfo *pLock; struct openCnt *pOpen; rc = fstat(fd, &statbuf); if( rc!=0 ){#ifdef EOVERFLOW if( errno==EOVERFLOW ) return SQLITE_NOLFS;#endif return SQLITE_IOERR; } /* On OS X on an msdos filesystem, the inode number is reported ** incorrectly for zero-size files. See ticket #3260. To work ** around this problem (we consider it a bug in OS X, not SQLite) ** we always increase the file size to 1 by writing a single byte ** prior to accessing the inode number. The one byte written is ** an ASCII 'S' character which also happens to be the first byte ** in the header of every SQLite database. In this way, if there ** is a race condition such that another thread has already populated ** the first page of the database, no damage is done. */ if( statbuf.st_size==0 ){ write(fd, "S", 1); rc = fstat(fd, &statbuf); if( rc!=0 ){ return SQLITE_IOERR; } } memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev;#if IS_VXWORKS key1.rnam = rnam;#else key1.ino = statbuf.st_ino;#endif#if SQLITE_THREADSAFE if( threadsOverrideEachOthersLocks<0 ){ testThreadLockingBehavior(fd); } key1.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();#endif memset(&key2, 0, sizeof(key2)); key2.dev = statbuf.st_dev;#if IS_VXWORKS key2.rnam = rnam;#else key2.ino = statbuf.st_ino;#endif pLock = lockList; while( pLock && memcmp(&key1, &pLock->key, sizeof(key1)) ){ pLock = pLock->pNext; } if( pLock==0 ){ pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = SQLITE_NOMEM; goto exit_findlockinfo; } pLock->key = key1; pLock->nRef = 1; pLock->cnt = 0; pLock->locktype = 0; pLock->pNext = lockList; pLock->pPrev = 0; if( lockList ) lockList->pPrev = pLock; lockList = pLock; }else{ pLock->nRef++; } *ppLock = pLock; if( ppOpen!=0 ){ pOpen = openList; while( pOpen && memcmp(&key2, &pOpen->key, sizeof(key2)) ){ pOpen = pOpen->pNext; } if( pOpen==0 ){ pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = SQLITE_NOMEM; goto exit_findlockinfo; } pOpen->key = key2; pOpen->nRef = 1; pOpen->nLock = 0; pOpen->nPending = 0; pOpen->aPending = 0; pOpen->pNext = openList; pOpen->pPrev = 0; if( openList ) openList->pPrev = pOpen; openList = pOpen;#if IS_VXWORKS pOpen->pSem = NULL; pOpen->aSemName[0] = '\0';#endif }else{ pOpen->nRef++; } *ppOpen = pOpen; }exit_findlockinfo: return rc;}#ifdef SQLITE_DEBUG/*** Helper function for printing out trace information from debugging** binaries. This returns the string represetation of the supplied** integer lock-type.*/static const char *locktypeName(int locktype){ switch( locktype ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; case EXCLUSIVE_LOCK: return "EXCLUSIVE"; } return "ERROR";}#endif/*** If we are currently in a different thread than the thread that the** unixFile argument belongs to, then transfer ownership of the unixFile** over to the current thread.**** A unixFile is only owned by a thread on systems where one thread is** unable to override locks created by a different thread. RedHat9 is** an example of such a system.**** Ownership transfer is only allowed if the unixFile is currently unlocked.** If the unixFile is locked and an ownership is wrong, then return** SQLITE_MISUSE. SQLITE_OK is returned if everything works.*/#if SQLITE_THREADSAFEstatic int transferOwnership(unixFile *pFile){ int rc; pthread_t hSelf; if( threadsOverrideEachOthersLocks ){ /* Ownership transfers not needed on this system */ return SQLITE_OK; } hSelf = pthread_self(); if( pthread_equal(pFile->tid, hSelf) ){ /* We are still in the same thread */ OSTRACE1("No-transfer, same thread\n"); return SQLITE_OK; } if( pFile->locktype!=NO_LOCK ){ /* We cannot change ownership while we are holding a lock! */ return SQLITE_MISUSE; } OSTRACE4("Transfer ownership of %d from %d to %d\n", pFile->h, pFile->tid, hSelf); pFile->tid = hSelf; if (pFile->pLock != NULL) { releaseLockInfo(pFile->pLock);#if IS_VXWORKS rc = findLockInfo(pFile->h, pFile->zRealpath, &pFile->pLock, 0);#else rc = findLockInfo(pFile->h, &pFile->pLock, 0);#endif OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, locktypeName(pFile->locktype), locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); return rc; } else { return SQLITE_OK; }}#else /* On single-threaded builds, ownership transfer is a no-op */# define transferOwnership(X) SQLITE_OK#endif/*** Seek to the offset passed as the second argument, then read cnt ** bytes into pBuf. Return the number of bytes actually read.**** NB: If you define USE_PREAD or USE_PREAD64, then it might also** be necessary to define _XOPEN_SOURCE to be 500. This varies from** one system to another. Since SQLite does not define USE_PREAD** any any form by default, we will not attempt to define _XOPEN_SOURCE.** See tickets #2741 and #2681.*/static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 );#elif defined(USE_PREAD64) got = pread64(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 );#else newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset-- ); if( newOffset!=offset ){ return -1; } got = read(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED); return got;}/*** Read data from a file into a buffer. Return SQLITE_OK if all** bytes were read successfully and SQLITE_IOERR if anything goes** wrong.*/static int unixRead( sqlite3_file *id, void *pBuf, int amt, sqlite3_int64 offset){ int got; assert( id ); got = seekAndRead((unixFile*)id, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ return SQLITE_IOERR_READ; }else{ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; }}/*** Seek to the offset in id->offset then read cnt bytes into pBuf.** Return the number of bytes actually read. Update the offset.*/static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pwrite(id->h, pBuf, cnt, offset);#elif defined(USE_PREAD64) got = pwrite64(id->h, pBuf, cnt, offset);#else newOffset = lseek(id->h, offset, SEEK_SET); if( newOffset!=offset ){ return -1; } got = write(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED); return got;}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/static int unixWrite( sqlite3_file *id, const void *pBuf, int amt, sqlite3_int64 offset ){ int wrote = 0; assert( id ); assert( amt>0 ); while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>0 ){ if( wrote<0 ){ return SQLITE_IOERR_WRITE; }else{ return SQLITE_FULL; } } return SQLITE_OK;}#ifdef SQLITE_TEST/*** Count the number of fullsyncs and normal syncs. This is used to test** that syncs and fullsyncs are occuring at the right times.*/int sqlite3_sync_count = 0;int sqlite3_fullsync_count = 0;#endif/*** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.** Otherwise use fsync() in its place.*/#ifndef HAVE_FDATASYNC# define fdatasync fsync#endif/*** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently** only available on Mac OS X. But that could change.*/#ifdef F_FULLFSYNC# define HAVE_FULLFSYNC 1#else# define HAVE_FULLFSYNC 0#endif/*** The fsync() system call does not work as advertised on many** unix systems. The following procedure is an attempt to make** it work better.**** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful** for testing when we want to run through the test suite quickly.** You are strongly advised *not* to deploy with SQLITE_NO_SYNC** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash** or power failure will likely corrupt the database file.*/static int full_fsync(int fd, int fullSync, int dataOnly){ int rc; /* The following "ifdef/elif/else/" block has the same structure as ** the one below. It is replicated here solely to avoid cluttering ** up the real code with the UNUSED_PARAMETER() macros. */#ifdef SQLITE_NO_SYNC UNUSED_PARAMETER(fd); UNUSED_PARAMETER(fullSync); UNUSED_PARAMETER(dataOnly);#elif HAVE_FULLFSYNC UNUSED_PARAMETER(dataOnly);#else UNUSED_PARAMETER(fullSync);#endif /* Record the number of times that we do a normal fsync() and ** FULLSYNC. This is used during testing to verify that this procedure ** gets called with the correct arguments. */#ifdef SQLITE_TEST if( fullSync ) sqlite3_fullsync_count++; sqlite3_sync_count++;#endif /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a ** no-op */#ifdef SQLITE_NO_SYNC rc = SQLITE_OK;#elif HAVE_FULLFSYNC if( fullSync ){ rc = fcntl(fd, F_FULLFSYNC, 0); }else{ rc = 1; } /* If the FULLFSYNC failed, fall back to attempting an fsync(). * It shouldn't be possible for fullfsync to fail on the local * file system (on OSX), so failure indicates that FULLFSYNC * isn't supported for this file system. So, attempt an fsync * and (for now) ignore the overhead of a superfluous fcntl call. * It'd be better to detect fullfsync support once and avoid * the fcntl call every time sync is called. */ if( rc ) rc = fsync(fd);#else if( dataOnly ){ rc = fdatasync(fd); if( IS_VXWORKS && rc==-1 && errno==ENOTSUP ){ rc = fsync(fd); } }else{ rc = fsync(fd); }#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */ if( IS_VXWORKS && rc!= -1 ){ rc = 0; } return rc;}/*** Make sure all writes to a particular file are committed to disk.**** If dataOnly==0 then both the file itself and its metadata (file** size, access time, etc) are synced. If dataOnly!=0 then only the** file data is synced.**** Under Unix, also make sure that the directory entry for the file** has been created by fsync-ing the directory that contains the file.** If we do not do this and we encounter a power failure, the directory** entry for the journal might not exist after we reboot. The next** SQLite to access the file will not know that the journal exists (because** the directory entry for the journal was never created) and the transaction** will not roll back - possibly leading to database corruption.*/static int unixSync(sqlite3_file *id, int flags){ int rc; unixFile *pFile = (unixFile*)id; int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ assert((flags&0x0F)==SQLITE_SYNC_NORMAL || (flags&0x0F)==SQLITE_SYNC_FULL );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -