/ Check-in [a38858a2]
Login

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

Overview
Comment:Avoid running recovery while there is another read/write client.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | server-edition
Files: files | file ages | folders
SHA3-256: a38858a24c6edaa05966b7e158e603bcbde8b05c6233e3bb005cfb32bc91ea06
User & Date: dan 2017-05-13 19:07:10
Context
2017-05-15
19:32
Avoid writer starvation by adding a RESERVED state to page locks. check-in: 9b7f8024 user: dan tags: server-edition
2017-05-13
19:07
Avoid running recovery while there is another read/write client. check-in: a38858a2 user: dan tags: server-edition
2017-05-12
18:52
Require exclusive access to the db to wrap the wal file. Have "PRAGMA wal_checkpoint = restart" block for this. check-in: cbf44ed9 user: dan tags: server-edition
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/server.c.

   508    508         v = *pSlot;
   509    509       }
   510    510     }
   511    511   
   512    512   server_lock_out:
   513    513     return rc;
   514    514   }
          515  +
          516  +int sqlite3ServerHasLock(Server *p, Pgno pgno, int bWrite){
          517  +  u32 v = *serverPageLockSlot(p, pgno);
          518  +  if( bWrite ){
          519  +    return (v>>HMA_CLIENT_SLOTS)==(p->iClient+1);
          520  +  }
          521  +  return (v & (1 << p->iClient))!=0;
          522  +}
   515    523   
   516    524   #endif /* ifdef SQLITE_SERVER_EDITION */

Changes to src/server.h.

    24     24   void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd);
    25     25   
    26     26   int sqlite3ServerBegin(Server *p);
    27     27   int sqlite3ServerEnd(Server *p);
    28     28   int sqlite3ServerReleaseWriteLocks(Server *p);
    29     29   
    30     30   int sqlite3ServerLock(Server *p, Pgno pgno, int bWrite, int bBlock);
           31  +
           32  +int sqlite3ServerHasLock(Server *p, Pgno pgno, int bWrite);
    31     33   
    32     34   #endif /* SQLITE_SERVER_H */
    33     35   
    34     36   #endif /* SQLITE_SERVER_EDITION */

Changes to src/wal.c.

  2066   2066       testcase( pWal->szPage<=32768 );
  2067   2067       testcase( pWal->szPage>=65536 );
  2068   2068     }
  2069   2069   
  2070   2070     /* The header was successfully read. Return zero. */
  2071   2071     return 0;
  2072   2072   }
         2073  +
         2074  +static int walIndexWriteLock(Wal *pWal){
         2075  +  if( walIsServer(pWal) ){
         2076  +    return sqlite3ServerLock(pWal->pServer, 0, 1, 0);
         2077  +  }else{
         2078  +    return walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
         2079  +  }
         2080  +}
  2073   2081   
  2074   2082   /*
  2075   2083   ** Read the wal-index header from the wal-index and into pWal->hdr.
  2076   2084   ** If the wal-header appears to be corrupt, try to reconstruct the
  2077   2085   ** wal-index from the WAL before returning.
  2078   2086   **
  2079   2087   ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
................................................................................
  2107   2115   
  2108   2116     /* If the first attempt failed, it might have been due to a race
  2109   2117     ** with a writer.  So get a WRITE lock and try again.
  2110   2118     */
  2111   2119     assert( badHdr==0 || pWal->writeLock==0 );
  2112   2120     if( badHdr ){
  2113   2121       if( pWal->readOnly & WAL_SHM_RDONLY ){
         2122  +      assert( walIsServer(pWal)==0 );
  2114   2123         if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
  2115   2124           walUnlockShared(pWal, WAL_WRITE_LOCK);
  2116   2125           rc = SQLITE_READONLY_RECOVERY;
  2117   2126         }
  2118         -    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
         2127  +    }else if( SQLITE_OK==(rc = walIndexWriteLock(pWal)) ){
  2119   2128         pWal->writeLock = 1;
  2120   2129         if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
  2121   2130           badHdr = walIndexTryHdr(pWal, pChanged);
  2122   2131           if( badHdr ){
  2123   2132             /* If the wal-index header is still malformed even while holding
  2124   2133             ** a WRITE lock, it can only mean that the header is corrupted and
  2125   2134             ** needs to be reconstructed.  So run recovery to do exactly that.
  2126   2135             */
  2127   2136             rc = walIndexRecover(pWal);
  2128   2137             *pChanged = 1;
  2129   2138           }
  2130   2139         }
  2131   2140         pWal->writeLock = 0;
  2132         -      walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
         2141  +      if( walIsServer(pWal)==0 ){
         2142  +        walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
         2143  +      }
  2133   2144       }
  2134   2145     }
  2135   2146   
  2136   2147     /* If the header is read successfully, check the version number to make
  2137   2148     ** sure the wal-index was not constructed with some future format that
  2138   2149     ** this version of SQLite cannot understand.
  2139   2150     */
................................................................................
  2609   2620     u32 iLast = pWal->hdr.mxFrame;  /* Last page in WAL for this reader */
  2610   2621     int iHash;                      /* Used to loop through N hash tables */
  2611   2622     int iMinHash;
  2612   2623   
  2613   2624     /* This routine is only be called from within a read transaction. */
  2614   2625     assert( walIsServer(pWal) || pWal->readLock>=0 || pWal->lockError );
  2615   2626   
         2627  +  assert( walIsServer(pWal)==0 || pWal->writeLock==0 
         2628  +       || sqlite3ServerHasLock(pWal->pServer, 0, 1) 
         2629  +  );
  2616   2630     if( walIsServer(pWal) && pWal->writeLock==0 ){
  2617   2631       /* A server mode connection must read from the most recent snapshot. */
  2618   2632       iLast = walIndexHdr(pWal)->mxFrame;
  2619   2633     }
  2620   2634   
  2621   2635     /* If the "last page" field of the wal-index header snapshot is 0, then
  2622   2636     ** no data will be read from the wal under any circumstances. Return early
................................................................................
  3105   3119         pWal->writeLock = 1;
  3106   3120         rc = walIndexTryHdr(pWal, &bDummy);
  3107   3121       }
  3108   3122       if( rc!=SQLITE_OK ){
  3109   3123         return rc;
  3110   3124       }
  3111   3125     }
         3126  +  assert( walIsServer(pWal)==0 || sqlite3ServerHasLock(pWal->pServer, 0, 1) );
  3112   3127   
  3113   3128     /* If this frame set completes a transaction, then nTruncate>0.  If
  3114   3129     ** nTruncate==0 then this frame set does not complete the transaction. */
  3115   3130     assert( (isCommit!=0)==(nTruncate!=0) );
  3116   3131   
  3117   3132   #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
  3118   3133     { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}