/ Check-in [3a3e8eb2]
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:Changes to support medium sector sizes larger than the database page size. (CVS 3701)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3a3e8eb25d8e04cfccc5c0513ed04efcc25d3dbf
User & Date: danielk1977 2007-03-19 11:25:20
Context
2007-03-19
11:54
Fix a comment in btree.c (CVS 3702) check-in: 05700c11 user: drh tags: trunk
11:25
Changes to support medium sector sizes larger than the database page size. (CVS 3701) check-in: 3a3e8eb2 user: danielk1977 tags: trunk
05:54
Add new OS file method to return the sector-size of the underlying storage: sqlite3OsSectorSize() (CVS 3700) check-in: 5752d84d user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.338 2007/03/06 15:53:44 drh Exp $
           12  +** $Id: btree.c,v 1.339 2007/03/19 11:25:20 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
  4027   4027   
  4028   4028     assert( pNewParent!=0 );
  4029   4029     if( pgno==0 ) return SQLITE_OK;
  4030   4030     assert( pBt->pPager!=0 );
  4031   4031     aData = sqlite3pager_lookup(pBt->pPager, pgno);
  4032   4032     if( aData ){
  4033   4033       pThis = (MemPage*)&aData[pBt->pageSize];
  4034         -    assert( pThis->aData==aData );
  4035   4034       if( pThis->isInit ){
         4035  +      assert( pThis->aData==aData );
  4036   4036         if( pThis->pParent!=pNewParent ){
  4037   4037           if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
  4038   4038           pThis->pParent = pNewParent;
  4039   4039           sqlite3pager_ref(pNewParent->aData);
  4040   4040         }
  4041   4041         pThis->idxParent = idx;
  4042   4042       }

Changes to src/pager.c.

    14     14   ** The pager is used to access a database disk file.  It implements
    15     15   ** atomic commit and rollback through the use of a journal file that
    16     16   ** is separate from the database file.  The pager also implements file
    17     17   ** locking to prevent two processes from writing the same database
    18     18   ** file simultaneously, or one process from reading the database while
    19     19   ** another is writing.
    20     20   **
    21         -** @(#) $Id: pager.c,v 1.289 2007/03/19 05:54:49 danielk1977 Exp $
           21  +** @(#) $Id: pager.c,v 1.290 2007/03/19 11:25:20 danielk1977 Exp $
    22     22   */
    23     23   #ifndef SQLITE_OMIT_DISKIO
    24     24   #include "sqliteInt.h"
    25     25   #include "os.h"
    26     26   #include "pager.h"
    27     27   #include <assert.h>
    28     28   #include <string.h>
................................................................................
   281    281     void *pCodecArg;            /* First argument to xCodec() */
   282    282     int nHash;                  /* Size of the pager hash table */
   283    283     PgHdr **aHash;              /* Hash table to map page number to PgHdr */
   284    284   #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   285    285     Pager *pNext;               /* Linked list of pagers in this thread */
   286    286   #endif
   287    287     char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
          288  +  int doNotSync;
   288    289   };
   289    290   
   290    291   /*
   291    292   ** If SQLITE_TEST is defined then increment the variable given in
   292    293   ** the argument
   293    294   */
   294    295   #ifdef SQLITE_TEST
................................................................................
   624    625   ** - 4 bytes: Initial database page count.
   625    626   ** - 4 bytes: Sector size used by the process that wrote this journal.
   626    627   ** 
   627    628   ** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space.
   628    629   */
   629    630   static int writeJournalHdr(Pager *pPager){
   630    631     char zHeader[sizeof(aJournalMagic)+16];
          632  +  int rc;
   631    633   
   632         -  int rc = seekJournalHdr(pPager);
   633         -  if( rc ) return rc;
   634         -
   635         -  pPager->journalHdr = pPager->journalOff;
   636    634     if( pPager->stmtHdrOff==0 ){
   637         -    pPager->stmtHdrOff = pPager->journalHdr;
          635  +    pPager->stmtHdrOff = pPager->journalOff;
   638    636     }
          637  +
          638  +  rc = seekJournalHdr(pPager);
          639  +  if( rc ) return rc;
          640  +
          641  +  pPager->journalHdr = pPager->journalOff;
   639    642     pPager->journalOff += JOURNAL_HDR_SZ(pPager);
   640    643   
   641    644     /* FIX ME: 
   642    645     **
   643    646     ** Possibly for a pager not in no-sync mode, the journal magic should not
   644    647     ** be written until nRec is filled in as part of next syncJournal(). 
   645    648     **
................................................................................
  1418   1421       i64 os_szJ;
  1419   1422       rc = sqlite3OsFileSize(pPager->jfd, &os_szJ);
  1420   1423       if( rc!=SQLITE_OK ) return rc;
  1421   1424       assert( szJ==os_szJ );
  1422   1425     }
  1423   1426   #endif
  1424   1427   
  1425         -  /* Set hdrOff to be the offset to the first journal header written
  1426         -  ** this statement transaction, or the end of the file if no journal
         1428  +  /* Set hdrOff to be the offset just after the end of the last journal
         1429  +  ** page written before the first journal-header for this statement
         1430  +  ** transaction was written, or the end of the file if no journal
  1427   1431     ** header was written.
  1428   1432     */
  1429   1433     hdrOff = pPager->stmtHdrOff;
  1430   1434     assert( pPager->fullSync || !hdrOff );
  1431   1435     if( !hdrOff ){
  1432   1436       hdrOff = szJ;
  1433   1437     }
................................................................................
  1467   1471     */
  1468   1472     rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize);
  1469   1473     if( rc!=SQLITE_OK ){
  1470   1474       goto end_stmt_playback;
  1471   1475     }
  1472   1476     pPager->journalOff = pPager->stmtJSize;
  1473   1477     pPager->cksumInit = pPager->stmtCksum;
  1474         -  assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) );
  1475         -  while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){
         1478  +  while( pPager->journalOff < hdrOff ){
  1476   1479       rc = pager_playback_one_page(pPager, pPager->jfd, 1);
  1477   1480       assert( rc!=SQLITE_DONE );
  1478   1481       if( rc!=SQLITE_OK ) goto end_stmt_playback;
  1479   1482     }
  1480   1483   
  1481   1484     while( pPager->journalOff < szJ ){
  1482   1485       u32 nJRec;         /* Number of Journal Records */
................................................................................
  2475   2478         ** journal file. This is done to avoid ever modifying a journal
  2476   2479         ** header that is involved in the rollback of pages that have
  2477   2480         ** already been written to the database (in case the header is
  2478   2481         ** trashed when the nRec field is updated).
  2479   2482         */
  2480   2483         pPager->nRec = 0;
  2481   2484         assert( pPager->journalOff > 0 );
         2485  +      assert( pPager->doNotSync==0 );
  2482   2486         rc = writeJournalHdr(pPager);
  2483   2487         if( rc!=0 ){
  2484   2488           return rc;
  2485   2489         }
  2486   2490       }
  2487   2491       pPg = pPager->pFirst;
  2488   2492     }
................................................................................
  2727   2731         pPager->state = PAGER_SHARED;
  2728   2732       }
  2729   2733     }
  2730   2734     if( pPg==0 ){
  2731   2735       /* The requested page is not in the page cache. */
  2732   2736       int h;
  2733   2737       TEST_INCR(pPager->nMiss);
  2734         -    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
         2738  +    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ||
         2739  +        (pPager->pFirstSynced==0 && pPager->doNotSync)
         2740  +    ){
  2735   2741         /* Create a new page */
  2736   2742         if( pPager->nPage>=pPager->nHash ){
  2737   2743           pager_resize_hash_table(pPager,
  2738   2744              pPager->nHash<256 ? 256 : pPager->nHash*2);
  2739   2745           if( pPager->nHash==0 ){
  2740   2746             return SQLITE_NOMEM;
  2741   2747           }
................................................................................
  3100   3106   **
  3101   3107   ** If the journal file could not be written because the disk is full,
  3102   3108   ** then this routine returns SQLITE_FULL and does an immediate rollback.
  3103   3109   ** All subsequent write attempts also return SQLITE_FULL until there
  3104   3110   ** is a call to sqlite3pager_commit() or sqlite3pager_rollback() to
  3105   3111   ** reset.
  3106   3112   */
  3107         -int sqlite3pager_write(void *pData){
         3113  +static int pager_write(void *pData){
  3108   3114     PgHdr *pPg = DATA_TO_PGHDR(pData);
  3109   3115     Pager *pPager = pPg->pPager;
  3110   3116     int rc = SQLITE_OK;
  3111   3117   
  3112   3118     /* Check for errors
  3113   3119     */
  3114   3120     if( pPager->errCode ){ 
................................................................................
  3253   3259       pPager->dbSize = pPg->pgno;
  3254   3260       if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
  3255   3261         pPager->dbSize++;
  3256   3262       }
  3257   3263     }
  3258   3264     return rc;
  3259   3265   }
         3266  +
         3267  +/*
         3268  +** This function is used to mark a data-page as writable. It uses 
         3269  +** pager_write() to open a journal file (if it is not already open)
         3270  +** and write the page *pData to the journal.
         3271  +**
         3272  +** The difference between this function and pager_write() is that this
         3273  +** function also deals with the special case where 2 or more pages
         3274  +** fit on a single disk sector. In this case all co-resident pages
         3275  +** must have been written to the journal file before returning.
         3276  +*/
         3277  +int sqlite3pager_write(void *pData){
         3278  +  int rc = SQLITE_OK;
         3279  +
         3280  +  PgHdr *pPg = DATA_TO_PGHDR(pData);
         3281  +  Pager *pPager = pPg->pPager;
         3282  +  Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
         3283  +
         3284  +  if( !MEMDB && nPagePerSector>1 ){
         3285  +    Pgno nPageCount;          /* Total number of pages in database file */
         3286  +    Pgno pg1;                 /* First page of the sector pPg is located on. */
         3287  +    int nPage;                /* Number of pages starting at pg1 to journal */
         3288  +    int ii;
         3289  +
         3290  +    /* Set the doNotSync flag to 1. This is because we cannot allow a journal
         3291  +    ** header to be written between the pages journaled by this function.
         3292  +    */
         3293  +    assert( pPager->doNotSync==0 );
         3294  +    pPager->doNotSync = 1;
         3295  +
         3296  +    /* This trick assumes that both the page-size and sector-size are
         3297  +    ** an integer power of 2. It sets variable pg1 to the identifier
         3298  +    ** of the first page of the sector pPg is located on.
         3299  +    */
         3300  +    pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
         3301  +
         3302  +    nPageCount = sqlite3pager_pagecount(pPager);
         3303  +    if( pPg->pgno>nPageCount ){
         3304  +      nPage = (pPg->pgno - pg1)+1;
         3305  +    }else if( (pg1+nPagePerSector-1)>nPageCount ){
         3306  +      nPage = nPageCount+1-pg1;
         3307  +    }else{
         3308  +      nPage = nPagePerSector;
         3309  +    }
         3310  +    assert(nPage>0);
         3311  +    assert(pg1<=pPg->pgno);
         3312  +    assert((pg1+nPage)>pPg->pgno);
         3313  +
         3314  +    for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
         3315  +      Pgno pg = pg1+ii;
         3316  +      if( !pPager->aInJournal || pg==pPg->pgno || 
         3317  +          pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7)))
         3318  +      ) {
         3319  +        if( pg!=PAGER_MJ_PGNO(pPager) ){
         3320  +          void *pPage;
         3321  +          rc = sqlite3pager_get(pPager, pg, &pPage);
         3322  +          if( rc==SQLITE_OK ){
         3323  +            rc = pager_write(pPage);
         3324  +            sqlite3pager_unref(pPage);
         3325  +          }
         3326  +        }
         3327  +      }
         3328  +    }
         3329  +
         3330  +    assert( pPager->doNotSync==1 );
         3331  +    pPager->doNotSync = 0;
         3332  +  }else{
         3333  +    rc = pager_write(pData);
         3334  +  }
         3335  +  return rc;
         3336  +}
  3260   3337   
  3261   3338   /*
  3262   3339   ** Return TRUE if the page given in the argument was previously passed
  3263   3340   ** to sqlite3pager_write().  In other words, return TRUE if it is ok
  3264   3341   ** to change the content of the page.
  3265   3342   */
  3266   3343   #ifndef NDEBUG