blob: 7a361d19f0a477016a4312f6b38654f0933cf353 [file] [log] [blame]
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 */