📄 os_unix.c
字号:
** 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{ 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; /* 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;#else#if 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); }else{ rc = fsync(fd); }#endif /* HAVE_FULLFSYNC */#endif /* defined(SQLITE_NO_SYNC) */ 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 ); assert( pFile ); OSTRACE2("SYNC %-3d\n", pFile->h); rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ return SQLITE_IOERR_FSYNC; } if( pFile->dirfd>=0 ){ OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, HAVE_FULLFSYNC, isFullsync);#ifndef SQLITE_DISABLE_DIRSYNC /* The directory sync is only attempted if full_fsync is ** turned off or unavailable. If a full_fsync occurred above, ** then the directory sync is superfluous. */ if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ /* ** We have received multiple reports of fsync() returning ** errors when applied to directories on certain file systems. ** A failed directory sync is not a big deal. So it seems ** better to ignore the error. Ticket #1657 */ /* return SQLITE_IOERR; */ }#endif close(pFile->dirfd); /* Only need to sync once, so close the directory */ pFile->dirfd = -1; /* when we are done. */ } return SQLITE_OK;}/*** Truncate an open file to a specified size*/static int unixTruncate(sqlite3_file *id, i64 nByte){ int rc; assert( id ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); if( rc ){ return SQLITE_IOERR_TRUNCATE; }else{ return SQLITE_OK; }}/*** Determine the current size of a file in bytes*/static int unixFileSize(sqlite3_file *id, i64 *pSize){ int rc; struct stat buf; assert( id ); rc = fstat(((unixFile*)id)->h, &buf); SimulateIOError( rc=1 ); if( rc!=0 ){ return SQLITE_IOERR_FSTAT; } *pSize = buf.st_size; /* When opening a zero-size database, the findLockInfo() procedure ** writes a single byte into that file in order to work around a bug ** in the OS-X msdos filesystem. In order to avoid problems with upper ** layers, we need to report this file size as zero even though it is ** really 1. Ticket #3260. */ if( *pSize==1 ) *pSize = 0; return SQLITE_OK;}/*** This routine translates a standard POSIX errno code into something** useful to the clients of the sqlite3 functions. Specifically, it is** intended to translate a variety of "try again" errors into SQLITE_BUSY** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR** ** Errors during initialization of locks, or file system support for locks,** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.*/static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { switch (posixError) { case 0: return SQLITE_OK; case EAGAIN: case ETIMEDOUT: case EBUSY: case EINTR: case ENOLCK: /* random NFS retry error, unless during file system support * introspection, in which it actually means what it says */ return SQLITE_BUSY; case EACCES: /* EACCES is like EAGAIN during locking operations, but not any other time*/ if( (sqliteIOErr == SQLITE_IOERR_LOCK) || (sqliteIOErr == SQLITE_IOERR_UNLOCK) || (sqliteIOErr == SQLITE_IOERR_RDLOCK) || (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ return SQLITE_BUSY; } /* else fall through */ case EPERM: return SQLITE_PERM; case EDEADLK: return SQLITE_IOERR_BLOCKED; #if EOPNOTSUPP!=ENOTSUP case EOPNOTSUPP: /* something went terribly awry, unless during file system support * introspection, in which it actually means what it says */#endif case ENOTSUP: /* invalid fd, unless during file system support introspection, in which * it actually means what it says */ case EIO: case EBADF: case EINVAL: case ENOTCONN: case ENODEV: case ENXIO: case ENOENT: case ESTALE: case ENOSYS: /* these should force the client to close the file and reconnect */ default: return sqliteIOErr; }}/*** 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 unixCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); enterMutex(); /* Because pFile->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( pFile->pLock->locktype>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; if (-1 == fcntl(pFile->h, F_GETLK, &lock)) { int tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); pFile->lastErrno = tErrno; } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } } leaveMutex(); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -