SQLite4
Check-in [4418f901c9]
Not logged in

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

Overview
Comment:Fix various issues in lsm_file.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4418f901c97d18d2c444555682d13e6f3093ff02
User & Date: dan 2013-03-08 20:47:16
Context
2013-03-09
19:04
Fix further small issues in lsm_file.c. check-in: 38ef349463 user: dan tags: trunk
2013-03-08
20:47
Fix various issues in lsm_file.c. check-in: 4418f901c9 user: dan tags: trunk
09:59
Merge prefix-mmap branch with trunk. This allows lsm to memory map a prefix of the database file and use regular read and write system calls to access the remainder. check-in: 02954a5b8d user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/lsmInt.h.

   738    738   int lsmFsWriteLog(FileSystem *pFS, i64 iOff, LsmString *pStr);
   739    739   int lsmFsSyncLog(FileSystem *pFS);
   740    740   int lsmFsReadLog(FileSystem *pFS, i64 iOff, int nRead, LsmString *pStr);
   741    741   int lsmFsTruncateLog(FileSystem *pFS, i64 nByte);
   742    742   int lsmFsTruncateDb(FileSystem *pFS, i64 nByte);
   743    743   int lsmFsCloseAndDeleteLog(FileSystem *pFS);
   744    744   
   745         -void lsmFsDeferClose(FileSystem *pFS, LsmFile **pp);
          745  +LsmFile *lsmFsDeferClose(FileSystem *pFS);
   746    746   
   747    747   /* And to sync the db file */
   748    748   int lsmFsSyncDb(FileSystem *, int);
   749    749   
   750    750   void lsmFsFlushWaiting(FileSystem *, int *);
   751    751   
   752    752   /* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */
................................................................................
   764    764   void lsmEnvShmUnmap(lsm_env *, lsm_file *, int);
   765    765   
   766    766   void lsmEnvSleep(lsm_env *, int);
   767    767   
   768    768   int lsmFsReadSyncedId(lsm_db *db, int, i64 *piVal);
   769    769   
   770    770   int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, Pgno, int *);
   771         -Pgno lsmFsRedirectPage(FileSystem *, Redirect *, Pgno);
   772    771   
   773    772   void lsmFsPurgeCache(FileSystem *);
   774    773   
   775    774   /*
   776    775   ** End of functions from "lsm_file.c".
   777    776   **************************************************************************/
   778    777   

Changes to src/lsm_file.c.

    35     35   **   while writing to a meta page there is no risk of damage to the other
    36     36   **   meta page or any other part of the database file. TODO: This may need
    37     37   **   to be revisited.
    38     38   **
    39     39   ** Blocks:
    40     40   **
    41     41   **   The database file is also divided into blocks. The default block size is
    42         -**   2MB. When writing to the database file, an attempt is made to write data
           42  +**   1MB. When writing to the database file, an attempt is made to write data
    43     43   **   in contiguous block-sized chunks.
    44     44   **
    45     45   **   The first and last page on each block are special in that they are 4 
    46     46   **   bytes smaller than all other pages. This is because the last four bytes 
    47     47   **   of space on the first and last pages of each block are reserved for
    48     48   **   pointers to other blocks (i.e. a 32-bit block number).
    49     49   **
................................................................................
   190    190   **   assigned page number (N+2). To avoid writing page (N+2) before page 
   191    191   **   (N+1), the recently completed b-tree page is held in the singly linked
   192    192   **   list headed by pWaiting until page (N+1) has been written. 
   193    193   **
   194    194   **   Function lsmFsFlushWaiting() is responsible for eventually writing 
   195    195   **   waiting pages to disk.
   196    196   **
   197         -**
   198    197   ** apHash/nHash:
   199    198   **   Hash table used to store all Page objects that carry malloc'd arrays,
   200    199   **   except those b-tree pages that have not yet been assigned page numbers.
   201    200   **   Once they have been assigned page numbers - they are added to this
   202    201   **   hash table.
   203    202   **
   204    203   **   Hash table overflow chains are connected using the Page.pHashNext
................................................................................
   310    309   ** Number of pgsz byte pages omitted from the start of block 1. The start
   311    310   ** of block 1 contains two 4096 byte meta pages (8192 bytes in total).
   312    311   */
   313    312   #define BLOCK1_HDR_SIZE(pgsz)  LSM_MAX(1, 8192/(pgsz))
   314    313   
   315    314   /*
   316    315   ** If NDEBUG is not defined, set a breakpoint in function lsmIoerrBkpt()
   317         -** to catch IO errors. 
          316  +** to catch IO errors (any error returned by a VFS method). 
   318    317   */
   319    318   #ifndef NDEBUG
   320    319   static void lsmIoerrBkpt(){
   321    320     static int nErr = 0;
   322    321     nErr++;
   323    322   }
   324    323   static int IOERR_WRAPPER(int rc){
................................................................................
   367    366   **     lsmEnvTruncate()
   368    367   **     lsmEnvUnlink()
   369    368   **     lsmEnvRemap()
   370    369   */
   371    370   int lsmEnvOpen(lsm_env *pEnv, const char *zFile, int flags, lsm_file **ppNew){
   372    371     return pEnv->xOpen(pEnv, zFile, flags, ppNew);
   373    372   }
          373  +
   374    374   static int lsmEnvRead(
   375    375     lsm_env *pEnv, 
   376    376     lsm_file *pFile, 
   377    377     lsm_i64 iOff, 
   378    378     void *pRead, 
   379    379     int nRead
   380    380   ){
   381    381     return IOERR_WRAPPER( pEnv->xRead(pFile, iOff, pRead, nRead) );
   382    382   }
          383  +
   383    384   static int lsmEnvWrite(
   384    385     lsm_env *pEnv, 
   385    386     lsm_file *pFile, 
   386    387     lsm_i64 iOff, 
   387    388     const void *pWrite, 
   388    389     int nWrite
   389    390   ){
   390    391     return IOERR_WRAPPER( pEnv->xWrite(pFile, iOff, (void *)pWrite, nWrite) );
   391    392   }
          393  +
   392    394   static int lsmEnvSync(lsm_env *pEnv, lsm_file *pFile){
   393    395     return IOERR_WRAPPER( pEnv->xSync(pFile) );
   394    396   }
          397  +
   395    398   static int lsmEnvSectorSize(lsm_env *pEnv, lsm_file *pFile){
   396    399     return pEnv->xSectorSize(pFile);
   397    400   }
          401  +
   398    402   int lsmEnvClose(lsm_env *pEnv, lsm_file *pFile){
   399    403     return IOERR_WRAPPER( pEnv->xClose(pFile) );
   400    404   }
          405  +
   401    406   static int lsmEnvTruncate(lsm_env *pEnv, lsm_file *pFile, lsm_i64 nByte){
   402    407     return IOERR_WRAPPER( pEnv->xTruncate(pFile, nByte) );
   403    408   }
          409  +
   404    410   static int lsmEnvUnlink(lsm_env *pEnv, const char *zDel){
   405    411     return IOERR_WRAPPER( pEnv->xUnlink(pEnv, zDel) );
   406    412   }
          413  +
   407    414   static int lsmEnvRemap(
   408    415     lsm_env *pEnv, 
   409    416     lsm_file *pFile, 
   410    417     i64 szMin,
   411    418     void **ppMap,
   412    419     i64 *pszMap
   413    420   ){
................................................................................
   579    586       }
   580    587     }
   581    588   
   582    589     if( pbOpen ) *pbOpen = (pFS->fdLog!=0);
   583    590     return rc;
   584    591   }
   585    592   
          593  +/*
          594  +** Close the log file, if it is open.
          595  +*/
   586    596   void lsmFsCloseLog(lsm_db *db){
   587    597     FileSystem *pFS = db->pFS;
   588    598     if( pFS->fdLog ){
   589    599       lsmEnvClose(pFS->pEnv, pFS->fdLog);
   590    600       pFS->fdLog = 0;
   591    601     }
   592    602   }
   593    603   
   594    604   /*
   595         -** Open a connection to a database stored within the file-system (the
   596         -** "system of files").
          605  +** Open a connection to a database stored within the file-system.
   597    606   **
   598    607   ** If parameter bReadonly is true, then open a read-only file-descriptor
   599    608   ** on the database file. It is possible that bReadonly will be false even
   600    609   ** if the user requested that pDb be opened read-only. This is because the
   601    610   ** file-descriptor may later on be recycled by a read-write connection.
   602    611   ** If the db file can be opened for read-write access, it always is. Parameter
   603    612   ** bReadonly is only ever true if it has already been determined that the
   604    613   ** db can only be opened for read-only access.
          614  +**
          615  +** Return LSM_OK if successful or an lsm error code otherwise.
   605    616   */
   606    617   int lsmFsOpen(
   607    618     lsm_db *pDb,                    /* Database connection to open fd for */
   608    619     const char *zDb,                /* Full path to database file */
   609    620     int bReadonly                   /* True to open db file read-only */
   610    621   ){
   611    622     FileSystem *pFS;
................................................................................
   721    732         pFS->nMapLimit = 0;
   722    733       }else{
   723    734         pFS->pCompress = 0;
   724    735         if( db->iMmap==1 ){
   725    736           /* Unlimited */
   726    737           pFS->nMapLimit = (i64)1 << 60;
   727    738         }else{
          739  +        /* iMmap is a limit in KB. Set nMapLimit to the same value in bytes. */
   728    740           pFS->nMapLimit = (i64)db->iMmap * 1024;
   729    741         }
   730    742       }
   731    743     }
   732    744   
   733    745     return LSM_OK;
   734    746   }
................................................................................
   756    768       lsmFree(pEnv, pFS->apHash);
   757    769       lsmFree(pEnv, pFS->aIBuffer);
   758    770       lsmFree(pEnv, pFS->aOBuffer);
   759    771       lsmFree(pEnv, pFS);
   760    772     }
   761    773   }
   762    774   
   763         -void lsmFsDeferClose(FileSystem *pFS, LsmFile **pp){
          775  +/*
          776  +** This function is called when closing a database handle (i.e. lsm_close()) 
          777  +** if there exist other connections to the same database within this process.
          778  +** In that case the file-descriptor open on the database file is not closed
          779  +** when the FileSystem object is destroyed, as this would cause any POSIX
          780  +** locks held by the other connections to be silently dropped (see "man close"
          781  +** for details). Instead, the file-descriptor is stored in a list by the
          782  +** lsm_shared.c module until it is either closed or reused.
          783  +**
          784  +** This function returns a pointer to an object that can be linked into
          785  +** the list described above. The returned object now 'owns' the database
          786  +** file descriptr, so that when the FileSystem object is destroyed, it
          787  +** will not be closed. 
          788  +**
          789  +** This function may be called at most once in the life-time of a 
          790  +** FileSystem object. The results of any operations involving the database 
          791  +** file descriptor are undefined once this function has been called.
          792  +**
          793  +** None of this is necessary on non-POSIX systems. But we do it anyway in
          794  +** the name of using as similar code as possible on all platforms.
          795  +*/
          796  +LsmFile *lsmFsDeferClose(FileSystem *pFS){
   764    797     LsmFile *p = pFS->pLsmFile;
   765    798     assert( p->pNext==0 );
   766    799     p->pFile = pFS->fdDb;
   767    800     pFS->fdDb = 0;
   768    801     pFS->pLsmFile = 0;
   769         -  *pp = p;
          802  +  return p;
   770    803   }
   771    804   
   772    805   /*
   773    806   ** Allocate a buffer and populate it with the output of the xFileid() 
   774    807   ** method of the database file handle. If successful, set *ppId to point 
   775    808   ** to the buffer and *pnId to the number of bytes in the buffer and return
   776    809   ** LSM_OK. Otherwise, set *ppId and *pnId to zero and return an LSM
................................................................................
   819    852   */
   820    853   void lsmFsSetPageSize(FileSystem *pFS, int nPgsz){
   821    854     pFS->nPagesize = nPgsz;
   822    855     pFS->nCacheMax = 2048*1024 / pFS->nPagesize;
   823    856   }
   824    857   
   825    858   /*
   826         -** Configure the block-size used by this file-system. Actual pages may be 
   827         -** smaller or larger than this value.
          859  +** Configure the block-size used by this file-system. 
   828    860   */
   829    861   void lsmFsSetBlockSize(FileSystem *pFS, int nBlocksize){
   830    862     pFS->nBlocksize = nBlocksize;
   831    863   }
   832    864   
   833    865   /*
   834    866   ** Return the page number of the first page on block iBlock. Blocks are
................................................................................
   907    939     assert( !pFS->pCompress );
   908    940     return ( (iPg % nPagePerBlock)==1
   909    941           || (iPg<nPagePerBlock && iPg==fsFirstPageOnBlock(pFS, 1))
   910    942     );
   911    943   }
   912    944   
   913    945   /*
   914         -** Given a page reference, return a pointer to the in-memory buffer of the
          946  +** Given a page reference, return a pointer to the buffer containing the 
   915    947   ** pages contents. If parameter pnData is not NULL, set *pnData to the size
   916    948   ** of the buffer in bytes before returning.
   917    949   */
   918    950   u8 *lsmFsPageData(Page *pPage, int *pnData){
   919    951     if( pnData ){
   920    952       *pnData = pPage->nData;
   921    953     }
................................................................................
   963    995     }else{
   964    996       pFS->pLruFirst = pPg;
   965    997     }
   966    998     pFS->pLruLast = pPg;
   967    999   }
   968   1000   
   969   1001   /*
   970         -** Remove page pPg from the hash table.
         1002  +** Page pPg is currently stored in the apHash/nHash hash table. Remove it.
   971   1003   */
   972   1004   static void fsPageRemoveFromHash(FileSystem *pFS, Page *pPg){
   973   1005     int iHash;
   974   1006     Page **pp;
   975   1007   
   976   1008     iHash = fsHashKey(pFS->nHash, pPg->iPg);
   977   1009     for(pp=&pFS->apHash[iHash]; *pp!=pPg; pp=&(*pp)->pHashNext);
   978   1010     *pp = pPg->pHashNext;
   979   1011     pPg->pHashNext = 0;
   980   1012   }
   981   1013   
         1014  +/*
         1015  +** Free a Page object allocated by fsPageBuffer().
         1016  +*/
   982   1017   static void fsPageBufferFree(Page *pPg){
   983   1018     pPg->pFS->nCacheAlloc--;
   984   1019     lsmFree(pPg->pFS->pEnv, pPg->aData);
   985   1020     lsmFree(pPg->pFS->pEnv, pPg);
   986   1021   }
   987   1022   
   988   1023   
................................................................................
  1032   1067   static int fsPageBuffer(
  1033   1068     FileSystem *pFS, 
  1034   1069     Page **ppOut
  1035   1070   ){
  1036   1071     int rc = LSM_OK;
  1037   1072     Page *pPage = 0;
  1038   1073     if( pFS->pLruFirst==0 || pFS->nCacheAlloc<pFS->nCacheMax ){
         1074  +    /* Allocate a new Page object */
  1039   1075       pPage = lsmMallocZero(pFS->pEnv, sizeof(Page));
  1040   1076       if( !pPage ){
  1041   1077         rc = LSM_NOMEM_BKPT;
  1042   1078       }else{
  1043   1079         pPage->aData = (u8 *)lsmMalloc(pFS->pEnv, pFS->nPagesize);
  1044   1080         if( !pPage->aData ){
  1045   1081           lsmFree(pFS->pEnv, pPage);
  1046   1082           rc = LSM_NOMEM_BKPT;
  1047   1083           pPage = 0;
         1084  +      }else{
         1085  +        pFS->nCacheAlloc++;
  1048   1086         }
  1049         -      pFS->nCacheAlloc++;
  1050   1087       }
  1051   1088     }else{
         1089  +    /* Reuse an existing Page object */
  1052   1090       u8 *aData;
  1053   1091       pPage = pFS->pLruFirst;
  1054   1092       aData = pPage->aData;
  1055   1093       fsPageRemoveFromLru(pFS, pPage);
  1056   1094       fsPageRemoveFromHash(pFS, pPage);
  1057   1095   
  1058   1096       memset(pPage, 0, sizeof(Page));
................................................................................
  1062   1100     if( pPage ){
  1063   1101       pPage->flags = PAGE_FREE;
  1064   1102     }
  1065   1103     *ppOut = pPage;
  1066   1104     return rc;
  1067   1105   }
  1068   1106   
         1107  +/*
         1108  +** Assuming *pRc is initially LSM_OK, attempt to ensure that the 
         1109  +** memory-mapped region is at least iSz bytes in size. If it is not already,
         1110  +** iSz bytes in size, extend it and update the pointers associated with any
         1111  +** outstanding Page objects.
         1112  +**
         1113  +** If *pRc is not LSM_OK when this function is called, it is a no-op. 
         1114  +** Otherwise, *pRc is set to an lsm error code if an error occurs, or
         1115  +** left unmodified otherwise.
         1116  +**
         1117  +** This function is never called in compressed database mode.
         1118  +*/
  1069   1119   static void fsGrowMapping(
  1070         -  FileSystem *pFS,
  1071         -  i64 iSz,
  1072         -  int *pRc
         1120  +  FileSystem *pFS,                /* File system object */
         1121  +  i64 iSz,                        /* Minimum size to extend mapping to */
         1122  +  int *pRc                        /* IN/OUT: Error code */
  1073   1123   ){
  1074         -  /* This function won't work with compressed databases yet. */
  1075   1124     assert( pFS->pCompress==0 );
  1076   1125     assert( PAGE_HASPREV==4 );
  1077   1126   
  1078   1127     if( *pRc==LSM_OK && iSz>pFS->nMap ){
  1079   1128       int rc;
  1080   1129       u8 *aOld = pFS->pMap;
  1081   1130       rc = lsmEnvRemap(pFS->pEnv, pFS->fdDb, iSz, &pFS->pMap, &pFS->nMap);
................................................................................
  1087   1136         }
  1088   1137         lsmSortedRemap(pFS->pDb);
  1089   1138       }
  1090   1139       *pRc = rc;
  1091   1140     }
  1092   1141   }
  1093   1142   
  1094         -
  1095   1143   /*
  1096   1144   ** fsync() the database file.
  1097   1145   */
  1098   1146   int lsmFsSyncDb(FileSystem *pFS, int nBlock){
  1099         -#if 0
  1100         -  if( nBlock && pFS->bUseMmap ){
  1101         -    int rc = LSM_OK;
  1102         -    i64 nMin = (i64)nBlock * (i64)pFS->nBlocksize;
  1103         -    fsGrowMapping(pFS, nMin, &rc);
  1104         -    if( rc!=LSM_OK ) return rc;
  1105         -  }
  1106         -#endif
  1107   1147     return lsmEnvSync(pFS->pEnv, pFS->fdDb);
  1108   1148   }
  1109   1149   
  1110         -static int fsPageGet(FileSystem *, Segment *, Pgno, int, Page **, int *);
  1111         -
         1150  +/*
         1151  +** If block iBlk has been redirected according to the redirections in the
         1152  +** object passed as the first argument, return the destination block to
         1153  +** which it is redirected. Otherwise, return a copy of iBlk.
         1154  +*/
  1112   1155   static int fsRedirectBlock(Redirect *p, int iBlk){
  1113   1156     if( p ){
  1114   1157       int i;
  1115   1158       for(i=0; i<p->n; i++){
  1116   1159         if( iBlk==p->a[i].iFrom ) return p->a[i].iTo;
  1117   1160       }
  1118   1161     }
  1119   1162     assert( iBlk!=0 );
  1120   1163     return iBlk;
  1121   1164   }
  1122   1165   
  1123         -Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
         1166  +/*
         1167  +** If page iPg has been redirected according to the redirections in the
         1168  +** object passed as the second argument, return the destination page to
         1169  +** which it is redirected. Otherwise, return a copy of iPg.
         1170  +*/
         1171  +static Pgno fsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
  1124   1172     Pgno iReal = iPg;
  1125   1173   
  1126   1174     if( pRedir ){
  1127   1175       const int nPagePerBlock = (
  1128   1176           pFS->pCompress ? pFS->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
  1129   1177       );
  1130   1178       int iBlk = fsPageToBlock(pFS, iPg);
................................................................................
  1143   1191       }
  1144   1192     }
  1145   1193   
  1146   1194     assert( iReal!=0 );
  1147   1195     return iReal;
  1148   1196   }
  1149   1197   
         1198  +/* Required by the circular fsBlockNext<->fsPageGet dependency. */
         1199  +static int fsPageGet(FileSystem *, Segment *, Pgno, int, Page **, int *);
         1200  +
  1150   1201   /*
  1151   1202   ** Parameter iBlock is a database file block. This function reads the value 
  1152   1203   ** stored in the blocks "next block" pointer and stores it in *piNext.
  1153   1204   ** LSM_OK is returned if everything is successful, or an LSM error code
  1154   1205   ** otherwise.
  1155   1206   */
  1156   1207   static int fsBlockNext(
................................................................................
  1198   1249   ** Return the page number of the last page on the same block as page iPg.
  1199   1250   */
  1200   1251   Pgno fsLastPageOnPagesBlock(FileSystem *pFS, Pgno iPg){
  1201   1252     return fsLastPageOnBlock(pFS, fsPageToBlock(pFS, iPg));
  1202   1253   }
  1203   1254   
  1204   1255   /*
         1256  +** Read nData bytes of data from offset iOff of the database file into
         1257  +** buffer aData. If this means reading past the end of a block, follow
         1258  +** the block pointer to the next block and continue reading.
         1259  +**
         1260  +** Offset iOff is an absolute offset - not subject to any block redirection.
         1261  +** However any block pointer followed is. Use pSeg->pRedirect in this case.
         1262  +**
  1205   1263   ** This function is only called in compressed database mode.
  1206   1264   */
  1207   1265   static int fsReadData(
  1208   1266     FileSystem *pFS,                /* File-system handle */
  1209   1267     Segment *pSeg,                  /* Block redirection */
  1210   1268     i64 iOff,                       /* Read data from this offset */
  1211   1269     u8 *aData,                      /* Buffer to read data into */
................................................................................
  1278   1336     nByte  = (aBuf[0] & 0x7F) << 14;
  1279   1337     nByte += (aBuf[1] & 0x7F) << 7;
  1280   1338     nByte += (aBuf[2] & 0x7F);
  1281   1339     *pbFree = !(aBuf[1] & 0x80);
  1282   1340     return nByte;
  1283   1341   }
  1284   1342   
         1343  +/*
         1344  +** Subtract iSub from database file offset iOff and set *piRes to the
         1345  +** result. If doing so means passing the start of a block, follow the
         1346  +** block pointer stored in the first 4 bytes of the block.
         1347  +**
         1348  +** Offset iOff is an absolute offset - not subject to any block redirection.
         1349  +** However any block pointer followed is. Use pSeg->pRedirect in this case.
         1350  +**
         1351  +** Return LSM_OK if successful or an lsm error code if an error occurs.
         1352  +*/
  1285   1353   static int fsSubtractOffset(
  1286   1354     FileSystem *pFS, 
  1287   1355     Segment *pSeg,
  1288   1356     i64 iOff, 
  1289   1357     int iSub, 
  1290   1358     i64 *piRes
  1291   1359   ){
................................................................................
  1302   1370     }
  1303   1371   
  1304   1372     rc = fsBlockPrev(pFS, pSeg, fsPageToBlock(pFS, iOff), &iBlk);
  1305   1373     *piRes = fsLastPageOnBlock(pFS, iBlk) - iSub + (iOff - iStart + 1);
  1306   1374     return rc;
  1307   1375   }
  1308   1376   
         1377  +/*
         1378  +** Add iAdd to database file offset iOff and set *piRes to the
         1379  +** result. If doing so means passing the end of a block, follow the
         1380  +** block pointer stored in the last 4 bytes of the block.
         1381  +**
         1382  +** Offset iOff is an absolute offset - not subject to any block redirection.
         1383  +** However any block pointer followed is. Use pSeg->pRedirect in this case.
         1384  +**
         1385  +** Return LSM_OK if successful or an lsm error code if an error occurs.
         1386  +*/
  1309   1387   static int fsAddOffset(
  1310   1388     FileSystem *pFS, 
  1311   1389     Segment *pSeg,
  1312   1390     i64 iOff, 
  1313   1391     int iAdd, 
  1314   1392     i64 *piRes
  1315   1393   ){
................................................................................
  1326   1404     }
  1327   1405   
  1328   1406     rc = fsBlockNext(pFS, pSeg, fsPageToBlock(pFS, iOff), &iBlk);
  1329   1407     *piRes = fsFirstPageOnBlock(pFS, iBlk) + iAdd - (iEob - iOff + 1);
  1330   1408     return rc;
  1331   1409   }
  1332   1410   
         1411  +/*
         1412  +** If it is not already allocated, allocate either the FileSystem.aOBuffer (if
         1413  +** bWrite is true) or the FileSystem.aIBuffer (if bWrite is false). Return
         1414  +** LSM_OK if successful if the attempt to allocate memory fails.
         1415  +*/
  1333   1416   static int fsAllocateBuffer(FileSystem *pFS, int bWrite){
  1334   1417     u8 **pp;                        /* Pointer to either aIBuffer or aOBuffer */
  1335   1418   
  1336   1419     assert( pFS->pCompress );
  1337   1420   
  1338   1421     /* If neither buffer has been allocated, figure out how large they
  1339   1422     ** should be. Store this value in FileSystem.nBuffer.  */
................................................................................
  1430   1513     Page *p;
  1431   1514     int iHash;
  1432   1515     int rc = LSM_OK;
  1433   1516   
  1434   1517     /* In most cases iReal is the same as iPg. Except, if pSeg->pRedirect is 
  1435   1518     ** not NULL, and the block containing iPg has been redirected, then iReal
  1436   1519     ** is the page number after redirection.  */
  1437         -  Pgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
         1520  +  Pgno iReal = fsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
  1438   1521   
  1439   1522     assert_lists_are_ok(pFS);
  1440   1523     assert( iPg>=fsFirstPageOnBlock(pFS, 1) );
  1441   1524     assert( iReal>=fsFirstPageOnBlock(pFS, 1) );
  1442   1525     *ppPg = 0;
  1443   1526   
  1444   1527   
................................................................................
  1693   1776   
  1694   1777   #ifndef NDEBUG
  1695   1778   /*
  1696   1779   ** Return true if page iPg, which is a part of segment p, lies on
  1697   1780   ** a redirected block. 
  1698   1781   */
  1699   1782   static int fsPageRedirects(FileSystem *pFS, Segment *p, Pgno iPg){
  1700         -  return (iPg!=0 && iPg!=lsmFsRedirectPage(pFS, p->pRedirect, iPg));
         1783  +  return (iPg!=0 && iPg!=fsRedirectPage(pFS, p->pRedirect, iPg));
  1701   1784   }
  1702   1785   
  1703   1786   /*
  1704   1787   ** Return true if the second argument is not NULL and any of the first
  1705   1788   ** last or root pages lie on a redirected block. 
  1706   1789   */
  1707   1790   static int fsSegmentRedirects(FileSystem *pFS, Segment *p){

Changes to src/lsm_shared.c.

   520    520     }
   521    521   
   522    522     return rc;
   523    523   }
   524    524   
   525    525   static void dbDeferClose(lsm_db *pDb){
   526    526     if( pDb->pFS ){
   527         -    LsmFile *pLsmFile = 0;
          527  +    LsmFile *pLsmFile;
   528    528       Database *p = pDb->pDatabase;
   529         -    lsmFsDeferClose(pDb->pFS, &pLsmFile);
          529  +    pLsmFile = lsmFsDeferClose(pDb->pFS);
   530    530       pLsmFile->pNext = p->pLsmFile;
   531    531       p->pLsmFile = pLsmFile;
   532    532     }
   533    533   }
   534    534   
   535    535   LsmFile *lsmDbRecycleFd(lsm_db *db){
   536    536     LsmFile *pRet;