/ Check-in [21695c34]
Login

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

Overview
Comment:Reduce the size of the MemPage object by about 32 bytes. Other structure size optimizations.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:21695c3476804477cb378b5a643196380e7e2281
User & Date: drh 2012-02-02 19:37:18
Context
2012-02-02
21:02
More structure packing for smaller objects and less memory usage. check-in: f14e7f29 user: drh tags: trunk
19:37
Reduce the size of the MemPage object by about 32 bytes. Other structure size optimizations. check-in: 21695c34 user: drh tags: trunk
18:46
When non-aggregate columns occur in an aggregate query with a single min() or max(), then the values of the non-aggregate columns are taken from one of the rows that was the min() or max(). check-in: fa13edd3 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

   866    866   ** pages that do contain overflow cells.
   867    867   */
   868    868   static u8 *findOverflowCell(MemPage *pPage, int iCell){
   869    869     int i;
   870    870     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
   871    871     for(i=pPage->nOverflow-1; i>=0; i--){
   872    872       int k;
   873         -    struct _OvflCell *pOvfl;
   874         -    pOvfl = &pPage->aOvfl[i];
   875         -    k = pOvfl->idx;
          873  +    k = pPage->aiOvfl[i];
   876    874       if( k<=iCell ){
   877    875         if( k==iCell ){
   878         -        return pOvfl->pCell;
          876  +        return pPage->apOvfl[i];
   879    877         }
   880    878         iCell--;
   881    879       }
   882    880     }
   883    881     return findCell(pPage, iCell);
   884    882   }
   885    883   
................................................................................
  5517   5515   /*
  5518   5516   ** Insert a new cell on pPage at cell index "i".  pCell points to the
  5519   5517   ** content of the cell.
  5520   5518   **
  5521   5519   ** If the cell content will fit on the page, then put it there.  If it
  5522   5520   ** will not fit, then make a copy of the cell content into pTemp if
  5523   5521   ** pTemp is not null.  Regardless of pTemp, allocate a new entry
  5524         -** in pPage->aOvfl[] and make it point to the cell content (either
         5522  +** in pPage->apOvfl[] and make it point to the cell content (either
  5525   5523   ** in pTemp or the original pCell) and also record its index. 
  5526   5524   ** Allocating a new entry in pPage->aCell[] implies that 
  5527   5525   ** pPage->nOverflow is incremented.
  5528   5526   **
  5529   5527   ** If nSkip is non-zero, then do not copy the first nSkip bytes of the
  5530   5528   ** cell. The caller will overwrite them after this function returns. If
  5531   5529   ** nSkip is non-zero, then pCell may not point to an invalid memory location 
................................................................................
  5551   5549   
  5552   5550     int nSkip = (iChild ? 4 : 0);
  5553   5551   
  5554   5552     if( *pRC ) return;
  5555   5553   
  5556   5554     assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
  5557   5555     assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
  5558         -  assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );
         5556  +  assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
         5557  +  assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
  5559   5558     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  5560   5559     /* The cell should normally be sized correctly.  However, when moving a
  5561   5560     ** malformed cell from a leaf page to an interior page, if the cell size
  5562   5561     ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
  5563   5562     ** might be less than 8 (leaf-size + pointer) on the interior node.  Hence
  5564   5563     ** the term after the || in the following assert(). */
  5565   5564     assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
................................................................................
  5568   5567         memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
  5569   5568         pCell = pTemp;
  5570   5569       }
  5571   5570       if( iChild ){
  5572   5571         put4byte(pCell, iChild);
  5573   5572       }
  5574   5573       j = pPage->nOverflow++;
  5575         -    assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) );
  5576         -    pPage->aOvfl[j].pCell = pCell;
  5577         -    pPage->aOvfl[j].idx = (u16)i;
         5574  +    assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
         5575  +    pPage->apOvfl[j] = pCell;
         5576  +    pPage->aiOvfl[j] = (u16)i;
  5578   5577     }else{
  5579   5578       int rc = sqlite3PagerWrite(pPage->pDbPage);
  5580   5579       if( rc!=SQLITE_OK ){
  5581   5580         *pRC = rc;
  5582   5581         return;
  5583   5582       }
  5584   5583       assert( sqlite3PagerIswriteable(pPage->pDbPage) );
................................................................................
  5718   5717     ** may be inserted. If both these operations are successful, proceed.
  5719   5718     */
  5720   5719     rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
  5721   5720   
  5722   5721     if( rc==SQLITE_OK ){
  5723   5722   
  5724   5723       u8 *pOut = &pSpace[4];
  5725         -    u8 *pCell = pPage->aOvfl[0].pCell;
         5724  +    u8 *pCell = pPage->apOvfl[0];
  5726   5725       u16 szCell = cellSizePtr(pPage, pCell);
  5727   5726       u8 *pStop;
  5728   5727   
  5729   5728       assert( sqlite3PagerIswriteable(pNew->pDbPage) );
  5730   5729       assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
  5731   5730       zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
  5732   5731       assemblePage(pNew, 1, &pCell, &szCell);
................................................................................
  5828   5827   ** on page pFrom to page pTo. If page pFrom was not a leaf page, then
  5829   5828   ** the pointer-map entries for each child page are updated so that the
  5830   5829   ** parent page stored in the pointer map is page pTo. If pFrom contained
  5831   5830   ** any cells with overflow page pointers, then the corresponding pointer
  5832   5831   ** map entries are also updated so that the parent page is page pTo.
  5833   5832   **
  5834   5833   ** If pFrom is currently carrying any overflow cells (entries in the
  5835         -** MemPage.aOvfl[] array), they are not copied to pTo. 
         5834  +** MemPage.apOvfl[] array), they are not copied to pTo. 
  5836   5835   **
  5837   5836   ** Before returning, page pTo is reinitialized using btreeInitPage().
  5838   5837   **
  5839   5838   ** The performance of this function is not critical. It is only used by 
  5840   5839   ** the balance_shallower() and balance_deeper() procedures, neither of
  5841   5840   ** which are called often under normal circumstances.
  5842   5841   */
................................................................................
  5965   5964   
  5966   5965     /* At this point pParent may have at most one overflow cell. And if
  5967   5966     ** this overflow cell is present, it must be the cell with 
  5968   5967     ** index iParentIdx. This scenario comes about when this function
  5969   5968     ** is called (indirectly) from sqlite3BtreeDelete().
  5970   5969     */
  5971   5970     assert( pParent->nOverflow==0 || pParent->nOverflow==1 );
  5972         -  assert( pParent->nOverflow==0 || pParent->aOvfl[0].idx==iParentIdx );
         5971  +  assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
  5973   5972   
  5974   5973     if( !aOvflSpace ){
  5975   5974       return SQLITE_NOMEM;
  5976   5975     }
  5977   5976   
  5978   5977     /* Find the sibling pages to balance. Also locate the cells in pParent 
  5979   5978     ** that divide the siblings. An attempt is made to find NN siblings on 
................................................................................
  6012   6011       if( rc ){
  6013   6012         memset(apOld, 0, (i+1)*sizeof(MemPage*));
  6014   6013         goto balance_cleanup;
  6015   6014       }
  6016   6015       nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
  6017   6016       if( (i--)==0 ) break;
  6018   6017   
  6019         -    if( i+nxDiv==pParent->aOvfl[0].idx && pParent->nOverflow ){
  6020         -      apDiv[i] = pParent->aOvfl[0].pCell;
         6018  +    if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
         6019  +      apDiv[i] = pParent->apOvfl[0];
  6021   6020         pgno = get4byte(apDiv[i]);
  6022   6021         szNew[i] = cellSizePtr(pParent, apDiv[i]);
  6023   6022         pParent->nOverflow = 0;
  6024   6023       }else{
  6025   6024         apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
  6026   6025         pgno = get4byte(apDiv[i]);
  6027   6026         szNew[i] = cellSizePtr(pParent, apDiv[i]);
................................................................................
  6454   6453       ** setting a pointer map entry is a relatively expensive operation, this
  6455   6454       ** code only sets pointer map entries for child or overflow pages that have
  6456   6455       ** actually moved between pages.  */
  6457   6456       MemPage *pNew = apNew[0];
  6458   6457       MemPage *pOld = apCopy[0];
  6459   6458       int nOverflow = pOld->nOverflow;
  6460   6459       int iNextOld = pOld->nCell + nOverflow;
  6461         -    int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1);
         6460  +    int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1);
  6462   6461       j = 0;                             /* Current 'old' sibling page */
  6463   6462       k = 0;                             /* Current 'new' sibling page */
  6464   6463       for(i=0; i<nCell; i++){
  6465   6464         int isDivider = 0;
  6466   6465         while( i==iNextOld ){
  6467   6466           /* Cell i is the cell immediately following the last cell on old
  6468   6467           ** sibling page j. If the siblings are not leaf pages of an
  6469   6468           ** intkey b-tree, then cell i was a divider cell. */
  6470   6469           assert( j+1 < ArraySize(apCopy) );
  6471   6470           pOld = apCopy[++j];
  6472   6471           iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
  6473   6472           if( pOld->nOverflow ){
  6474   6473             nOverflow = pOld->nOverflow;
  6475         -          iOverflow = i + !leafData + pOld->aOvfl[0].idx;
         6474  +          iOverflow = i + !leafData + pOld->aiOvfl[0];
  6476   6475           }
  6477   6476           isDivider = !leafData;  
  6478   6477         }
  6479   6478   
  6480   6479         assert(nOverflow>0 || iOverflow<i );
  6481         -      assert(nOverflow<2 || pOld->aOvfl[0].idx==pOld->aOvfl[1].idx-1);
  6482         -      assert(nOverflow<3 || pOld->aOvfl[1].idx==pOld->aOvfl[2].idx-1);
         6480  +      assert(nOverflow<2 || pOld->aiOvfl[0]==pOld->aiOvfl[1]-1);
         6481  +      assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1);
  6483   6482         if( i==iOverflow ){
  6484   6483           isDivider = 1;
  6485   6484           if( (--nOverflow)>0 ){
  6486   6485             iOverflow++;
  6487   6486           }
  6488   6487         }
  6489   6488   
................................................................................
  6596   6595     assert( sqlite3PagerIswriteable(pChild->pDbPage) );
  6597   6596     assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
  6598   6597     assert( pChild->nCell==pRoot->nCell );
  6599   6598   
  6600   6599     TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
  6601   6600   
  6602   6601     /* Copy the overflow cells from pRoot to pChild */
  6603         -  memcpy(pChild->aOvfl, pRoot->aOvfl, pRoot->nOverflow*sizeof(pRoot->aOvfl[0]));
         6602  +  memcpy(pChild->aiOvfl, pRoot->aiOvfl,
         6603  +         pRoot->nOverflow*sizeof(pRoot->aiOvfl[0]));
         6604  +  memcpy(pChild->apOvfl, pRoot->apOvfl,
         6605  +         pRoot->nOverflow*sizeof(pRoot->apOvfl[0]));
  6604   6606     pChild->nOverflow = pRoot->nOverflow;
  6605   6607   
  6606   6608     /* Zero the contents of pRoot. Then install pChild as the right-child. */
  6607   6609     zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF);
  6608   6610     put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild);
  6609   6611   
  6610   6612     *ppChild = pChild;
................................................................................
  6659   6661         int const iIdx = pCur->aiIdx[iPage-1];
  6660   6662   
  6661   6663         rc = sqlite3PagerWrite(pParent->pDbPage);
  6662   6664         if( rc==SQLITE_OK ){
  6663   6665   #ifndef SQLITE_OMIT_QUICKBALANCE
  6664   6666           if( pPage->hasData
  6665   6667            && pPage->nOverflow==1
  6666         -         && pPage->aOvfl[0].idx==pPage->nCell
         6668  +         && pPage->aiOvfl[0]==pPage->nCell
  6667   6669            && pParent->pgno!=1
  6668   6670            && pParent->nCell==iIdx
  6669   6671           ){
  6670   6672             /* Call balance_quick() to create a new sibling of pPage on which
  6671   6673             ** to store the overflow cell. balance_quick() inserts a new cell
  6672   6674             ** into pParent, which may cause pParent overflow. If this
  6673   6675             ** happens, the next interation of the do-loop will balance pParent 

Changes to src/btreeInt.h.

   280    280     u8 max1bytePayload;  /* min(maxLocal,127) */
   281    281     u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
   282    282     u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
   283    283     u16 cellOffset;      /* Index in aData of first cell pointer */
   284    284     u16 nFree;           /* Number of free bytes on the page */
   285    285     u16 nCell;           /* Number of cells on this page, local and ovfl */
   286    286     u16 maskPage;        /* Mask for page offset */
   287         -  struct _OvflCell {   /* Cells that will not fit on aData[] */
   288         -    u8 *pCell;          /* Pointers to the body of the overflow cell */
   289         -    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
   290         -  } aOvfl[5];
          287  +  u16 aiOvfl[5];       /* Insert the i-th overflow cell before the aiOvfl-th
          288  +                       ** non-overflow cell */
          289  +  u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
   291    290     BtShared *pBt;       /* Pointer to BtShared that this page is part of */
   292    291     u8 *aData;           /* Pointer to disk image of the page data */
   293    292     u8 *aDataEnd;        /* One byte past the end of usable data */
   294    293     u8 *aCellIdx;        /* The cell index area */
   295    294     DbPage *pDbPage;     /* Pager page handle */
   296    295     Pgno pgno;           /* Page number for this page */
   297    296   };
................................................................................
   491    490   ** found at self->pBt->mutex. 
   492    491   */
   493    492   struct BtCursor {
   494    493     Btree *pBtree;            /* The Btree to which this cursor belongs */
   495    494     BtShared *pBt;            /* The BtShared this cursor points to */
   496    495     BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
   497    496     struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
          497  +#ifndef SQLITE_OMIT_INCRBLOB
          498  +  Pgno *aOverflow;          /* Cache of overflow page locations */
          499  +#endif
   498    500     Pgno pgnoRoot;            /* The root page of this tree */
   499    501     sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
   500    502     CellInfo info;            /* A parse of the cell we are pointing at */
   501    503     i64 nKey;        /* Size of pKey, or last integer key */
   502    504     void *pKey;      /* Saved key that was cursor's last known position */
   503    505     int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
   504    506     u8 wrFlag;                /* True if writable */
   505    507     u8 atLast;                /* Cursor pointing to the last entry */
   506    508     u8 validNKey;             /* True if info.nKey is valid */
   507    509     u8 eState;                /* One of the CURSOR_XXX constants (see below) */
   508    510   #ifndef SQLITE_OMIT_INCRBLOB
   509         -  Pgno *aOverflow;          /* Cache of overflow page locations */
   510    511     u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
   511    512   #endif
   512    513     i16 iPage;                            /* Index of current page in apPage */
   513    514     u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
   514    515     MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
   515    516   };
   516    517   
................................................................................
   631    632   ** This structure is passed around through all the sanity checking routines
   632    633   ** in order to keep track of some global state information.
   633    634   */
   634    635   typedef struct IntegrityCk IntegrityCk;
   635    636   struct IntegrityCk {
   636    637     BtShared *pBt;    /* The tree being checked out */
   637    638     Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
   638         -  Pgno nPage;       /* Number of pages in the database */
   639    639     int *anRef;       /* Number of times each page is referenced */
          640  +  Pgno nPage;       /* Number of pages in the database */
   640    641     int mxErr;        /* Stop accumulating errors when this reaches zero */
   641    642     int nErr;         /* Number of messages written to zErrMsg so far */
   642    643     int mallocFailed; /* A memory allocation error has occurred */
   643    644     StrAccum errMsg;  /* Accumulate the error message text here */
   644    645   };
   645    646   
   646    647   /*
   647    648   ** Routines to read or write a two- and four-byte big-endian integer values.
   648    649   */
   649    650   #define get2byte(x)   ((x)[0]<<8 | (x)[1])
   650    651   #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
   651    652   #define get4byte sqlite3Get4byte
   652    653   #define put4byte sqlite3Put4byte

Changes to src/pcache1.c.

    72     72     PGroup *pGroup;                     /* PGroup this cache belongs to */
    73     73     int szPage;                         /* Size of allocated pages in bytes */
    74     74     int szExtra;                        /* Size of extra space in bytes */
    75     75     int bPurgeable;                     /* True if cache is purgeable */
    76     76     unsigned int nMin;                  /* Minimum number of pages reserved */
    77     77     unsigned int nMax;                  /* Configured "cache_size" value */
    78     78     unsigned int n90pct;                /* nMax*9/10 */
           79  +  unsigned int iMaxKey;               /* Largest key seen since xTruncate() */
    79     80   
    80     81     /* Hash table of all pages. The following variables may only be accessed
    81     82     ** when the accessor is holding the PGroup mutex.
    82     83     */
    83     84     unsigned int nRecyclable;           /* Number of pages in the LRU list */
    84     85     unsigned int nPage;                 /* Total number of pages in apHash */
    85     86     unsigned int nHash;                 /* Number of slots in apHash[] */
    86     87     PgHdr1 **apHash;                    /* Hash table for fast lookup by key */
    87         -
    88         -  unsigned int iMaxKey;               /* Largest key seen since xTruncate() */
    89     88   };
    90     89   
    91     90   /*
    92     91   ** Each cache entry is represented by an instance of the following 
    93     92   ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
    94     93   ** PgHdr1.pCache->szPage bytes is allocated directly before this structure 
    95     94   ** in memory.
................................................................................
   125    124     int isInit;                    /* True if initialized */
   126    125     int szSlot;                    /* Size of each free slot */
   127    126     int nSlot;                     /* The number of pcache slots */
   128    127     int nReserve;                  /* Try to keep nFreeSlot above this */
   129    128     void *pStart, *pEnd;           /* Bounds of pagecache malloc range */
   130    129     /* Above requires no mutex.  Use mutex below for variable that follow. */
   131    130     sqlite3_mutex *mutex;          /* Mutex for accessing the following: */
   132         -  int nFreeSlot;                 /* Number of unused pcache slots */
   133    131     PgFreeslot *pFree;             /* Free page blocks */
          132  +  int nFreeSlot;                 /* Number of unused pcache slots */
   134    133     /* The following value requires a mutex to change.  We skip the mutex on
   135    134     ** reading because (1) most platforms read a 32-bit integer atomically and
   136    135     ** (2) even if an incorrect value is read, no great harm is done since this
   137    136     ** is really just an optimization. */
   138    137     int bUnderPressure;            /* True if low on PAGECACHE memory */
   139    138   } pcache1_g;
   140    139