/ Check-in [09c10fe3]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 09c10fe3c99cffc64ed02c2929f206d99c8e3309
User & Date: drh 2003-07-27 18:59:43
Context
2003-07-30
12:34
The {quote: SrcList} object was not being expanded correctly by a call to sqliteSrcListAppend() if the {quote: SrcList} had previously been duplicated by a call to sqliteSrcListDup(). Ticket #416. This check-in fixes that problem by keeping a separate nAlloc field on {quote: SrcList}. A similar change is made to {quote: IdList} and {quote: ExprList} to avoid future problems. (CVS 1067) check-in: da627325 user: drh tags: trunk
2003-07-27
18:59
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) check-in: 09c10fe3 user: drh tags: trunk
17:26
Make sure the schema loader callback can handle EMPTY_RESULT_CALLBACKS being on. Ticket #406. (CVS 1065) check-in: 8c163fc0 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os.c.

322
323
324
325
326
327
328

329
330
331
332
333
334
335
...
446
447
448
449
450
451
452

453
454
455
456
457
458
459
...
532
533
534
535
536
537
538

539
540
541
542
543
544
545
...
592
593
594
595
596
597
598




































599
600
601
602
603
604
605
...
702
703
704
705
706
707
708


709
710
711
712
713
714
715
...
888
889
890
891
892
893
894








895
896
897
898
899
900
901
902






903
904
905
906
907
908
909
*/
int sqliteOsOpenReadWrite(
  const char *zFilename,
  OsFile *id,
  int *pReadonly
){
#if OS_UNIX

  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);
    if( id->fd<0 ){
      return SQLITE_CANTOPEN; 
    }
    *pReadonly = 1;
................................................................................
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
#if OS_UNIX
  if( access(zFilename, 0)==0 ){
    return SQLITE_CANTOPEN;
  }

  id->fd = open(zFilename,
                O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
  if( id->fd<0 ){
    return SQLITE_CANTOPEN;
  }
  sqliteOsEnterMutex();
  id->pLock = findLockInfo(id->fd);
................................................................................
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){
#if OS_UNIX

  id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
  if( id->fd<0 ){
    return SQLITE_CANTOPEN;
  }
  sqliteOsEnterMutex();
  id->pLock = findLockInfo(id->fd);
  sqliteOsLeaveMutex();
................................................................................
  }
  id->locked = 0;
  id->delOnClose = 0;
  OpenCounter(+1);
  return SQLITE_OK;
#endif
}





































/*
** Create a temporary file name in zBuf.  zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
int sqliteOsTempFileName(char *zBuf){
#if OS_UNIX
................................................................................

/*
** Close a file
*/
int sqliteOsClose(OsFile *id){
#if OS_UNIX
  close(id->fd);


  sqliteOsEnterMutex();
  releaseLockInfo(id->pLock);
  sqliteOsLeaveMutex();
  TRACE2("CLOSE   %-3d\n", id->fd);
  OpenCounter(-1);
  return SQLITE_OK;
#endif
................................................................................
    }
  }
#endif
}

/*
** Make sure all writes to a particular file are committed to disk.








*/
int sqliteOsSync(OsFile *id){
#if OS_UNIX
  SimulateIOError(SQLITE_IOERR);
  TRACE2("SYNC    %-3d\n", id->fd);
  if( fsync(id->fd) ){
    return SQLITE_IOERR;
  }else{






    return SQLITE_OK;
  }
#endif
#if OS_WIN
  if( FlushFileBuffers(id->h) ){
    return SQLITE_OK;
  }else{







>







 







>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







 







>
>
>
>
>
>
>
>








>
>
>
>
>
>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
...
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
*/
int sqliteOsOpenReadWrite(
  const char *zFilename,
  OsFile *id,
  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);
    if( id->fd<0 ){
      return SQLITE_CANTOPEN; 
    }
    *pReadonly = 1;
................................................................................
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
#if OS_UNIX
  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 ){
    return SQLITE_CANTOPEN;
  }
  sqliteOsEnterMutex();
  id->pLock = findLockInfo(id->fd);
................................................................................
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
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;
  }
  sqliteOsEnterMutex();
  id->pLock = findLockInfo(id->fd);
  sqliteOsLeaveMutex();
................................................................................
  }
  id->locked = 0;
  id->delOnClose = 0;
  OpenCounter(+1);
  return SQLITE_OK;
#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.
*/
int sqliteOsTempFileName(char *zBuf){
#if OS_UNIX
................................................................................

/*
** Close a file
*/
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();
  TRACE2("CLOSE   %-3d\n", id->fd);
  OpenCounter(-1);
  return SQLITE_OK;
#endif
................................................................................
    }
  }
#endif
}

/*
** 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
  SimulateIOError(SQLITE_IOERR);
  TRACE2("SYNC    %-3d\n", id->fd);
  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
#if OS_WIN
  if( FlushFileBuffers(id->h) ){
    return SQLITE_OK;
  }else{

Changes to src/os.h.

100
101
102
103
104
105
106

107
108
109
110
111
112
113
...
152
153
154
155
156
157
158

159
160
161
162
163
164
165
# include <fcntl.h>
# include <unistd.h>
  typedef struct OsFile OsFile;
  struct OsFile {
    struct lockInfo *pLock;  /* Information about locks on this inode */
    int fd;                  /* The file descriptor */
    int locked;              /* True if this user holds the lock */

  };
# define SQLITE_TEMPNAME_SIZE 200
# if defined(HAVE_USLEEP) && HAVE_USLEEP
#  define SQLITE_MIN_SLEEP_MS 1
# else
#  define SQLITE_MIN_SLEEP_MS 1000
# endif
................................................................................

int sqliteOsDelete(const char*);
int sqliteOsFileExists(const char*);
int sqliteOsFileRename(const char*, const char*);
int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
int sqliteOsOpenExclusive(const char*, OsFile*, int);
int sqliteOsOpenReadOnly(const char*, OsFile*);

int sqliteOsTempFileName(char*);
int sqliteOsClose(OsFile*);
int sqliteOsRead(OsFile*, void*, int amt);
int sqliteOsWrite(OsFile*, const void*, int amt);
int sqliteOsSeek(OsFile*, off_t offset);
int sqliteOsSync(OsFile*);
int sqliteOsTruncate(OsFile*, off_t size);







>







 







>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# include <fcntl.h>
# include <unistd.h>
  typedef struct OsFile OsFile;
  struct OsFile {
    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
#  define SQLITE_MIN_SLEEP_MS 1
# else
#  define SQLITE_MIN_SLEEP_MS 1000
# endif
................................................................................

int sqliteOsDelete(const char*);
int sqliteOsFileExists(const char*);
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);
int sqliteOsWrite(OsFile*, const void*, int amt);
int sqliteOsSeek(OsFile*, off_t offset);
int sqliteOsSync(OsFile*);
int sqliteOsTruncate(OsFile*, off_t size);

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
125
126
127
128
129
130
131

132
133
134
135
136
137
138
...
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
...
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866

867



868
869
870
871
872
873
874
...
991
992
993
994
995
996
997

998
999

1000
1001
1002
1003
1004
1005
1006
....
1531
1532
1533
1534
1535
1536
1537

1538
1539
1540
1541
1542
1543
1544
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** 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 $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................

/*
** A open page cache is an instance of the following structure.
*/
struct Pager {
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */

  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 */
  int origDbSize;             /* dbSize before the current change */
  int ckptSize;               /* Size of database (in pages) at ckpt_begin() */
  off_t ckptJSize;            /* Size of journal at ckpt_begin() */
  int nRec;                   /* Number of pages written to the journal */
................................................................................
  int nExtra,              /* Extra bytes append to each in-memory page */
  int useJournal           /* TRUE to use a rollback journal on this file */
){
  Pager *pPager;
  char *zFullPathname;
  int nameLen;
  OsFile fd;
  int rc;
  int tempFile;
  int readOnly = 0;
  char zTemp[SQLITE_TEMPNAME_SIZE];

  *ppPager = 0;
  if( sqlite_malloc_failed ){
    return SQLITE_NOMEM;
................................................................................
    return SQLITE_NOMEM;
  }
  if( rc!=SQLITE_OK ){
    sqliteFree(zFullPathname);
    return SQLITE_CANTOPEN;
  }
  nameLen = strlen(zFullPathname);
  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*2 + 30 );
  if( pPager==0 ){
    sqliteOsClose(&fd);
    sqliteFree(zFullPathname);
    return SQLITE_NOMEM;
  }
  SET_PAGER(pPager);
  pPager->zFilename = (char*)&pPager[1];
  pPager->zJournal = &pPager->zFilename[nameLen+1];

  strcpy(pPager->zFilename, zFullPathname);



  strcpy(pPager->zJournal, zFullPathname);
  sqliteFree(zFullPathname);
  strcpy(&pPager->zJournal[nameLen], "-journal");
  pPager->fd = fd;
  pPager->journalOpen = 0;
  pPager->useJournal = useJournal;
  pPager->ckptOpen = 0;
................................................................................
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqliteOsDelete(pPager->zFilename);
  ** }
  */
  CLR_PAGER(pPager);
  if( pPager->zFilename!=(char*)&pPager[1] ){

    sqliteFree(pPager->zFilename);
    sqliteFree(pPager->zJournal);

  }
  sqliteFree(pPager);
  return SQLITE_OK;
}

/*
** Return the page number for the given page data.
................................................................................
  if( rc!=SQLITE_OK ){
    sqliteFree(pPager->aInJournal);
    pPager->aInJournal = 0;
    sqliteOsReadLock(&pPager->fd);
    pPager->state = SQLITE_READLOCK;
    return SQLITE_CANTOPEN;
  }

  pPager->journalOpen = 1;
  pPager->journalStarted = 0;
  pPager->needSync = 0;
  pPager->alwaysRollback = 0;
  pPager->nRec = 0;
  if( pPager->errMask!=0 ){
    rc = pager_errcode(pPager);







|







 







>







 







|







 







|







|
>

>
>
>







 







>


>







 







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
...
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
....
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $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"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................

/*
** A open page cache is an instance of the following structure.
*/
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 */
  int origDbSize;             /* dbSize before the current change */
  int ckptSize;               /* Size of database (in pages) at ckpt_begin() */
  off_t ckptJSize;            /* Size of journal at ckpt_begin() */
  int nRec;                   /* Number of pages written to the journal */
................................................................................
  int nExtra,              /* Extra bytes append to each in-memory page */
  int useJournal           /* TRUE to use a rollback journal on this file */
){
  Pager *pPager;
  char *zFullPathname;
  int nameLen;
  OsFile fd;
  int rc, i;
  int tempFile;
  int readOnly = 0;
  char zTemp[SQLITE_TEMPNAME_SIZE];

  *ppPager = 0;
  if( sqlite_malloc_failed ){
    return SQLITE_NOMEM;
................................................................................
    return SQLITE_NOMEM;
  }
  if( rc!=SQLITE_OK ){
    sqliteFree(zFullPathname);
    return SQLITE_CANTOPEN;
  }
  nameLen = strlen(zFullPathname);
  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
  if( pPager==0 ){
    sqliteOsClose(&fd);
    sqliteFree(zFullPathname);
    return SQLITE_NOMEM;
  }
  SET_PAGER(pPager);
  pPager->zFilename = (char*)&pPager[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");
  pPager->fd = fd;
  pPager->journalOpen = 0;
  pPager->useJournal = useJournal;
  pPager->ckptOpen = 0;
................................................................................
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqliteOsDelete(pPager->zFilename);
  ** }
  */
  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;
}

/*
** Return the page number for the given page data.
................................................................................
  if( rc!=SQLITE_OK ){
    sqliteFree(pPager->aInJournal);
    pPager->aInJournal = 0;
    sqliteOsReadLock(&pPager->fd);
    pPager->state = SQLITE_READLOCK;
    return SQLITE_CANTOPEN;
  }
  sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd);
  pPager->journalOpen = 1;
  pPager->journalStarted = 0;
  pPager->needSync = 0;
  pPager->alwaysRollback = 0;
  pPager->nRec = 0;
  if( pPager->errMask!=0 ){
    rc = pager_errcode(pPager);