]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When creating a new journal file, open a (read-only) file descriptor on the
authordrh <drh@noemail.net>
Sun, 27 Jul 2003 18:59:42 +0000 (18:59 +0000)
committerdrh <drh@noemail.net>
Sun, 27 Jul 2003 18:59:42 +0000 (18:59 +0000)
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

manifest
manifest.uuid
src/os.c
src/os.h
src/pager.c

index 3fdaf001f07ef8546540c81bb84f58b17dd1e72c..93d8d9072365ee4545ee672b342385c08145aec6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\sschema\sloader\scallback\scan\shandle\sEMPTY_RESULT_CALLBACKS\sbeing\non.\s\sTicket\s#406.\s(CVS\s1065)
-D 2003-07-27T17:26:23
+C When\screating\sa\snew\sjournal\sfile,\sopen\sa\s(read-only)\sfile\sdescriptor\son\sthe\ndirectory\scontaining\sthe\sjournal\sand\ssync\sthat\sdirectory\sonce\sto\smake\ssure\nthat\sthe\sjournal\sfilename\sentry\sgets\sinto\sthe\sdirectory.\s\sTicket\s#410.\s(CVS\s1066)
+D 2003-07-27T18:59:43
 F Makefile.in 9ad23ed4ca97f9670c4496432e3fbd4b3760ebde
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -35,9 +35,9 @@ F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
 F src/insert.c fc4c26a0bb505fb802babfb9a7b7a1d4be2e3061
 F src/main.c 2500392bad5629b6d70b06ac5a076958acb49b92
 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
-F src/os.c 2f24ede4d3464ac38d24d113e0d44d3c7d460be4
-F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
-F src/pager.c 9512e789dbd5acaf91e74c4665e03c2734d3da25
+F src/os.c b0ae51da6e2ec7dd9f48f92ac88985d5fde8c1d5
+F src/os.h 8aed1c928449433acf19d30f76bc86d549041167
+F src/pager.c a4fd3a61d63879365f775875edfffaa8c6f3d7f8
 F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31
 F src/parse.y 16aed0e3ed05445fa7f6a4209cc054208c7083c0
 F src/pragma.c 3b4f5a800e7a2145bc1930f323232e297d4eb782
@@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3
 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
-P 7514c3db165e8cc5c696b2b345844949a0e45a61
-R 85b9f91d179fe7af6d0cda86f9bcda89
+P 8c163fc0c7c721b7a5fa6727b0e90bff4484c782
+R 8fa888001788f8c7b2a2f5a0b6144c1c
 U drh
-Z 4a83ca4578ca29e5406602c40689d847
+Z 5beb2c4636d8c2b6025132999d440be1
index 79e163d533c1f5c712670a43a4c6a0511676fb9c..da11a898856f622f9a72de460c35d27cfa7f0846 100644 (file)
@@ -1 +1 @@
-8c163fc0c7c721b7a5fa6727b0e90bff4484c782
\ No newline at end of file
+09c10fe3c99cffc64ed02c2929f206d99c8e3309
\ No newline at end of file
index cca4ac48dcf915903eabae37bfcca0c5c08db7ce..2e3fdddbc6a57a6df507902880fa3bb64a24fea0 100644 (file)
--- a/src/os.c
+++ b/src/os.c
@@ -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
index d7674267d7c7b5237cb64bad36a2108c1f61acce..f47046ce13a706424179b004556bb63b172a3ccd 100644 (file)
--- a/src/os.h
+++ b/src/os.h
     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);
index 66c36159739aee8f02b9f3f517c1ddb27bd9d837..f470c0dd667478487129c75b93a2709d378b7132 100644 (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;