/ Check-in [3075cfa0]
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:For the unix VFS, avoid an unnecessary stat() system call prior to opening any file in the common case where there are no unused file descriptors.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3075cfa07489eaf13cb9a2760e2391e79dd73181fe1730fae7bdcd6ad66d2a1f
User & Date: drh 2017-08-18 16:09:52
Context
2017-08-18
21:14
Size and performance optimization the readDbPage() routine in the pager. check-in: ca9e1875 user: drh tags: trunk
16:09
For the unix VFS, avoid an unnecessary stat() system call prior to opening any file in the common case where there are no unused file descriptors. check-in: 3075cfa0 user: drh tags: trunk
14:34
Combine the OP_CreateTable and OP_CreateIndex opcodes of the bytecode engine into a single OP_CreateBtree opcode. This simplifies the implementation and makes the bytecode programs clearer. check-in: eb1202b5 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

   206    206     sqlite3_vfs *pVfs;                  /* The VFS that created this unixFile */
   207    207     unixInodeInfo *pInode;              /* Info about locks on this inode */
   208    208     int h;                              /* The file descriptor */
   209    209     unsigned char eFileLock;            /* The type of lock held on this fd */
   210    210     unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
   211    211     int lastErrno;                      /* The unix errno from last I/O error */
   212    212     void *lockingContext;               /* Locking style specific state */
   213         -  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
          213  +  UnixUnusedFd *pPreallocatedUnused;  /* Pre-allocated UnixUnusedFd */
   214    214     const char *zPath;                  /* Name of the file */
   215    215     unixShm *pShm;                      /* Shared memory segment information */
   216    216     int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
   217    217   #if SQLITE_MAX_MMAP_SIZE>0
   218    218     int nFetchOut;                      /* Number of outstanding xFetch refs */
   219    219     sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
   220    220     sqlite3_int64 mmapSizeActual;       /* Actual size of mapping at pMapRegion */
................................................................................
  1116   1116     char aSemName[MAX_PATHNAME+2];  /* Name of that semaphore */
  1117   1117   #endif
  1118   1118   };
  1119   1119   
  1120   1120   /*
  1121   1121   ** A lists of all unixInodeInfo objects.
  1122   1122   */
  1123         -static unixInodeInfo *inodeList = 0;
         1123  +static unixInodeInfo *inodeList = 0;  /* All unixInodeInfo objects */
         1124  +static unsigned int nUnusedFd = 0;    /* Total unused file descriptors */
  1124   1125   
  1125   1126   /*
  1126   1127   **
  1127   1128   ** This function - unixLogErrorAtLine(), is only ever called via the macro
  1128   1129   ** unixLogError().
  1129   1130   **
  1130   1131   ** It is invoked after an error occurs in an OS function and errno has been
................................................................................
  1226   1227     unixInodeInfo *pInode = pFile->pInode;
  1227   1228     UnixUnusedFd *p;
  1228   1229     UnixUnusedFd *pNext;
  1229   1230     for(p=pInode->pUnused; p; p=pNext){
  1230   1231       pNext = p->pNext;
  1231   1232       robust_close(pFile, p->fd, __LINE__);
  1232   1233       sqlite3_free(p);
         1234  +    nUnusedFd--;
  1233   1235     }
  1234   1236     pInode->pUnused = 0;
  1235   1237   }
  1236   1238   
  1237   1239   /*
  1238   1240   ** Release a unixInodeInfo structure previously allocated by findInodeInfo().
  1239   1241   **
................................................................................
  1258   1260         if( pInode->pNext ){
  1259   1261           assert( pInode->pNext->pPrev==pInode );
  1260   1262           pInode->pNext->pPrev = pInode->pPrev;
  1261   1263         }
  1262   1264         sqlite3_free(pInode);
  1263   1265       }
  1264   1266     }
         1267  +  assert( inodeList!=0 || nUnusedFd==0 );
  1265   1268   }
  1266   1269   
  1267   1270   /*
  1268   1271   ** Given a file descriptor, locate the unixInodeInfo object that
  1269   1272   ** describes that file descriptor.  Create a new one if necessary.  The
  1270   1273   ** return value might be uninitialized if an error occurs.
  1271   1274   **
................................................................................
  1327   1330     memset(&fileId, 0, sizeof(fileId));
  1328   1331     fileId.dev = statbuf.st_dev;
  1329   1332   #if OS_VXWORKS
  1330   1333     fileId.pId = pFile->pId;
  1331   1334   #else
  1332   1335     fileId.ino = (u64)statbuf.st_ino;
  1333   1336   #endif
         1337  +  assert( inodeList!=0 || nUnusedFd==0 );
  1334   1338     pInode = inodeList;
  1335   1339     while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
  1336   1340       pInode = pInode->pNext;
  1337   1341     }
  1338   1342     if( pInode==0 ){
  1339   1343       pInode = sqlite3_malloc64( sizeof(*pInode) );
  1340   1344       if( pInode==0 ){
................................................................................
  1746   1750   
  1747   1751   /*
  1748   1752   ** Add the file descriptor used by file handle pFile to the corresponding
  1749   1753   ** pUnused list.
  1750   1754   */
  1751   1755   static void setPendingFd(unixFile *pFile){
  1752   1756     unixInodeInfo *pInode = pFile->pInode;
  1753         -  UnixUnusedFd *p = pFile->pUnused;
         1757  +  UnixUnusedFd *p = pFile->pPreallocatedUnused;
  1754   1758     p->pNext = pInode->pUnused;
  1755   1759     pInode->pUnused = p;
  1756   1760     pFile->h = -1;
  1757         -  pFile->pUnused = 0;
         1761  +  pFile->pPreallocatedUnused = 0;
         1762  +  nUnusedFd++;
  1758   1763   }
  1759   1764   
  1760   1765   /*
  1761   1766   ** Lower the locking level on file descriptor pFile to eFileLock.  eFileLock
  1762   1767   ** must be either NO_LOCK or SHARED_LOCK.
  1763   1768   **
  1764   1769   ** If the locking level of the file descriptor is already at or below
................................................................................
  1975   1980       osUnlink(pFile->zPath);
  1976   1981       sqlite3_free(*(char**)&pFile->zPath);
  1977   1982       pFile->zPath = 0;
  1978   1983     }
  1979   1984   #endif
  1980   1985     OSTRACE(("CLOSE   %-3d\n", pFile->h));
  1981   1986     OpenCounter(-1);
  1982         -  sqlite3_free(pFile->pUnused);
         1987  +  sqlite3_free(pFile->pPreallocatedUnused);
  1983   1988     memset(pFile, 0, sizeof(unixFile));
  1984   1989     return SQLITE_OK;
  1985   1990   }
  1986   1991   
  1987   1992   /*
  1988   1993   ** Close a file.
  1989   1994   */
................................................................................
  3196   3201     assert( id );
  3197   3202     assert( offset>=0 );
  3198   3203     assert( amt>0 );
  3199   3204   
  3200   3205     /* If this is a database file (not a journal, master-journal or temp
  3201   3206     ** file), the bytes in the locking range should never be read or written. */
  3202   3207   #if 0
  3203         -  assert( pFile->pUnused==0
         3208  +  assert( pFile->pPreallocatedUnused==0
  3204   3209          || offset>=PENDING_BYTE+512
  3205   3210          || offset+amt<=PENDING_BYTE 
  3206   3211     );
  3207   3212   #endif
  3208   3213   
  3209   3214   #if SQLITE_MAX_MMAP_SIZE>0
  3210   3215     /* Deal with as much of this read request as possible by transfering
................................................................................
  3309   3314     int wrote = 0;
  3310   3315     assert( id );
  3311   3316     assert( amt>0 );
  3312   3317   
  3313   3318     /* If this is a database file (not a journal, master-journal or temp
  3314   3319     ** file), the bytes in the locking range should never be read or written. */
  3315   3320   #if 0
  3316         -  assert( pFile->pUnused==0
         3321  +  assert( pFile->pPreallocatedUnused==0
  3317   3322          || offset>=PENDING_BYTE+512
  3318   3323          || offset+amt<=PENDING_BYTE 
  3319   3324     );
  3320   3325   #endif
  3321   3326   
  3322   3327   #ifdef SQLITE_DEBUG
  3323   3328     /* If we are doing a normal write to a database file (as opposed to
................................................................................
  5559   5564     /* Do not search for an unused file descriptor on vxworks. Not because
  5560   5565     ** vxworks would not benefit from the change (it might, we're not sure),
  5561   5566     ** but because no way to test it is currently available. It is better 
  5562   5567     ** not to risk breaking vxworks support for the sake of such an obscure 
  5563   5568     ** feature.  */
  5564   5569   #if !OS_VXWORKS
  5565   5570     struct stat sStat;                   /* Results of stat() call */
         5571  +
         5572  +  unixEnterMutex();
  5566   5573   
  5567   5574     /* A stat() call may fail for various reasons. If this happens, it is
  5568   5575     ** almost certain that an open() call on the same path will also fail.
  5569   5576     ** For this reason, if an error occurs in the stat() call here, it is
  5570   5577     ** ignored and -1 is returned. The caller will try to open a new file
  5571   5578     ** descriptor on the same path, fail, and return an error to SQLite.
  5572   5579     **
  5573   5580     ** Even if a subsequent open() call does succeed, the consequences of
  5574   5581     ** not searching for a reusable file descriptor are not dire.  */
  5575         -  if( 0==osStat(zPath, &sStat) ){
         5582  +  if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
  5576   5583       unixInodeInfo *pInode;
  5577   5584   
  5578         -    unixEnterMutex();
  5579   5585       pInode = inodeList;
  5580   5586       while( pInode && (pInode->fileId.dev!=sStat.st_dev
  5581   5587                        || pInode->fileId.ino!=(u64)sStat.st_ino) ){
  5582   5588          pInode = pInode->pNext;
  5583   5589       }
  5584   5590       if( pInode ){
  5585   5591         UnixUnusedFd **pp;
  5586   5592         for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
  5587   5593         pUnused = *pp;
  5588   5594         if( pUnused ){
         5595  +        nUnusedFd--;
  5589   5596           *pp = pUnused->pNext;
  5590   5597         }
  5591   5598       }
  5592         -    unixLeaveMutex();
  5593   5599     }
         5600  +  unixLeaveMutex();
  5594   5601   #endif    /* if !OS_VXWORKS */
  5595   5602     return pUnused;
  5596   5603   }
  5597   5604   
  5598   5605   /*
  5599   5606   ** Find the mode, uid and gid of file zFile. 
  5600   5607   */
................................................................................
  5807   5814         fd = pUnused->fd;
  5808   5815       }else{
  5809   5816         pUnused = sqlite3_malloc64(sizeof(*pUnused));
  5810   5817         if( !pUnused ){
  5811   5818           return SQLITE_NOMEM_BKPT;
  5812   5819         }
  5813   5820       }
  5814         -    p->pUnused = pUnused;
         5821  +    p->pPreallocatedUnused = pUnused;
  5815   5822   
  5816   5823       /* Database filenames are double-zero terminated if they are not
  5817   5824       ** URIs with parameters.  Hence, they can always be passed into
  5818   5825       ** sqlite3_uri_parameter(). */
  5819   5826       assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 );
  5820   5827   
  5821   5828     }else if( !zName ){
................................................................................
  5844   5851   
  5845   5852     if( fd<0 ){
  5846   5853       mode_t openMode;              /* Permissions to create file with */
  5847   5854       uid_t uid;                    /* Userid for the file */
  5848   5855       gid_t gid;                    /* Groupid for the file */
  5849   5856       rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
  5850   5857       if( rc!=SQLITE_OK ){
  5851         -      assert( !p->pUnused );
         5858  +      assert( !p->pPreallocatedUnused );
  5852   5859         assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
  5853   5860         return rc;
  5854   5861       }
  5855   5862       fd = robust_open(zName, openFlags, openMode);
  5856   5863       OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
  5857   5864       assert( !isExclusive || (openFlags & O_CREAT)!=0 );
  5858   5865       if( fd<0 && errno!=EISDIR && isReadWrite ){
................................................................................
  5878   5885       }
  5879   5886     }
  5880   5887     assert( fd>=0 );
  5881   5888     if( pOutFlags ){
  5882   5889       *pOutFlags = flags;
  5883   5890     }
  5884   5891   
  5885         -  if( p->pUnused ){
  5886         -    p->pUnused->fd = fd;
  5887         -    p->pUnused->flags = flags;
         5892  +  if( p->pPreallocatedUnused ){
         5893  +    p->pPreallocatedUnused->fd = fd;
         5894  +    p->pPreallocatedUnused->flags = flags;
  5888   5895     }
  5889   5896   
  5890   5897     if( isDelete ){
  5891   5898   #if OS_VXWORKS
  5892   5899       zPath = zName;
  5893   5900   #elif defined(SQLITE_UNLINK_AFTER_CLOSE)
  5894   5901       zPath = sqlite3_mprintf("%s", zName);
................................................................................
  5961   5968     }
  5962   5969   #endif
  5963   5970     
  5964   5971     rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
  5965   5972   
  5966   5973   open_finished:
  5967   5974     if( rc!=SQLITE_OK ){
  5968         -    sqlite3_free(p->pUnused);
         5975  +    sqlite3_free(p->pPreallocatedUnused);
  5969   5976     }
  5970   5977     return rc;
  5971   5978   }
  5972   5979   
  5973   5980   
  5974   5981   /*
  5975   5982   ** Delete the file at zPath. If the dirSync argument is true, fsync()
................................................................................
  6702   6709     memset(pNew, 0, sizeof(unixFile));
  6703   6710     pNew->openFlags = openFlags;
  6704   6711     memset(&dummyVfs, 0, sizeof(dummyVfs));
  6705   6712     dummyVfs.pAppData = (void*)&autolockIoFinder;
  6706   6713     dummyVfs.zName = "dummy";
  6707   6714     pUnused->fd = fd;
  6708   6715     pUnused->flags = openFlags;
  6709         -  pNew->pUnused = pUnused;
         6716  +  pNew->pPreallocatedUnused = pUnused;
  6710   6717     
  6711   6718     rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
  6712   6719     if( rc==SQLITE_OK ){
  6713   6720       *ppFile = pNew;
  6714   6721       return SQLITE_OK;
  6715   6722     }
  6716   6723   end_create_proxy: