1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

When creating a new journal file, open a (read-only) file descriptor on the

directory containing the journal and sync that directory once to make sure
that the journal filename entry gets into the directory.  Ticket #410. (CVS 1066)

FossilOrigin-Name: 09c10fe3c99cffc64ed02c2929f206d99c8e3309
This commit is contained in:
drh
2003-07-27 18:59:42 +00:00
parent 98e3e60012
commit a76c82eb0d
5 changed files with 78 additions and 13 deletions

View File

@ -326,6 +326,7 @@ int sqliteOsOpenReadWrite(
int *pReadonly
){
#if OS_UNIX
id->dirfd = -1;
id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
if( id->fd<0 ){
id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
@ -450,6 +451,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
if( access(zFilename, 0)==0 ){
return SQLITE_CANTOPEN;
}
id->dirfd = -1;
id->fd = open(zFilename,
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
if( id->fd<0 ){
@ -536,6 +538,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
*/
int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){
#if OS_UNIX
id->dirfd = -1;
id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
if( id->fd<0 ){
return SQLITE_CANTOPEN;
@ -597,6 +600,42 @@ int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){
#endif
}
/*
** Attempt to open a file descriptor for the directory that contains a
** file. This file descriptor can be used to fsync() the directory
** in order to make sure the creation of a new file is actually written
** to disk.
**
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
** On success, a handle for a previously open file is at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
int sqliteOsOpenDirectory(
const char *zDirname,
OsFile *id
){
#if OS_UNIX
if( id->fd<0 ){
/* Do not open the directory if the corresponding file is not already
** open. */
return SQLITE_CANTOPEN;
}
assert( id->dirfd<0 );
id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
if( id->dirfd<0 ){
return SQLITE_CANTOPEN;
}
TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
#endif
return SQLITE_OK;
}
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
@ -706,6 +745,8 @@ int sqliteOsTempFileName(char *zBuf){
int sqliteOsClose(OsFile *id){
#if OS_UNIX
close(id->fd);
if( id->dirfd>=0 ) close(id->dirfd);
id->dirfd = -1;
sqliteOsEnterMutex();
releaseLockInfo(id->pLock);
sqliteOsLeaveMutex();
@ -892,6 +933,14 @@ int sqliteOsSeek(OsFile *id, off_t offset){
/*
** Make sure all writes to a particular file are committed to disk.
**
** 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.
*/
int sqliteOsSync(OsFile *id){
#if OS_UNIX
@ -900,6 +949,12 @@ int sqliteOsSync(OsFile *id){
if( fsync(id->fd) ){
return SQLITE_IOERR;
}else{
if( id->dirfd>=0 ){
TRACE2("DIRSYNC %-3d\n", id->dirfd);
fsync(id->dirfd);
close(id->dirfd); /* Only need to sync once, so close the directory */
id->dirfd = -1; /* when we are done. */
}
return SQLITE_OK;
}
#endif

View File

@ -104,6 +104,7 @@
struct lockInfo *pLock; /* Information about locks on this inode */
int fd; /* The file descriptor */
int locked; /* True if this user holds the lock */
int dirfd; /* File descriptor for the directory */
};
# define SQLITE_TEMPNAME_SIZE 200
# if defined(HAVE_USLEEP) && HAVE_USLEEP
@ -156,6 +157,7 @@ int sqliteOsFileRename(const char*, const char*);
int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
int sqliteOsOpenExclusive(const char*, OsFile*, int);
int sqliteOsOpenReadOnly(const char*, OsFile*);
int sqliteOsOpenDirectory(const char*, OsFile*);
int sqliteOsTempFileName(char*);
int sqliteOsClose(OsFile*);
int sqliteOsRead(OsFile*, void*, int amt);

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.86 2003/07/07 10:47:10 drh Exp $
** @(#) $Id: pager.c,v 1.87 2003/07/27 18:59:43 drh Exp $
*/
#include "os.h" /* Must be first to enable large file support */
#include "sqliteInt.h"
@ -129,6 +129,7 @@ struct PgHdr {
struct Pager {
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
char *zDirectory; /* Directory hold database and journal files */
OsFile fd, jfd; /* File descriptors for database and journal */
OsFile cpfd; /* File descriptor for the checkpoint journal */
int dbSize; /* Number of pages in the file */
@ -828,7 +829,7 @@ int sqlitepager_open(
char *zFullPathname;
int nameLen;
OsFile fd;
int rc;
int rc, i;
int tempFile;
int readOnly = 0;
char zTemp[SQLITE_TEMPNAME_SIZE];
@ -855,7 +856,7 @@ int sqlitepager_open(
return SQLITE_CANTOPEN;
}
nameLen = strlen(zFullPathname);
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*2 + 30 );
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
if( pPager==0 ){
sqliteOsClose(&fd);
sqliteFree(zFullPathname);
@ -863,8 +864,12 @@ int sqlitepager_open(
}
SET_PAGER(pPager);
pPager->zFilename = (char*)&pPager[1];
pPager->zJournal = &pPager->zFilename[nameLen+1];
pPager->zDirectory = &pPager->zFilename[nameLen+1];
pPager->zJournal = &pPager->zDirectory[nameLen+1];
strcpy(pPager->zFilename, zFullPathname);
strcpy(pPager->zDirectory, zFullPathname);
for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
if( i>0 ) pPager->zDirectory[i-1] = 0;
strcpy(pPager->zJournal, zFullPathname);
sqliteFree(zFullPathname);
strcpy(&pPager->zJournal[nameLen], "-journal");
@ -995,8 +1000,10 @@ int sqlitepager_close(Pager *pPager){
*/
CLR_PAGER(pPager);
if( pPager->zFilename!=(char*)&pPager[1] ){
assert( 0 ); /* Cannot happen */
sqliteFree(pPager->zFilename);
sqliteFree(pPager->zJournal);
sqliteFree(pPager->zDirectory);
}
sqliteFree(pPager);
return SQLITE_OK;
@ -1535,6 +1542,7 @@ static int pager_open_journal(Pager *pPager){
pPager->state = SQLITE_READLOCK;
return SQLITE_CANTOPEN;
}
sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd);
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->needSync = 0;