|  | Adds a new API function sqlite3_preload().  This fills the page cache | 
|  | with the first pages of the database. | 
|  |  | 
|  | Index: src/build.c | 
|  | =================================================================== | 
|  | --- src/build.c	2009-09-11 07:02:46.000000000 -0700 | 
|  | +++ src/build.c	2009-09-14 18:16:46.000000000 -0700 | 
|  | @@ -26,6 +26,9 @@ | 
|  | */ | 
|  | #include "sqliteInt.h" | 
|  |  | 
|  | +#include "pager.h" | 
|  | +#include "btree.h" | 
|  | + | 
|  | /* | 
|  | ** This routine is called when a new SQL statement is beginning to | 
|  | ** be parsed.  Initialize the pParse structure as needed. | 
|  | @@ -3659,3 +3662,30 @@ | 
|  | } | 
|  | return pKey; | 
|  | } | 
|  | + | 
|  | +/* Begin preload-cache.patch for Chromium */ | 
|  | +/* See declaration in sqlite3.h for information */ | 
|  | +int sqlite3_preload(sqlite3 *db) | 
|  | +{ | 
|  | +  Pager *pPager; | 
|  | +  Btree *pBt; | 
|  | +  int rc; | 
|  | +  int i; | 
|  | +  int dbsLoaded = 0; | 
|  | + | 
|  | +  for(i=0; i<db->nDb; i++) { | 
|  | +    pBt = db->aDb[i].pBt; | 
|  | +    if( !pBt ) | 
|  | +      continue; | 
|  | +    pPager = sqlite3BtreePager(pBt); | 
|  | +    if( pPager ) { | 
|  | +      rc = sqlite3PagerLoadall(pPager); | 
|  | +      if (rc == SQLITE_OK) | 
|  | +        dbsLoaded++; | 
|  | +    } | 
|  | +  } | 
|  | +  if (dbsLoaded == 0) | 
|  | +    return SQLITE_ERROR; | 
|  | +  return SQLITE_OK; | 
|  | +} | 
|  | +/* End preload-cache.patch for Chromium */ | 
|  | Index: src/sqlite3.h.in | 
|  | =================================================================== | 
|  | --- src/sqlite.h.in	2009-09-09 07:03:20.000000000 -0700 | 
|  | +++ src/sqlite.h.in	2009-09-15 11:34:26.000000000 -0700 | 
|  | @@ -4677,6 +4677,21 @@ | 
|  | */ | 
|  | int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); | 
|  |  | 
|  | +/* Begin preload-cache.patch for Chromium */ | 
|  | +/* | 
|  | +** Preload the databases into the pager cache, up to the maximum size of the | 
|  | +** pager cache. | 
|  | +** | 
|  | +** For a database to be loaded successfully, the pager must be active. That is, | 
|  | +** there must be an open statement on that database. See sqlite3pager_loadall | 
|  | +** | 
|  | +** There might be many databases attached to the given connection. We iterate | 
|  | +** them all and try to load them. If none are loadable successfully, we return | 
|  | +** an error. Otherwise, we return OK. | 
|  | +*/ | 
|  | +int sqlite3_preload(sqlite3 *db); | 
|  | +/* End preload-cache.patch for Chromium */ | 
|  | + | 
|  | /* | 
|  | ** CAPI3REF: Virtual File System Objects {H11200} <S20100> | 
|  | ** | 
|  | Index: src/pager.c | 
|  | =================================================================== | 
|  | --- src/pager.c	2009-09-07 08:58:09.000000000 -0700 | 
|  | +++ src/pager.c	2009-09-15 16:43:07.000000000 -0700 | 
|  | @@ -388,6 +388,16 @@ | 
|  | */ | 
|  | #define PAGER_MAX_PGNO 2147483647 | 
|  |  | 
|  | +/* Begin preload-cache.patch for Chromium */ | 
|  | +/* See comments above the definition. */ | 
|  | +int sqlite3PagerAcquire2( | 
|  | +  Pager *pPager, | 
|  | +  Pgno pgno, | 
|  | +  DbPage **ppPage, | 
|  | +  int noContent, | 
|  | +  unsigned char *pDataToFill); | 
|  | +/* End preload-cache.patch for Chromium */ | 
|  | + | 
|  | #ifndef NDEBUG | 
|  | /* | 
|  | ** Usage: | 
|  | @@ -3788,6 +3798,25 @@ | 
|  | DbPage **ppPage,    /* Write a pointer to the page here */ | 
|  | int noContent       /* Do not bother reading content from disk if true */ | 
|  | ){ | 
|  | +  /* This just passes through to our modified version with NULL data. */ | 
|  | +  return sqlite3PagerAcquire2(pPager, pgno, ppPage, noContent, 0); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | +** This is an internal version of sqlite3PagerAcquire that takes an extra | 
|  | +** parameter of data to use to fill the page with. This allows more efficient | 
|  | +** filling for preloaded data. If this extra parameter is NULL, we'll go to | 
|  | +** the file. | 
|  | +** | 
|  | +** See sqlite3PagerLoadall which uses this function. | 
|  | +*/ | 
|  | +int sqlite3PagerAcquire2( | 
|  | +  Pager *pPager,      /* The pager open on the database file */ | 
|  | +  Pgno pgno,          /* Page number to fetch */ | 
|  | +  DbPage **ppPage,    /* Write a pointer to the page here */ | 
|  | +  int noContent,      /* Do not bother reading content from disk if true */ | 
|  | +  unsigned char* pDataToFill | 
|  | +){ | 
|  | int rc; | 
|  | PgHdr *pPg; | 
|  |  | 
|  | @@ -3870,9 +3899,17 @@ | 
|  | IOTRACE(("ZERO %p %d\n", pPager, pgno)); | 
|  | }else{ | 
|  | assert( pPg->pPager==pPager ); | 
|  | -      rc = readDbPage(pPg); | 
|  | -      if( rc!=SQLITE_OK ){ | 
|  | -        goto pager_acquire_err; | 
|  | +      if( pDataToFill ){ | 
|  | +        /* Just copy from the given memory */ | 
|  | +        memcpy(pPg->pData, pDataToFill, pPager->pageSize); | 
|  | +        CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM; | 
|  | +                                                 goto pager_acquire_err); | 
|  | +      }else{ | 
|  | +        /* Load from disk (old regular sqlite code path) */ | 
|  | +        rc = readDbPage(pPg); | 
|  | +        if( rc!=SQLITE_OK ){ | 
|  | +          goto pager_acquire_err; | 
|  | +        } | 
|  | } | 
|  | } | 
|  | #ifdef SQLITE_CHECK_PAGES | 
|  | @@ -5221,6 +5258,91 @@ | 
|  | } | 
|  | #endif | 
|  |  | 
|  | +/* Begin preload-cache.patch for Chromium */ | 
|  | +/** | 
|  | +** When making large allocations, there is no need to stress the heap and | 
|  | +** potentially hold its lock while we allocate a bunch of memory.  If we know | 
|  | +** the allocation will be large, go directly to the OS instead of the heap. | 
|  | +**/ | 
|  | +static void* allocLarge(size_t size) { | 
|  | +#if SQLITE_OS_WIN | 
|  | +  return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); | 
|  | +#else | 
|  | +  return sqlite3Malloc(size); | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | +static void freeLarge(void* ptr) { | 
|  | +#if SQLITE_OS_WIN | 
|  | +  VirtualFree(ptr, 0, MEM_RELEASE); | 
|  | +#else | 
|  | +  sqlite3_free(ptr); | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | +/** | 
|  | +** Addition: This will attempt to populate the database cache with | 
|  | +** the first N bytes of the file, where N is the total size of the cache. | 
|  | +** Because we can load this as one chunk from the disk, this is much faster | 
|  | +** than loading a subset of the pages one at a time in random order. | 
|  | +** | 
|  | +** The pager must be initialized before this function is called. This means a | 
|  | +* statement must be open that has initialized the pager and is keeping the | 
|  | +** cache in memory. | 
|  | +**/ | 
|  | +int sqlite3PagerLoadall(Pager* pPager) | 
|  | +{ | 
|  | +  int i; | 
|  | +  int rc; | 
|  | +  int nMax; | 
|  | +  int loadSize; | 
|  | +  int loadPages; | 
|  | +  unsigned char *fileData; | 
|  | + | 
|  | +  if (pPager->dbSize < 0 || pPager->pageSize < 0) { | 
|  | +    /* pager not initialized, this means a statement is not open */ | 
|  | +    return SQLITE_MISUSE; | 
|  | +  } | 
|  | + | 
|  | +  /* compute sizes */ | 
|  | +  nMax = sqlite3PcacheGetCachesize(pPager->pPCache); | 
|  | +  if (nMax < pPager->dbSize) | 
|  | +    loadPages = nMax; | 
|  | +  else | 
|  | +    loadPages = pPager->dbSize; | 
|  | +  loadSize = loadPages * pPager->pageSize; | 
|  | + | 
|  | +  /* load the file as one chunk */ | 
|  | +  fileData = allocLarge(loadSize); | 
|  | +  if (! fileData) | 
|  | +    return SQLITE_NOMEM; | 
|  | +  rc = sqlite3OsRead(pPager->fd, fileData, loadSize, 0); | 
|  | +  if (rc != SQLITE_OK) { | 
|  | +    freeLarge(fileData); | 
|  | +    return rc; | 
|  | +  } | 
|  | + | 
|  | +  /* Copy the data to each page. Note that the page numbers we pass to _get | 
|  | +   * are one-based, 0 is a marker for no page. We also need to check that we | 
|  | +   * haven't loaded more pages than the cache can hold total. There may have | 
|  | +   * already been a few pages loaded before, so we may fill the cache before | 
|  | +   * loading all of the pages we want to. | 
|  | +   */ | 
|  | +  for(i=1; | 
|  | +      i <= loadPages && sqlite3PcachePagecount(pPager->pPCache) < nMax; | 
|  | +      i++) { | 
|  | +    DbPage *pPage = 0; | 
|  | +    rc = sqlite3PagerAcquire2(pPager, i, &pPage, 0, | 
|  | +                              &fileData[(i-1)*(i64)pPager->pageSize]); | 
|  | +    if (rc != SQLITE_OK) | 
|  | +      break; | 
|  | +    sqlite3PagerUnref(pPage); | 
|  | +  } | 
|  | +  freeLarge(fileData); | 
|  | +  return SQLITE_OK; | 
|  | +} | 
|  | +/* End preload-cache.patch for Chromium */ | 
|  | + | 
|  | /* | 
|  | ** Return a pointer to the data for the specified page. | 
|  | */ | 
|  | Index: src/pager.h | 
|  | =================================================================== | 
|  | --- src/pager.h	2009-09-04 13:37:42.000000000 -0700 | 
|  | +++ src/pager.h	2009-09-15 11:31:55.000000000 -0700 | 
|  | @@ -143,6 +143,8 @@ | 
|  | sqlite3_file *sqlite3PagerFile(Pager*); | 
|  | const char *sqlite3PagerJournalname(Pager*); | 
|  | int sqlite3PagerNosync(Pager*); | 
|  | +/* This function is for preload-cache.patch for Chromium: */ | 
|  | +int sqlite3PagerLoadall(Pager*); | 
|  | void *sqlite3PagerTempSpace(Pager*); | 
|  | int sqlite3PagerIsMemdb(Pager*); | 
|  |  | 
|  | Index: src/pcache.c | 
|  | =================================================================== | 
|  | --- src/pcache.c	2009-09-04 13:37:42.000000000 -0700 | 
|  | +++ src/pcache.c	2009-09-15 16:41:55.000000000 -0700 | 
|  | @@ -542,14 +542,12 @@ | 
|  | return nPage; | 
|  | } | 
|  |  | 
|  | -#ifdef SQLITE_TEST | 
|  | /* | 
|  | ** Get the suggested cache-size value. | 
|  | */ | 
|  | int sqlite3PcacheGetCachesize(PCache *pCache){ | 
|  | return pCache->nMax; | 
|  | } | 
|  | -#endif | 
|  |  | 
|  | /* | 
|  | ** Set the suggested cache-size value. | 
|  | Index: src/pcache.h | 
|  | =================================================================== | 
|  | --- src/pcache.h	2009-09-04 13:37:42.000000000 -0700 | 
|  | +++ src/pcache.h	2009-09-15 16:41:52.000000000 -0700 | 
|  | @@ -139,9 +139,7 @@ | 
|  | ** of the suggested cache-sizes. | 
|  | */ | 
|  | void sqlite3PcacheSetCachesize(PCache *, int); | 
|  | -#ifdef SQLITE_TEST | 
|  | int sqlite3PcacheGetCachesize(PCache *); | 
|  | -#endif | 
|  |  | 
|  | #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT | 
|  | /* Try to return memory used by the pcache module to the main memory heap */ |