Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Changes to the backup API: (1) if a negative number is passed as the second argument to backup_step(), this is interpreted as "copy all remaining pages" and (2) if backup_finish() is called after backup_step() fails with a BUSY or LOCKED error, then this error is also returned by backup_finish() (same handling as for other errors encountered by backup_step()). (CVS 6266) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9b8c8b18cf6b7d44d5fd64760537bc03 |
User & Date: | danielk1977 2009-02-06 05:59:44.000 |
Context
2009-02-09
| ||
05:18 | Attempt to reproduce ticket #3643. No luck yet. (CVS 6267) (check-in: 8f2f98d247 user: danielk1977 tags: trunk) | |
2009-02-06
| ||
05:59 | Changes to the backup API: (1) if a negative number is passed as the second argument to backup_step(), this is interpreted as "copy all remaining pages" and (2) if backup_finish() is called after backup_step() fails with a BUSY or LOCKED error, then this error is also returned by backup_finish() (same handling as for other errors encountered by backup_step()). (CVS 6266) (check-in: 9b8c8b18cf user: danielk1977 tags: trunk) | |
2009-02-05
| ||
17:00 | Fix a test case that was still using the old pending_byte mechanism. (CVS 6265) (check-in: 08ec4f2c39 user: drh tags: trunk) | |
Changes
Changes to src/backup.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. ** ** $Id: backup.c,v 1.8 2009/02/06 05:59:44 danielk1977 Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" /* Macro to find the minimum of two numeric values. */ #ifndef MIN |
︙ | ︙ | |||
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | p->pSrc->nBackup++; } sqlite3_mutex_leave(pDestDb->mutex); sqlite3_mutex_leave(pSrcDb->mutex); return p; } /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; assert( p->bDestLocked ); | > > > > > > > > > | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | p->pSrc->nBackup++; } sqlite3_mutex_leave(pDestDb->mutex); sqlite3_mutex_leave(pSrcDb->mutex); return p; } /* ** Argument rc is an SQLite error code. Return true if this error is ** considered fatal if encountered during a backup operation. All errors ** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED. */ static int isFatalError(int rc){ return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED); } /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the ** page sizes of the source and destination differ. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){ |
︙ | ︙ | |||
254 255 256 257 258 259 260 | sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } rc = p->rc; | | > > | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } rc = p->rc; if( !isFatalError(rc) ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ /* If the source pager is currently in a write-transaction, return ** SQLITE_LOCKED immediately. */ if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ rc = SQLITE_LOCKED; }else{ rc = SQLITE_OK; } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) ){ p->bDestLocked = 1; |
︙ | ︙ | |||
291 292 293 294 295 296 297 | /* Now that there is a read-lock on the source database, query the ** source pager for the number of pages in the database. */ if( rc==SQLITE_OK ){ rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage); } | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | /* Now that there is a read-lock on the source database, query the ** source pager for the number of pages in the database. */ if( rc==SQLITE_OK ){ rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage); } for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); if( rc==SQLITE_OK ){ rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg)); sqlite3PagerUnref(pSrcPg); |
︙ | ︙ | |||
406 407 408 409 410 411 412 | if( bCloseTrans ){ TESTONLY( int rc2 ); TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc); assert( rc2==SQLITE_OK ); } | < | < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | if( bCloseTrans ){ TESTONLY( int rc2 ); TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc); assert( rc2==SQLITE_OK ); } p->rc = rc; } if( p->pDestDb ){ sqlite3_mutex_leave(p->pDestDb->mutex); } sqlite3BtreeLeave(p->pSrc); sqlite3_mutex_leave(p->pSrcDb->mutex); return rc; |
︙ | ︙ | |||
495 496 497 498 499 500 501 | ** corresponding to the source database is held when this function is ** called. */ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ sqlite3_backup *p; /* Iterator variable */ for(p=pBackup; p; p=p->pNext){ assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); | | > | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | ** corresponding to the source database is held when this function is ** called. */ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ sqlite3_backup *p; /* Iterator variable */ for(p=pBackup; p; p=p->pNext){ assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); if( !isFatalError(p->rc) && iPage<p->iNext ){ /* The backup process p has already copied page iPage. But now it ** has been modified by a transaction on the source pager. Copy ** the new data into the backup. */ int rc = backupOnePage(p, iPage, aData); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); if( rc!=SQLITE_OK ){ p->rc = rc; } } } } |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** ** @(#) $Id: sqlite.h.in,v 1.428 2009/02/06 05:59:44 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
6783 6784 6785 6786 6787 6788 6789 | ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** <b>sqlite3_backup_step()</b> ** ** Function [sqlite3_backup_step()] is used to copy up to nPage pages between ** the source and destination databases, where nPage is the value of the | | > | 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 | ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** <b>sqlite3_backup_step()</b> ** ** Function [sqlite3_backup_step()] is used to copy up to nPage pages between ** the source and destination databases, where nPage is the value of the ** second parameter passed to sqlite3_backup_step(). If nPage is a negative ** value, all remaining source pages are copied. If the required pages are ** succesfully copied, but there are still more pages to copy before the ** backup is complete, it returns [SQLITE_OK]. If no error occured and there ** are no more pages to copy, then [SQLITE_DONE] is returned. If an error ** occurs, then an SQLite error code is returned. As well as [SQLITE_OK] and ** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], ** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. |
︙ | ︙ |
Changes to test/backup.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2009 January 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_backup_XXX API. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2009 January 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_backup_XXX API. # # $Id: backup.test,v 1.4 2009/02/06 05:59:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl #--------------------------------------------------------------------- # Test organization: # |
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # backup-5.*: Test the source database being modified during a backup. # # backup-6.*: Test the backup_remaining() and backup_pagecount() APIs. # # backup-7.*: Test SQLITE_BUSY and SQLITE_LOCKED errors. # # backup-8.*: Test multiple simultaneous backup operations. # proc data_checksum {db file} { $db one "SELECT md5sum(a, b) FROM ${file}.t1" } proc test_contents {name db1 file1 db2 file2} { $db2 eval {select * from sqlite_master} $db1 eval {select * from sqlite_master} set checksum [data_checksum $db2 $file2] | > > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # backup-5.*: Test the source database being modified during a backup. # # backup-6.*: Test the backup_remaining() and backup_pagecount() APIs. # # backup-7.*: Test SQLITE_BUSY and SQLITE_LOCKED errors. # # backup-8.*: Test multiple simultaneous backup operations. # # backup-9.*: Test that passing a negative argument to backup_step() is # interpreted as "copy the whole file". # proc data_checksum {db file} { $db one "SELECT md5sum(a, b) FROM ${file}.t1" } proc test_contents {name db1 file1 db2 file2} { $db2 eval {select * from sqlite_master} $db1 eval {select * from sqlite_master} set checksum [data_checksum $db2 $file2] |
︙ | ︙ | |||
759 760 761 762 763 764 765 | } {main shared temp closed} do_test backup-8.10 { execsql COMMIT } {} catch { db2 close } catch { db3 close } | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | } {main shared temp closed} do_test backup-8.10 { execsql COMMIT } {} catch { db2 close } catch { db3 close } #----------------------------------------------------------------------- # The following tests, backup-9.*, test that: # # * Passing 0 as an argument to sqlite3_backup_step() means no pages # are backed up (backup-9.1.*), and # * Passing a negative value as an argument to sqlite3_backup_step() means # all pages are backed up (backup-9.2.*). # # These tests reuse the database "test.db" left over from backup-7.*. # do_test backup-9.1.1 { sqlite3 db2 test2.db sqlite3_backup B db2 main db main B step 1 } {SQLITE_OK} do_test backup-9.1.2 { set nRemaining [B remaining] expr {$nRemaining>100} } {1} do_test backup-9.1.3 { B step 0 } {SQLITE_OK} do_test backup-9.1.4 { B remaining } $nRemaining do_test backup-9.2.1 { B step -1 } {SQLITE_DONE} do_test backup-9.2.2 { B remaining } {0} do_test backup-9.2.3 { B finish } {SQLITE_OK} catch {db2 close} finish_test |