@@ -56,7 +56,6 @@ struct ceshim_header {
5656*/
5757typedef struct CeshimMMTblEntry CeshimMMTblEntry ;
5858struct __attribute__ ((__packed__ )) CeshimMMTblEntry {
59- sqlite3_int64 uppOfst ; // 08 upper pager offset
6059 Pgno lwrPgno ; // 04 lower pager pgno where actual page map data is stored
6160};
6261
@@ -82,7 +81,6 @@ struct CeshimMemPage {
8281*/
8382typedef struct ceshim_map_entry ceshim_map_entry ;
8483struct __attribute__ ((__packed__ )) ceshim_map_entry {
85- sqlite3_int64 uppOfst ; // 08 upper pager offset
8684 Pgno lwrPgno ; // 04 mapped lower pager pgno
8785 CeshimCmpSize cmprSz ; // 02 size of compressed page
8886 CeshimCmpOfst cmprOfst ; // 02 lower page offset for compressed page
@@ -114,9 +112,10 @@ struct ceshim_info {
114112 CeshimMMTblEntry * mmTbl ; // The master mapping table
115113 u16 mmTblCurrIx ; // Index of the current page map in mmTbl
116114 ceshim_map_entry * pPgMap ; // The current page map
117- ceshim_map_entry * pTmpPgMap ; // Used for converting integers to big-endian when saving
115+ ceshim_map_entry * pBigEndianPgMap ; // Used for converting integers to big-endian when saving
118116 u16 pgMapMaxCnt ; // Max entries for a page map, based on page size
119117 u16 pgMapSz ; // Size in bytes for the page map allocation
118+ u32 nBytesPerPgMap ; // Performance optimization premultiplication store
120119
121120 // bools
122121 u8 bPgMapDirty :1 ; // Curr page map needs to be persisted
@@ -353,32 +352,27 @@ static int ceshimCreateMMTbl(ceshim_file *p, int *memSzOut){
353352 ceshim_info * pInfo = p -> pInfo ;
354353 u16 maxSz = p -> pageSize - CESHIM_DB_HEADER_SIZE ;
355354 u16 maxEntries = maxSz / sizeof (CeshimMMTblEntry );
356-
357- // At this point, header has been loaded from persistent storage
355+
356+ // At this point, header may already be loaded from persistent storage
357+ // so be careful modifying header values
358358 pInfo -> ceshimHeader .mmTblMaxCnt = maxEntries ;
359- // pInfo->ceshimHeader.mmTblCurrCnt = 0;
360- pInfo -> mmTblCurrIx = 0 - 1 ; // Use max number to mean "not defined"
361-
359+ pInfo -> mmTblCurrIx = -1 ; // u16, so results in some large number to mean "not defined"
360+
361+ // allocate
362362 int memSz = maxEntries * sizeof (CeshimMMTblEntry );
363363 if ( !(pInfo -> mmTbl = sqlite3_malloc (memSz )) ) return SQLITE_NOMEM ;
364+
365+ // out param
364366 if ( memSzOut ) * memSzOut = memSz ;
365367 return SQLITE_OK ;
366368}
367369
368370static int ceshimSavePagemapData (ceshim_file * p ){
369371 int rc = SQLITE_OK ;
370372 ceshim_info * pInfo = p -> pInfo ;
371- ceshim_header * header = & pInfo -> ceshimHeader ;
372373 if ( pInfo -> bPgMapDirty ){
373374 Pgno pgno = pInfo -> mmTbl [pInfo -> mmTblCurrIx ].lwrPgno ;
374- u16 maxCnt = pInfo -> mmTblCurrIx == header -> mmTblCurrCnt - 1 ? header -> pgMapCnt : pInfo -> pgMapMaxCnt ;
375- for (u16 i = 0 ; i < maxCnt ; i ++ ) {
376- sqlite3PutVarint ((unsigned char * )& pInfo -> pTmpPgMap [i ].uppOfst , (u64 )pInfo -> pPgMap [i ].uppOfst );
377- put4byte ((u8 * )& pInfo -> pTmpPgMap [i ].lwrPgno , pInfo -> pPgMap [i ].lwrPgno );
378- put2byte ((u8 * )& pInfo -> pTmpPgMap [i ].cmprSz , pInfo -> pPgMap [i ].cmprSz );
379- put2byte ((u8 * )& pInfo -> pTmpPgMap [i ].cmprOfst , pInfo -> pPgMap [i ].cmprOfst );
380- }
381- rc = ceshimWriteUncompressed (p , pgno , 0 , pInfo -> pTmpPgMap , pInfo -> pgMapSz );
375+ rc = ceshimWriteUncompressed (p , pgno , 0 , pInfo -> pBigEndianPgMap , pInfo -> pgMapSz );
382376 if ( rc == SQLITE_OK ) pInfo -> bPgMapDirty = 0 ;
383377 }
384378 return rc ;
@@ -392,7 +386,6 @@ static int ceshimSaveMMTbl(ceshim_file *p){
392386 CeshimMMTblEntry * buf = sqlite3_malloc (memSz );
393387 if ( buf ){
394388 for (u16 i = 0 ; i < header -> mmTblCurrCnt ; i ++ ){
395- sqlite3PutVarint ((unsigned char * )& buf [i ].uppOfst , (u64 )pInfo -> mmTbl [i ].uppOfst );
396389 put2byte ((u8 * )& buf [i ].lwrPgno , pInfo -> mmTbl [i ].lwrPgno );
397390 }
398391 if ( (rc = ceshimWriteUncompressed (p , 1 , CESHIM_DB_MMTBL_OFST , buf , memSz ))== SQLITE_OK ){
@@ -408,16 +401,15 @@ static int ceshimLoadPagemapData(ceshim_file *p, u16 ix){
408401 ceshim_info * pInfo = p -> pInfo ;
409402 ceshim_header * header = & pInfo -> ceshimHeader ;
410403 assert ( pInfo -> bPgMapDirty == 0 );
411- assert ( ix != pInfo -> mmTblCurrIx );
404+ assert ( ix != pInfo -> mmTblCurrIx ); // mmTblCurrIx initially large number to mean no entries yet
412405 Pgno pgno = pInfo -> mmTbl [ix ].lwrPgno ;
413- rc = ceshimReadUncompressed (p , pgno , 0 , pInfo -> pTmpPgMap , pInfo -> pgMapSz );
406+ rc = ceshimReadUncompressed (p , pgno , 0 , pInfo -> pBigEndianPgMap , pInfo -> pgMapSz );
414407 if ( rc == SQLITE_OK ){
415408 u16 maxCnt = ix == header -> mmTblCurrCnt - 1 ? header -> pgMapCnt : pInfo -> pgMapMaxCnt ;
416409 for (u16 i = 0 ; i < maxCnt ; i ++ ) {
417- sqlite3GetVarint ((unsigned char * )& pInfo -> pTmpPgMap [i ].uppOfst , (u64 * )& pInfo -> pPgMap [i ].uppOfst );
418- pInfo -> pPgMap [i ].lwrPgno = get4byte ((u8 * )& pInfo -> pTmpPgMap [i ].lwrPgno );
419- pInfo -> pPgMap [i ].cmprSz = get2byte ((u8 * )& pInfo -> pTmpPgMap [i ].cmprSz );
420- pInfo -> pPgMap [i ].cmprOfst = get2byte ((u8 * )& pInfo -> pTmpPgMap [i ].cmprOfst );
410+ pInfo -> pPgMap [i ].lwrPgno = get4byte ((u8 * )& pInfo -> pBigEndianPgMap [i ].lwrPgno );
411+ pInfo -> pPgMap [i ].cmprSz = get2byte ((u8 * )& pInfo -> pBigEndianPgMap [i ].cmprSz );
412+ pInfo -> pPgMap [i ].cmprOfst = get2byte ((u8 * )& pInfo -> pBigEndianPgMap [i ].cmprOfst );
421413 }
422414 pInfo -> mmTblCurrIx = ix ;
423415 }
@@ -426,19 +418,19 @@ static int ceshimLoadPagemapData(ceshim_file *p, u16 ix){
426418
427419static int ceshimLoadMMTbl (ceshim_file * p ){
428420 int rc ;
421+ int memSz ;
429422 ceshim_info * pInfo = p -> pInfo ;
430423 ceshim_header * header = & pInfo -> ceshimHeader ;
431- // TODO: ensure header has already been loaded
432-
433- // assert( header->tblMaxCnt>0 );
434424 assert ( pInfo -> mmTbl == NULL );
435- int memSz ;
425+
426+ // Header must have already been loaded
427+ assert ( header -> mmTblCurrCnt > 0 );
428+
436429 if ( (rc = ceshimCreateMMTbl (p , & memSz ))== SQLITE_OK ){
437430 CeshimMMTblEntry * buf = sqlite3_malloc (memSz );
438431 if ( buf ){
439432 if ( (rc = ceshimReadUncompressed (p , 1 , CESHIM_DB_MMTBL_OFST , buf , memSz ))== SQLITE_OK ){
440433 for (u16 i = 0 ; i < header -> mmTblCurrCnt ; i ++ ){
441- sqlite3GetVarint ((unsigned char * )& buf [i ].uppOfst , (u64 * )& pInfo -> mmTbl [i ].uppOfst );
442434 pInfo -> mmTbl [i ].lwrPgno = get2byte ((u8 * )& buf [i ].lwrPgno );
443435 }
444436 sqlite3_free (buf );
@@ -463,13 +455,16 @@ static int ceshimPagerLock(ceshim_file *p){
463455 pInfo -> pgMapMaxCnt = p -> pageSize / sizeof (ceshim_map_entry );
464456 pInfo -> pgMapSz = pInfo -> pgMapMaxCnt * sizeof (ceshim_map_entry );
465457
458+ // Optimization: Do this multiplication and store it for later use.
459+ pInfo -> nBytesPerPgMap = pInfo -> pgMapMaxCnt * pInfo -> ceshimHeader .uppPgSz ;
460+
466461 /* Allocate space for a single page map.
467462 Only one page map will be in memory at a time. */
468463 pInfo -> pPgMap = sqlite3_malloc (pInfo -> pgMapSz );
469- pInfo -> pTmpPgMap = sqlite3_malloc (pInfo -> pgMapSz );
470- if ( pInfo -> pPgMap && pInfo -> pTmpPgMap ){
464+ pInfo -> pBigEndianPgMap = sqlite3_malloc (pInfo -> pgMapSz );
465+ if ( pInfo -> pPgMap && pInfo -> pBigEndianPgMap ){
471466 memset ((void * )pInfo -> pPgMap , 0 , pInfo -> pgMapSz );
472- memset ((void * )pInfo -> pTmpPgMap , 0 , pInfo -> pgMapSz );
467+ memset ((void * )pInfo -> pBigEndianPgMap , 0 , pInfo -> pgMapSz );
473468 if ( nPageFile == 0 ){
474469 /* We will be creating a new database so set up some data that is
475470 needed right away that would be too late to do in ceshimNewDatabase(). */
@@ -597,27 +592,23 @@ static int ceshimNewDatabase(ceshim_file *pFile){
597592}
598593
599594/*
600- static int ceshimCreateNewPageMap(ceshim_file *p){
601- ceshim_info *pInfo = p->pInfo;
602- ceshim_header *header = &pInfo->ceshimHeader;
603- assert( pInfo->pgMap==NULL || (pInfo->pgMapMaxCnt && header->pgMapCnt==pInfo->pgMapMaxCnt) );
604- int rc = SQLITE_OK;
605- // first save current pagemap
606- if( p->pInfo->pgMap ) rc = ceshimSavePagemapData(p, pInfo->nCurrPgMap);
607- if( rc==SQLITE_OK ){
608- pInfo->pgMap = sqlite3_malloc(pInfo->pgMapSz);
609- if( !pInfo->pgMap ) rc = SQLITE_NOMEM;
610- }
611- return rc;
612- }*/
613-
614- static int ceshimSwitchPageMap (ceshim_file * p , sqlite_int64 iUppOfst ){
595+ ** Switch to a specific page map based on pager offset,
596+ ** saving the current page map if needed.
597+ ** @returns index# of page map switched to.
598+ */
599+ static u16 ceshimSwitchPageMap (ceshim_file * p , sqlite_int64 iUppOfst ){
615600 int rc = SQLITE_ERROR ;
616601 ceshim_info * pInfo = p -> pInfo ;
617602 ceshim_header * header = & pInfo -> ceshimHeader ;
618603 u16 ix = 0 ;
619604
620605 // find page map
606+ #if 1
607+ ix = iUppOfst >= (pInfo -> nBytesPerPgMap * header -> mmTblCurrCnt )
608+ ? header -> mmTblCurrCnt - 1
609+ : (u16 )(iUppOfst / pInfo -> nBytesPerPgMap );
610+ if ( ix < header -> mmTblCurrCnt ) rc = SQLITE_OK ;
611+ #else
621612 // check last entry first (edge case)
622613 if ( iUppOfst >= pInfo -> mmTbl [header -> mmTblCurrCnt - 1 ].uppOfst ){
623614 ix = header -> mmTblCurrCnt - 1 ;
@@ -634,7 +625,9 @@ static int ceshimSwitchPageMap(ceshim_file *p, sqlite_int64 iUppOfst){
634625 }
635626 }
636627 }
628+ #endif
637629
630+ // switch
638631 if ( rc == SQLITE_OK && ix != pInfo -> mmTblCurrIx ){
639632 ceshim_printf (pInfo , "\nSwitching to map #%u for offset %lld\n" , (unsigned )ix , iUppOfst );
640633 // save
@@ -646,7 +639,7 @@ static int ceshimSwitchPageMap(ceshim_file *p, sqlite_int64 iUppOfst){
646639 if ( rc == SQLITE_OK ) pInfo -> mmTblCurrIx = ix ;
647640 }
648641 }
649- return rc ;
642+ return ix ;
650643}
651644
652645static int ceshimPageMapGet (
@@ -661,11 +654,25 @@ static int ceshimPageMapGet(
661654 ceshim_info * pInfo = pFile -> pInfo ;
662655 ceshim_header * header = & pInfo -> ceshimHeader ;
663656 if ( outUppPgno ) * outUppPgno = (Pgno )(uSrcOfst /header -> uppPgSz + 1 );
664- ceshimSwitchPageMap (pFile , uSrcOfst );
657+ int currPgMapNo = ceshimSwitchPageMap (pFile , uSrcOfst );
665658 if ( pInfo -> pPgMap ){
666659 // determine max elements based on if last page map is currently in memory
667660 u16 maxCnt = pInfo -> mmTblCurrIx == header -> mmTblCurrCnt - 1 ? header -> pgMapCnt : pInfo -> pgMapMaxCnt ;
668- for (int i = 0 ; i < maxCnt ; i ++ ){
661+ #if 1
662+ u16 pgMapIx = (u16 )(uSrcOfst /pInfo -> nBytesPerPgMap );
663+ int ix = uSrcOfst % pInfo -> nBytesPerPgMap / header -> uppPgSz ;
664+ if (
665+ ix < maxCnt // if we go beyond maxCnt, entry doesn't exist yet
666+ && pgMapIx == currPgMapNo // if pgMap not yet created, entry doesn't exist yet
667+ ){
668+ if ( outLwrPgno ) * outLwrPgno = pInfo -> pPgMap [ix ].lwrPgno ;
669+ if ( outCmpSz ) * outCmpSz = pInfo -> pPgMap [ix ].cmprSz ;
670+ if ( outCmpOfst ) * outCmpOfst = pInfo -> pPgMap [ix ].cmprOfst ;
671+ if ( outIx ) * outIx = ix ;
672+ return SQLITE_OK ;
673+ }
674+ #else
675+ for ( int i = 0 ; i < maxCnt ; i ++ ){
669676 if (
670677 pInfo -> pPgMap [i ].uppOfst <= uSrcOfst
671678 && uSrcOfst < pInfo -> pPgMap [i ].uppOfst + header -> uppPgSz
@@ -677,6 +684,7 @@ static int ceshimPageMapGet(
677684 return SQLITE_OK ;
678685 }
679686 }
687+ #endif
680688 }
681689 return SQLITE_ERROR ;
682690}
@@ -690,11 +698,13 @@ static int ceshimPageMapGet(
690698void ceshimAllocCmpPageSpace (
691699 ceshim_file * pFile ,
692700 CeshimCmpSize cmpSz , // Current compressed size of data for allocation
693- ceshim_map_entry * mapEntry // Existing map entry to record allocation data
701+ u16 pgMapIx // Index of map entry to record allocation data
694702){
695703 ceshim_info * pInfo = pFile -> pInfo ;
696704 ceshim_header * header = & pInfo -> ceshimHeader ;
697705 CeshimCmpOfst ofst = header -> currPageOfst ;
706+ ceshim_map_entry * pMapEntry = & pInfo -> pPgMap [pgMapIx ];
707+ ceshim_map_entry * pBigEndianPgMapEntry = & pInfo -> pBigEndianPgMap [pgMapIx ];
698708 // Since we no longer write compressed pages to page 1, we can optimize this
699709 //u32 realPageSize = pFile->pageSize - (header->currPgno == 1 ? CESHIM_DB_HEADER_SIZE : 0);
700710 header -> currPageOfst += cmpSz ;
@@ -709,9 +719,13 @@ void ceshimAllocCmpPageSpace(
709719 else
710720 header -> currPgno ++ ;
711721 }
712- mapEntry -> lwrPgno = header -> currPgno ;
713- mapEntry -> cmprOfst = ofst ;
714- mapEntry -> cmprSz = cmpSz ;
722+ // Set data in map and in Big Endian version of map for fast save to persistent storage
723+ pMapEntry -> lwrPgno = header -> currPgno ;
724+ pMapEntry -> cmprOfst = ofst ;
725+ pMapEntry -> cmprSz = cmpSz ;
726+ put4byte ((u8 * )& pBigEndianPgMapEntry -> lwrPgno , pMapEntry -> lwrPgno );
727+ put2byte ((u8 * )& pBigEndianPgMapEntry -> cmprSz , pMapEntry -> cmprSz );
728+ put2byte ((u8 * )& pBigEndianPgMapEntry -> cmprOfst , pMapEntry -> cmprOfst );
715729 pInfo -> bPgMapDirty = 1 ;
716730}
717731
@@ -734,7 +748,6 @@ int ceshimAddPageEntry(
734748 return CESHIM_ERROR_PAGE_SIZE_TOO_SMALL ;
735749 }
736750 CeshimMMTblEntry * entry = & pInfo -> mmTbl [header -> mmTblCurrCnt ];
737- entry -> uppOfst = uppOfst ;
738751 entry -> lwrPgno = header -> currPgno + 1 ; // use next pgno but don't incr. counter!
739752 header -> mmTblCurrCnt ++ ;
740753 header -> pgMapCnt = 0 ;
@@ -743,11 +756,11 @@ int ceshimAddPageEntry(
743756 }
744757
745758 // add new page map entry
746- ceshim_map_entry * pPgMapEntry = & pInfo -> pPgMap [ header -> pgMapCnt ++ ] ;
747- pPgMapEntry -> uppOfst = uppOfst ;
759+ u16 ix = header -> pgMapCnt ++ ;
760+ ceshim_map_entry * pPgMapEntry = & pInfo -> pPgMap [ ix ] ;
748761
749762 // assign space to store compressed page
750- ceshimAllocCmpPageSpace (pFile , cmpSz , pPgMapEntry );
763+ ceshimAllocCmpPageSpace (pFile , cmpSz , ix );
751764
752765 // for placeholder entries, set some data to zero
753766 if ( !outLwrPgno ) pPgMapEntry -> lwrPgno = 0 ;
@@ -786,7 +799,7 @@ static int ceshimPageMapSet(
786799 assert ( outUppPgno );
787800 assert ( outLwrPgno );
788801 assert ( outCmpOfst );
789- ceshimSwitchPageMap ( pFile , uppOfst );
802+
790803 if ( (rc = ceshimPageMapGet (pFile , uppOfst , outUppPgno , outLwrPgno , outCmpOfst , & oldCmpSz , & ix ))== SQLITE_OK ){
791804 /*
792805 ** We found a map entry. It's either a placeholder entry that need valid data,
@@ -798,21 +811,23 @@ static int ceshimPageMapSet(
798811 */
799812 if ( oldCmpSz == 0 || cmpSz > oldCmpSz ){
800813 // entry found was either a placeholder or we now need more room, so allocate new space.
801- ceshim_map_entry * mapEntry = & pInfo -> pPgMap [ix ];
802- ceshimAllocCmpPageSpace (pFile , cmpSz , mapEntry );
803- * outLwrPgno = mapEntry -> lwrPgno ;
804- * outCmpOfst = mapEntry -> cmprOfst ;
814+ ceshim_map_entry * pMapEntry = & pInfo -> pPgMap [ix ];
815+ ceshimAllocCmpPageSpace (pFile , cmpSz , ix );
816+
817+ * outLwrPgno = pMapEntry -> lwrPgno ;
818+ * outCmpOfst = pMapEntry -> cmprOfst ;
805819 ceshim_printf (pInfo , "Updated placeholder entry (uppOfst=%lld, lwrPgno=%lu,cmpOfst=%lu,cmpSz=%lu) \n" ,
806- (long long )mapEntry -> uppOfst , (unsigned long )mapEntry -> lwrPgno , (unsigned long )mapEntry -> cmprOfst , (unsigned long )mapEntry -> cmprSz );
820+ (long long )uppOfst , (unsigned long )pMapEntry -> lwrPgno , (unsigned long )pMapEntry -> cmprOfst , (unsigned long )pMapEntry -> cmprSz );
807821 return SQLITE_OK ;
808822 }else if ( cmpSz < oldCmpSz ){
809- // Update map entry data and keep compressed page slot. Abandoned space will be recovered via vacuum.
823+ // Update map entry data and keep compressed page slot. Abandoned space will need to be recovered via a vacuum operaion .
810824 pInfo -> pPgMap [ix ].cmprSz = cmpSz ;
825+ put2byte ((u8 * )& pInfo -> pBigEndianPgMap [ix ].cmprSz , cmpSz );
811826 pInfo -> bPgMapDirty = 1 ;
812827 }
813828 return rc ;
814829 }else {
815- sqlite3_int64 nextOfst = header -> pgMapCnt == 0 ? 0 : pInfo -> pPgMap [ header -> pgMapCnt - 1 ]. uppOfst + header -> uppPgSz ;
830+ sqlite3_int64 nextOfst = (( header -> mmTblCurrCnt - 1 ) * header -> uppPgSz * pInfo -> pgMapMaxCnt ) + ( header -> pgMapCnt * header -> uppPgSz ) ;
816831 while ( uppOfst > nextOfst ){
817832 ceshimAddPageEntry (pFile , nextOfst , 0 , NULL , NULL );
818833 ceshim_printf (pInfo , "Added intermin entry (uppOfst=%lld, lwrPgno=0,cmpOfst=0,cmpSz=0)\n" , (long long )nextOfst );
@@ -869,9 +884,9 @@ static int ceshimClose(sqlite3_file *pFile){
869884 sqlite3_free (pInfo -> pPgMap );
870885 pInfo -> pPgMap = NULL ;
871886 }
872- if ( pInfo -> pTmpPgMap ){
873- sqlite3_free (pInfo -> pTmpPgMap );
874- pInfo -> pTmpPgMap = NULL ;
887+ if ( pInfo -> pBigEndianPgMap ){
888+ sqlite3_free (pInfo -> pBigEndianPgMap );
889+ pInfo -> pBigEndianPgMap = NULL ;
875890 }
876891 }
877892 }
0 commit comments