Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Unified Diff: third_party/sqlite/amalgamation/sqlite3.c

Issue 1677193003: [sqlite] Implement RecoverPager in terms of sqlite3_file. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@zzsql_recover_handle_review0
Patch Set: Pager doesn't need to know reserved space. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
Download patch
« no previous file with comments | « no previous file | third_party/sqlite/src/src/recover.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/sqlite/amalgamation/sqlite3.c
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 2865501c6bc6a39a1a668c9ae5de4b672a3c5a2e..d96be59580f468646595ee5656749ad0d4bdee25 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -136872,19 +136872,22 @@ static int ascii_strcasecmp(const char *s1, const char *s2){
}
/* Provide access to the pages of a SQLite database in a way similar to SQLite's
-** Pager. Will be re-implemented in terms of sqlite3_file.
+** Pager.
*/
typedef struct RecoverPager RecoverPager;
struct RecoverPager {
- Pager *pSqlitePager; /* SQLite's pager. */
+ sqlite3_file *pSqliteFile; /* Reference to database's file handle */
+ u32 nPageSize; /* Size of pages in pSqliteFile */
};
static void pagerDestroy(RecoverPager *pPager){
+ pPager->pSqliteFile->pMethods->xUnlock(pPager->pSqliteFile, SQLITE_LOCK_NONE);
memset(pPager, 0xA5, sizeof(*pPager));
sqlite3_free(pPager);
}
-static int pagerCreate(Pager *pSqlitePager, u32 nPageSize,
+/* pSqliteFile should already have a SHARED lock. */
+static int pagerCreate(sqlite3_file *pSqliteFile, u32 nPageSize,
RecoverPager **ppPager){
RecoverPager *pPager = sqlite3_malloc(sizeof(RecoverPager));
if( !pPager ){
@@ -136892,28 +136895,35 @@ static int pagerCreate(Pager *pSqlitePager, u32 nPageSize,
}
memset(pPager, 0, sizeof(*pPager));
- pPager->pSqlitePager = pSqlitePager;
+ pPager->pSqliteFile = pSqliteFile;
+ pPager->nPageSize = nPageSize;
*ppPager = pPager;
return SQLITE_OK;
}
/* Matches DbPage (aka PgHdr) from SQLite internals. */
+/* TODO(shess): SQLite by default allocates page metadata in a single allocation
+** such that the page's data and metadata are contiguous, see pcache1AllocPage
+** in pcache1.c. I believe this was intended to reduce malloc churn. It means
+** that Chromium's automated tooling would be unlikely to see page-buffer
+** overruns. I believe that this code is safe, but for now replicate SQLite's
+** approach with kExcessSpace.
+*/
+const int kExcessSpace = 128;
typedef struct RecoverPage RecoverPage;
struct RecoverPage {
- DbPage *pSqlitePage; /* SQLite's page. */
Pgno pgno; /* Page number for this page */
- void *pData; /* Page data */
+ void *pData; /* Page data for pgno */
RecoverPager *pPager; /* The pager this page is part of */
};
static void pageDestroy(RecoverPage *pPage){
- sqlite3PagerUnref(pPage->pSqlitePage);
+ sqlite3_free(pPage->pData);
memset(pPage, 0xA5, sizeof(*pPage));
sqlite3_free(pPage);
}
-static int pageCreate(RecoverPager *pPager, DbPage *pSqlitePage,
- RecoverPage **ppPage){
+static int pageCreate(RecoverPager *pPager, u32 pgno, RecoverPage **ppPage){
RecoverPage *pPage = sqlite3_malloc(sizeof(RecoverPage));
if( !pPage ){
return SQLITE_NOMEM;
@@ -136921,33 +136931,44 @@ static int pageCreate(RecoverPager *pPager, DbPage *pSqlitePage,
memset(pPage, 0, sizeof(*pPage));
pPage->pPager = pPager;
- pPage->pSqlitePage = pSqlitePage;
- pPage->pgno = pSqlitePage->pgno;
- pPage->pData = pSqlitePage->pData;
+ pPage->pgno = pgno;
+ pPage->pData = sqlite3_malloc(pPager->nPageSize + kExcessSpace);
+ if( pPage->pData==NULL ){
+ pageDestroy(pPage);
+ return SQLITE_NOMEM;
+ }
+ memset((u8 *)pPage->pData + pPager->nPageSize, 0, kExcessSpace);
*ppPage = pPage;
return SQLITE_OK;
}
static int pagerGetPage(RecoverPager *pPager, u32 iPage, RecoverPage **ppPage) {
- DbPage *pSqlitePage;
- int rc = sqlite3PagerGet(pPager->pSqlitePager, iPage, &pSqlitePage, 0);
+ sqlite3_int64 iOfst;
+ sqlite3_file *pFile = pPager->pSqliteFile;
+ RecoverPage *pPage;
+ int rc = pageCreate(pPager, iPage, &pPage);
if( rc!=SQLITE_OK ){
return rc;
}
- rc = pageCreate(pPager, pSqlitePage, ppPage);
- if( rc!=SQLITE_OK ){
- sqlite3PagerUnref(pSqlitePage);
+ /* xRead() can return SQLITE_IOERR_SHORT_READ, which should be treated as
+ ** SQLITE_OK plus an EOF indicator. The excess space is zero-filled.
+ */
+ iOfst = ((sqlite3_int64)iPage - 1) * pPager->nPageSize;
+ rc = pFile->pMethods->xRead(pFile, pPage->pData, pPager->nPageSize, iOfst);
+ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ pageDestroy(pPage);
return rc;
}
+ *ppPage = pPage;
return SQLITE_OK;
}
/* For some reason I kept making mistakes with offset calculations. */
static const unsigned char *PageData(RecoverPage *pPage, unsigned iOffset){
- assert( iOffset<=pPage->nPageSize );
+ assert( iOffset<=pPage->pPager->nPageSize );
return (unsigned char *)pPage->pData + iOffset;
}
@@ -136968,8 +136989,10 @@ static const unsigned char *PageHeader(RecoverPage *pPage){
/* Helper to fetch the pager and page size for the named database. */
static int GetPager(sqlite3 *db, const char *zName,
RecoverPager **ppPager, unsigned *pnPageSize){
- Btree *pBt = NULL;
int i, rc;
+ unsigned nPageSize, nReservedSize;
+ sqlite3_file *pFile = NULL;
+ Btree *pBt = NULL;
RecoverPager *pPager;
for( i=0; i<db->nDb; ++i ){
if( ascii_strcasecmp(db->aDb[i].zName, zName)==0 ){
@@ -136981,14 +137004,32 @@ static int GetPager(sqlite3 *db, const char *zName,
return SQLITE_ERROR;
}
- rc = pagerCreate(sqlite3BtreePager(pBt), 0, &pPager);
+ rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_FILE_POINTER, &pFile);
+ if( rc!=SQLITE_OK ) {
+ return rc;
+ } else if( pFile==NULL ){
+ /* The documentation for sqlite3PagerFile() indicates it can return NULL if
+ ** the file has not yet been opened. That should not be possible here...
+ */
+ return SQLITE_MISUSE;
+ }
+
+ /* Get a shared lock to make sure the on-disk version of the file is truth. */
+ rc = pFile->pMethods->xLock(pFile, SQLITE_LOCK_SHARED);
+ if( rc != SQLITE_OK ){
+ return rc;
+ }
+
+ nPageSize = sqlite3BtreeGetPageSize(pBt);
+ nReservedSize = sqlite3BtreeGetOptimalReserve(pBt);
+ rc = pagerCreate(pFile, nPageSize, &pPager);
if( rc!=SQLITE_OK ){
+ pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE);
return rc;
}
*ppPager = pPager;
- *pnPageSize =
- sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetOptimalReserve(pBt);
+ *pnPageSize = nPageSize - nReservedSize;
return SQLITE_OK;
}
« no previous file with comments | « no previous file | third_party/sqlite/src/src/recover.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698