/ Check-in [1956a4ce]
Login

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

Overview
Comment:Performance improvements in moveToChild() by shifting some work over to getAndInitPage(). Net improvement is about 800K cycles at cost of 30 bytes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1956a4ce8eca650d98a7f68fd2d82eb8a3d6069f
User & Date: drh 2015-06-27 19:45:03
Context
2015-06-27
20:55
Enhancements to the previous check-in to make it a little smaller and faster. check-in: 291d9e0c user: drh tags: trunk
19:45
Performance improvements in moveToChild() by shifting some work over to getAndInitPage(). Net improvement is about 800K cycles at cost of 30 bytes. check-in: 1956a4ce user: drh tags: trunk
15:51
Manually inline the call from getAndInitPage() to btreeGetPage() for a savings of 2.5 million cycles at a cost of less than 100 bytes. check-in: 7f65b96b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  1905   1905   u32 sqlite3BtreeLastPage(Btree *p){
  1906   1906     assert( sqlite3BtreeHoldsMutex(p) );
  1907   1907     assert( ((p->pBt->nPage)&0x8000000)==0 );
  1908   1908     return btreePagecount(p->pBt);
  1909   1909   }
  1910   1910   
  1911   1911   /*
  1912         -** Get a page from the pager and initialize it.  This routine is just a
  1913         -** convenience wrapper around separate calls to btreeGetPage() and 
  1914         -** btreeInitPage().
         1912  +** Get a page from the pager and initialize it.
  1915   1913   **
  1916         -** If an error occurs, then the value *ppPage is set to is undefined. It
         1914  +** If pCur!=0 then the page acquired will be added to that cursor.
         1915  +** If the fetch fails, this routine must decrement pCur->iPage.
         1916  +**
         1917  +** The page is fetched as read-write unless pCur is not NULL and is
         1918  +** a read-only cursor.
         1919  +**
         1920  +** If an error occurs, then *ppPage is undefined. It
  1917   1921   ** may remain unchanged, or it may be set to an invalid value.
  1918   1922   */
  1919   1923   static int getAndInitPage(
  1920   1924     BtShared *pBt,                  /* The database file */
  1921   1925     Pgno pgno,                      /* Number of the page to get */
  1922   1926     MemPage **ppPage,               /* Write the page pointer here */
  1923         -  int bReadonly                   /* PAGER_GET_READONLY or 0 */
         1927  +  BtCursor *pCur,                 /* Cursor to receive the page, or NULL */
         1928  +  int bReadOnly                   /* True for a read-only page */
  1924   1929   ){
  1925   1930     int rc;
         1931  +  DbPage *pDbPage;
  1926   1932     assert( sqlite3_mutex_held(pBt->mutex) );
  1927         -  assert( bReadonly==PAGER_GET_READONLY || bReadonly==0 );
         1933  +  assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
         1934  +  assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
  1928   1935   
  1929   1936     if( pgno>btreePagecount(pBt) ){
  1930   1937       rc = SQLITE_CORRUPT_BKPT;
  1931         -  }else{
  1932         -    DbPage *pDbPage;
  1933         -    rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadonly);
  1934         -    if( rc ) return rc;
  1935         -    *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
  1936         -    if( (*ppPage)->isInit==0 ){
  1937         -      rc = btreeInitPage(*ppPage);
  1938         -      if( rc!=SQLITE_OK ){
  1939         -        releasePage(*ppPage);
  1940         -      }
         1938  +    goto getAndInitPage_error;
         1939  +  }
         1940  +  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
         1941  +  if( rc ){
         1942  +    goto getAndInitPage_error;
         1943  +  }
         1944  +  *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
         1945  +  if( (*ppPage)->isInit==0 ){
         1946  +    rc = btreeInitPage(*ppPage);
         1947  +    if( rc!=SQLITE_OK ){
         1948  +      releasePage(*ppPage);
         1949  +      goto getAndInitPage_error;
  1941   1950       }
  1942   1951     }
         1952  +
         1953  +  /* If obtaining a page for a cursor, we must verify that the page is
         1954  +  ** compatible with the cursor */
         1955  +  if( pCur && pCur->iPage>0
         1956  +   && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->apPage[0]->intKey)
         1957  +  ){
         1958  +    rc = SQLITE_CORRUPT_BKPT;
         1959  +    releasePage(*ppPage);
         1960  +    goto getAndInitPage_error;
         1961  +  }
  1943   1962   
  1944   1963     testcase( pgno==0 );
  1945   1964     assert( pgno!=0 || rc==SQLITE_CORRUPT );
         1965  +  return SQLITE_OK;
         1966  +
         1967  +getAndInitPage_error:
         1968  +  if( pCur ) pCur->iPage--;
  1946   1969     return rc;
  1947   1970   }
  1948   1971   
  1949   1972   /*
  1950   1973   ** Release a MemPage.  This should be called once for each prior
  1951   1974   ** call to btreeGetPage.
  1952   1975   */
................................................................................
  4024   4047     pCur->pgnoRoot = (Pgno)iTable;
  4025   4048     pCur->iPage = -1;
  4026   4049     pCur->pKeyInfo = pKeyInfo;
  4027   4050     pCur->pBtree = p;
  4028   4051     pCur->pBt = pBt;
  4029   4052     assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
  4030   4053     pCur->curFlags = wrFlag;
         4054  +  pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
  4031   4055     pCur->pNext = pBt->pCursor;
  4032   4056     if( pCur->pNext ){
  4033   4057       pCur->pNext->pPrev = pCur;
  4034   4058     }
  4035   4059     pBt->pCursor = pCur;
  4036   4060     pCur->eState = CURSOR_INVALID;
  4037   4061     return SQLITE_OK;
................................................................................
  4637   4661   **
  4638   4662   ** This function returns SQLITE_CORRUPT if the page-header flags field of
  4639   4663   ** the new child page does not match the flags field of the parent (i.e.
  4640   4664   ** if an intkey page appears to be the parent of a non-intkey page, or
  4641   4665   ** vice-versa).
  4642   4666   */
  4643   4667   static int moveToChild(BtCursor *pCur, u32 newPgno){
  4644         -  int rc;
  4645         -  int i = pCur->iPage;
  4646         -  MemPage *pNewPage;
  4647   4668     BtShared *pBt = pCur->pBt;
  4648   4669   
  4649   4670     assert( cursorHoldsMutex(pCur) );
  4650   4671     assert( pCur->eState==CURSOR_VALID );
  4651   4672     assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
  4652   4673     assert( pCur->iPage>=0 );
  4653   4674     if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
  4654   4675       return SQLITE_CORRUPT_BKPT;
  4655   4676     }
  4656         -  rc = getAndInitPage(pBt, newPgno, &pNewPage,
  4657         -               (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
  4658         -  if( rc ) return rc;
  4659         -  pCur->apPage[i+1] = pNewPage;
  4660         -  pCur->aiIdx[i+1] = 0;
  4661         -  pCur->iPage++;
  4662         -
  4663   4677     pCur->info.nSize = 0;
  4664   4678     pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4665         -  if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
  4666         -    return SQLITE_CORRUPT_BKPT;
  4667         -  }
  4668         -  return SQLITE_OK;
         4679  +  pCur->iPage++;
         4680  +  pCur->aiIdx[pCur->iPage] = 0;
         4681  +  return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
         4682  +                        pCur, pCur->curPagerFlags);
  4669   4683   }
  4670   4684   
  4671   4685   #if SQLITE_DEBUG
  4672   4686   /*
  4673   4687   ** Page pParent is an internal (non-leaf) tree page. This function 
  4674   4688   ** asserts that page number iChild is the left-child if the iIdx'th
  4675   4689   ** cell in page pParent. Or, if iIdx is equal to the total number of
................................................................................
  4756   4770         assert( pCur->apPage[pCur->iPage]!=0 );
  4757   4771         releasePageNotNull(pCur->apPage[pCur->iPage--]);
  4758   4772       }
  4759   4773     }else if( pCur->pgnoRoot==0 ){
  4760   4774       pCur->eState = CURSOR_INVALID;
  4761   4775       return SQLITE_OK;
  4762   4776     }else{
         4777  +    assert( pCur->iPage==(-1) );
         4778  +    pCur->iPage = 0;
  4763   4779       rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
  4764         -                 (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
         4780  +                        pCur, pCur->curPagerFlags);
  4765   4781       if( rc!=SQLITE_OK ){
  4766   4782         pCur->eState = CURSOR_INVALID;
  4767   4783         return rc;
  4768   4784       }
  4769   4785       pCur->iPage = 0;
  4770   4786     }
  4771   4787     pRoot = pCur->apPage[0];
................................................................................
  6959   6975     if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){
  6960   6976       pRight = &pParent->aData[pParent->hdrOffset+8];
  6961   6977     }else{
  6962   6978       pRight = findCell(pParent, i+nxDiv-pParent->nOverflow);
  6963   6979     }
  6964   6980     pgno = get4byte(pRight);
  6965   6981     while( 1 ){
  6966         -    rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
         6982  +    rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
  6967   6983       if( rc ){
  6968   6984         memset(apOld, 0, (i+1)*sizeof(MemPage*));
  6969   6985         goto balance_cleanup;
  6970   6986       }
  6971   6987       nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
  6972   6988       if( (i--)==0 ) break;
  6973   6989   
................................................................................
  8276   8292     int hdr;
  8277   8293     u16 szCell;
  8278   8294   
  8279   8295     assert( sqlite3_mutex_held(pBt->mutex) );
  8280   8296     if( pgno>btreePagecount(pBt) ){
  8281   8297       return SQLITE_CORRUPT_BKPT;
  8282   8298     }
  8283         -  rc = getAndInitPage(pBt, pgno, &pPage, 0);
         8299  +  rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
  8284   8300     if( rc ) return rc;
  8285   8301     if( pPage->bBusy ){
  8286   8302       rc = SQLITE_CORRUPT_BKPT;
  8287   8303       goto cleardatabasepage_out;
  8288   8304     }
  8289   8305     pPage->bBusy = 1;
  8290   8306     hdr = pPage->hdrOffset;

Changes to src/btreeInt.h.

   514    514     i64 nKey;                 /* Size of pKey, or last integer key */
   515    515     void *pKey;               /* Saved key that was cursor last known position */
   516    516     Pgno pgnoRoot;            /* The root page of this tree */
   517    517     int nOvflAlloc;           /* Allocated size of aOverflow[] array */
   518    518     int skipNext;    /* Prev() is noop if negative. Next() is noop if positive.
   519    519                      ** Error code if eState==CURSOR_FAULT */
   520    520     u8 curFlags;              /* zero or more BTCF_* flags defined below */
          521  +  u8 curPagerFlags;         /* Flags to send to sqlite3PagerAcquire() */
   521    522     u8 eState;                /* One of the CURSOR_XXX constants (see below) */
   522    523     u8 hints;                             /* As configured by CursorSetHints() */
   523    524     i16 iPage;                            /* Index of current page in apPage */
   524    525     u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
   525    526     MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
   526    527   };
   527    528