/ Check-in [e3ea43da]
Login

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

Overview
Comment:Stop requiring the global VFS mutex to access the unixInodeInfo.pUnused field. The unixInodeInfo mutex is sufficient.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:e3ea43dabf099dc2954c23d348638e7b2a8b9122d2994154bc649a2c09260c46
User & Date: drh 2018-08-13 22:50:34
Context
2018-08-14
15:12
Fix UPSERT so that it checks the target-constraint first and fires the DO UPDATE if that constraint is violated regardless of whether or not other constraints are in violation. This aligns SQLite behavior with what PostgreSQL does. Fix for ticket [908f001483982c43cdb476dfb590a1a]. check-in: 529fb55e user: drh tags: trunk
2018-08-13
22:50
Stop requiring the global VFS mutex to access the unixInodeInfo.pUnused field. The unixInodeInfo mutex is sufficient. check-in: e3ea43da user: drh tags: trunk
20:46
Take extra precautions to ensure access to unixInodeInfo.pUnused is protected by all necessary mutexes. check-in: 8b1e0010 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

  1122   1122   ** structure contains a pointer to an instance of this object and this
  1123   1123   ** object keeps a count of the number of unixFile pointing to it.
  1124   1124   **
  1125   1125   ** Mutex rules:
  1126   1126   **
  1127   1127   **  (1) Only the pLockMutex mutex must be held in order to read or write
  1128   1128   **      any of the locking fields:
  1129         -**          nShared, nLock, eFileLock, or bProcessLock
         1129  +**          nShared, nLock, eFileLock, bProcessLock, pUnused
  1130   1130   **
  1131   1131   **  (2) When nRef>0, then the following fields are unchanging and can
  1132   1132   **      be read (but not written) without holding any mutex:
  1133   1133   **          fileId, pLockMutex
  1134   1134   **
  1135         -**  (3) The pUnused field may only be changed while holding bo the
  1136         -**      pLockMutex and the bigUnixLock mutex.  But it may be read
  1137         -**      while holding either.
  1138         -**
  1139         -**  (4) With the exceptions above, all the fields may only be read
         1135  +**  (3) With the exceptions above, all the fields may only be read
  1140   1136   **      or written while holding the global unixBigLock mutex.
  1141   1137   **
  1142   1138   ** Deadlock prevention:  The global unixBigLock mutex may not
  1143   1139   ** be acquired while holding the pLockMutex mutex.  If both unixBigLock
  1144   1140   ** and pLockMutex are needed, then unixBigLock must be acquired first.
  1145   1141   */
  1146   1142   struct unixInodeInfo {
  1147   1143     struct unixFileId fileId;       /* The lookup key */
  1148   1144     sqlite3_mutex *pLockMutex;      /* Hold this mutex for... */
  1149   1145     int nShared;                      /* Number of SHARED locks held */
  1150   1146     int nLock;                        /* Number of outstanding file locks */
  1151   1147     unsigned char eFileLock;          /* One of SHARED_LOCK, RESERVED_LOCK etc. */
  1152   1148     unsigned char bProcessLock;       /* An exclusive process lock is held */
  1153         -  UnixUnusedFd *pUnused;          /* Unused file descriptors to close */
         1149  +  UnixUnusedFd *pUnused;            /* Unused file descriptors to close */
  1154   1150     int nRef;                       /* Number of pointers to this structure */
  1155   1151     unixShmNode *pShmNode;          /* Shared memory associated with this inode */
  1156   1152     unixInodeInfo *pNext;           /* List of all unixInodeInfo objects */
  1157   1153     unixInodeInfo *pPrev;           /*    .... doubly linked */
  1158   1154   #if SQLITE_ENABLE_LOCKING_STYLE
  1159   1155     unsigned long long sharedByte;  /* for AFP simulated shared lock */
  1160   1156   #endif
................................................................................
  1284   1280   /*
  1285   1281   ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
  1286   1282   */ 
  1287   1283   static void closePendingFds(unixFile *pFile){
  1288   1284     unixInodeInfo *pInode = pFile->pInode;
  1289   1285     UnixUnusedFd *p;
  1290   1286     UnixUnusedFd *pNext;
  1291         -  assert( unixMutexHeld() );
  1292         -  assert( unixFileMutexNotheld(pFile) );
  1293         -  sqlite3_mutex_enter(pInode->pLockMutex);
         1287  +  assert( unixFileMutexHeld(pFile) );
  1294   1288     for(p=pInode->pUnused; p; p=pNext){
  1295   1289       pNext = p->pNext;
  1296   1290       robust_close(pFile, p->fd, __LINE__);
  1297   1291       sqlite3_free(p);
  1298   1292     }
  1299   1293     pInode->pUnused = 0;
  1300         -  sqlite3_mutex_leave(pInode->pLockMutex);
  1301   1294   }
  1302   1295   
  1303   1296   /*
  1304   1297   ** Release a unixInodeInfo structure previously allocated by findInodeInfo().
  1305   1298   **
  1306   1299   ** The mutex entered using the unixEnterMutex() function must be held
  1307   1300   ** when this function is called.
................................................................................
  1310   1303     unixInodeInfo *pInode = pFile->pInode;
  1311   1304     assert( unixMutexHeld() );
  1312   1305     assert( unixFileMutexNotheld(pFile) );
  1313   1306     if( ALWAYS(pInode) ){
  1314   1307       pInode->nRef--;
  1315   1308       if( pInode->nRef==0 ){
  1316   1309         assert( pInode->pShmNode==0 );
         1310  +      sqlite3_mutex_enter(pInode->pLockMutex);
  1317   1311         closePendingFds(pFile);
         1312  +      sqlite3_mutex_leave(pInode->pLockMutex);
  1318   1313         if( pInode->pPrev ){
  1319   1314           assert( pInode->pPrev->pNext==pInode );
  1320   1315           pInode->pPrev->pNext = pInode->pNext;
  1321   1316         }else{
  1322   1317           assert( inodeList==pInode );
  1323   1318           inodeList = pInode->pNext;
  1324   1319         }
................................................................................
  1859   1854   /*
  1860   1855   ** Add the file descriptor used by file handle pFile to the corresponding
  1861   1856   ** pUnused list.
  1862   1857   */
  1863   1858   static void setPendingFd(unixFile *pFile){
  1864   1859     unixInodeInfo *pInode = pFile->pInode;
  1865   1860     UnixUnusedFd *p = pFile->pPreallocatedUnused;
  1866         -  assert( unixMutexHeld() );
  1867         -  assert( unixFileMutexNotheld(pFile) );
  1868         -  sqlite3_mutex_enter(pInode->pLockMutex);
         1861  +  assert( unixFileMutexHeld(pFile) );
  1869   1862     p->pNext = pInode->pUnused;
  1870   1863     pInode->pUnused = p;
  1871         -  sqlite3_mutex_leave(pInode->pLockMutex);
  1872   1864     pFile->h = -1;
  1873   1865     pFile->pPreallocatedUnused = 0;
  1874   1866   }
  1875   1867   
  1876   1868   /*
  1877   1869   ** Lower the locking level on file descriptor pFile to eFileLock.  eFileLock
  1878   1870   ** must be either NO_LOCK or SHARED_LOCK.
................................................................................
  1887   1879   ** remove the write lock on a region when a read lock is set.
  1888   1880   */
  1889   1881   static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
  1890   1882     unixFile *pFile = (unixFile*)id;
  1891   1883     unixInodeInfo *pInode;
  1892   1884     struct flock lock;
  1893   1885     int rc = SQLITE_OK;
  1894         -  int wantToClosePending = 0;  /* True to try to close file old descriptors */
  1895   1886   
  1896   1887     assert( pFile );
  1897   1888     OSTRACE(("UNLOCK  %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
  1898   1889         pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
  1899   1890         osGetpid(0)));
  1900   1891   
  1901   1892     assert( eFileLock<=SHARED_LOCK );
................................................................................
  2025   2016   
  2026   2017       /* Decrement the count of locks against this same file.  When the
  2027   2018       ** count reaches zero, close any other file descriptors whose close
  2028   2019       ** was deferred because of outstanding locks.
  2029   2020       */
  2030   2021       pInode->nLock--;
  2031   2022       assert( pInode->nLock>=0 );
  2032         -    if( pInode->nLock==0 && pInode->pUnused!=0 ){
  2033         -      wantToClosePending = 1;
  2034         -    }
         2023  +    if( pInode->nLock==0 ) closePendingFds(pFile);
  2035   2024     }
  2036   2025   
  2037   2026   end_unlock:
  2038   2027     sqlite3_mutex_leave(pInode->pLockMutex);
  2039   2028     if( rc==SQLITE_OK ){
  2040   2029       pFile->eFileLock = eFileLock;
  2041         -    if( wantToClosePending ){
  2042         -      unixEnterMutex();
  2043         -      if( pInode->nLock==0 ) closePendingFds(pFile);
  2044         -      unixLeaveMutex();
  2045         -    }
  2046   2030     }
  2047   2031     return rc;
  2048   2032   }
  2049   2033   
  2050   2034   /*
  2051   2035   ** Lower the locking level on file descriptor pFile to eFileLock.  eFileLock
  2052   2036   ** must be either NO_LOCK or SHARED_LOCK.
................................................................................
  2110   2094   
  2111   2095   /*
  2112   2096   ** Close a file.
  2113   2097   */
  2114   2098   static int unixClose(sqlite3_file *id){
  2115   2099     int rc = SQLITE_OK;
  2116   2100     unixFile *pFile = (unixFile *)id;
         2101  +  unixInodeInfo *pInode = pFile->pInode;
         2102  +
         2103  +  assert( pInode!=0 );
  2117   2104     verifyDbFile(pFile);
  2118   2105     unixUnlock(id, NO_LOCK);
  2119   2106     assert( unixFileMutexNotheld(pFile) );
  2120   2107     unixEnterMutex();
  2121   2108   
  2122   2109     /* unixFile.pInode is always valid here. Otherwise, a different close
  2123   2110     ** routine (e.g. nolockClose()) would be called instead.
  2124   2111     */
  2125   2112     assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
  2126         -  if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
         2113  +  sqlite3_mutex_enter(pInode->pLockMutex);
         2114  +  if( pFile->pInode->nLock ){
  2127   2115       /* If there are outstanding locks, do not actually close the file just
  2128   2116       ** yet because that would clear those locks.  Instead, add the file
  2129   2117       ** descriptor to pInode->pUnused list.  It will be automatically closed 
  2130   2118       ** when the last lock is cleared.
  2131   2119       */
  2132   2120       setPendingFd(pFile);
  2133   2121     }
         2122  +  sqlite3_mutex_leave(pInode->pLockMutex);
  2134   2123     releaseInodeInfo(pFile);
  2135   2124     rc = closeUnixFile(id);
  2136   2125     unixLeaveMutex();
  2137   2126     return rc;
  2138   2127   }
  2139   2128   
  2140   2129   /************** End of the posix advisory lock implementation *****************
................................................................................
  3082   3071   */
  3083   3072   static int afpUnlock(sqlite3_file *id, int eFileLock) {
  3084   3073     int rc = SQLITE_OK;
  3085   3074     unixFile *pFile = (unixFile*)id;
  3086   3075     unixInodeInfo *pInode;
  3087   3076     afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
  3088   3077     int skipShared = 0;
  3089         -  int wantToClosePending = 0;
  3090   3078   #ifdef SQLITE_TEST
  3091   3079     int h = pFile->h;
  3092   3080   #endif
  3093   3081   
  3094   3082     assert( pFile );
  3095   3083     OSTRACE(("UNLOCK  %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
  3096   3084              pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
................................................................................
  3166   3154           pInode->eFileLock = NO_LOCK;
  3167   3155           pFile->eFileLock = NO_LOCK;
  3168   3156         }
  3169   3157       }
  3170   3158       if( rc==SQLITE_OK ){
  3171   3159         pInode->nLock--;
  3172   3160         assert( pInode->nLock>=0 );
  3173         -      if( pInode->nLock==0 && pInode->pUnused!=0 ) wantToClosePending = 1;
         3161  +      if( pInode->nLock==0 ) closePendingFds(pFile);
  3174   3162       }
  3175   3163     }
  3176   3164     
  3177   3165     sqlite3_mutex_leave(pInode->pLockMutex);
  3178   3166     if( rc==SQLITE_OK ){
  3179   3167       pFile->eFileLock = eFileLock;
  3180         -    if( wantToClosePending ){
  3181         -      unixEnterMutex();
  3182         -      if( pInode->nLock==0 ) closePendingFds(pFile);
  3183         -      unixLeaveMutex();
  3184         -    }
  3185   3168     }
  3186   3169     return rc;
  3187   3170   }
  3188   3171   
  3189   3172   /*
  3190   3173   ** Close a file & cleanup AFP specific locking context 
  3191   3174   */
................................................................................
  3192   3175   static int afpClose(sqlite3_file *id) {
  3193   3176     int rc = SQLITE_OK;
  3194   3177     unixFile *pFile = (unixFile*)id;
  3195   3178     assert( id!=0 );
  3196   3179     afpUnlock(id, NO_LOCK);
  3197   3180     assert( unixFileMutexNotheld(pFile) );
  3198   3181     unixEnterMutex();
  3199         -  if( pFile->pInode && pFile->pInode->nLock ){
  3200         -    /* If there are outstanding locks, do not actually close the file just
  3201         -    ** yet because that would clear those locks.  Instead, add the file
  3202         -    ** descriptor to pInode->aPending.  It will be automatically closed when
  3203         -    ** the last lock is cleared.
  3204         -    */
  3205         -    setPendingFd(pFile);
         3182  +  if( pFile->pInode ){
         3183  +    unixInodeInfo *pInode = pFile->pInode;
         3184  +    sqlite3_mutex_enter(pInode->pLockMutex);
         3185  +    if( pFile->pInode->nLock ){
         3186  +      /* If there are outstanding locks, do not actually close the file just
         3187  +      ** yet because that would clear those locks.  Instead, add the file
         3188  +      ** descriptor to pInode->aPending.  It will be automatically closed when
         3189  +      ** the last lock is cleared.
         3190  +      */
         3191  +      setPendingFd(pFile);
         3192  +    }
         3193  +    sqlite3_mutex_leave(pInode->pLockMutex);
  3206   3194     }
  3207   3195     releaseInodeInfo(pFile);
  3208   3196     sqlite3_free(pFile->lockingContext);
  3209   3197     rc = closeUnixFile(id);
  3210   3198     unixLeaveMutex();
  3211   3199     return rc;
  3212   3200   }