Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Must hold mutex on the destination during backups. Add documentation to warn programmers that attempting to use the destination connection during a backup can lead to deadlock. (CVS 6246) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5f6c06b974f26532264467ace603b6f1 |
User & Date: | drh 2009-02-03 21:13:08.000 |
Context
2009-02-03
| ||
22:17 | A backup must clear the internal schema of the destination database so that the schema will be reloaded for the next sqlite3_prepare() (CVS 6247) (check-in: 76f23a4394 user: drh tags: trunk) | |
21:13 | Must hold mutex on the destination during backups. Add documentation to warn programmers that attempting to use the destination connection during a backup can lead to deadlock. (CVS 6246) (check-in: 5f6c06b974 user: drh tags: trunk) | |
19:55 | Fixed postToParent() return type (Tcl_ThreadCreateType) in test_thread.c to compile with MSVC. Removed a few compiler warnings. Test harness change only. (CVS 6245) (check-in: e9475abaf8 user: shane 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.2 2009/02/03 21:13:08 drh Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" /* Macro to find the minimum of two numeric values. */ #ifndef MIN |
︙ | ︙ | |||
122 123 124 125 126 127 128 | const char *zDestDb, /* Name of database within pDestDb */ sqlite3* pSrcDb, /* Database connection to read from */ const char *zSrcDb /* Name of database within pSrcDb */ ){ sqlite3_backup *p; /* Value to return */ /* Lock the source database handle. The destination database | > | | > > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | const char *zDestDb, /* Name of database within pDestDb */ sqlite3* pSrcDb, /* Database connection to read from */ const char *zSrcDb /* Name of database within pSrcDb */ ){ sqlite3_backup *p; /* Value to return */ /* Lock the source database handle. The destination database ** handle is not locked in this routine, but it is locked in ** sqlite3_backup_step(). The user is required to ensure that no ** other thread accesses the destination handle for the duration ** of the backup operation. Any attempt to use the destination ** database connection while a backup is in progress may cause ** a malfunction or a deadlock. */ sqlite3_mutex_enter(pSrcDb->mutex); if( pSrcDb==pDestDb ){ sqlite3Error( pDestDb, SQLITE_ERROR, "Source and destination handles must be distinct" ); |
︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 | ** Copy nPage pages from the source b-tree to the destination. */ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); rc = p->rc; if( rc==SQLITE_OK ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage; /* Size of source db in pages */ | > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | ** Copy nPage pages from the source b-tree to the destination. */ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); sqlite3_mutex_enter(p->pDestDb->mutex); rc = p->rc; if( rc==SQLITE_OK ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage; /* Size of source db in pages */ |
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | assert( rc2==SQLITE_OK ); } if( rc!=SQLITE_LOCKED && rc!=SQLITE_BUSY ){ p->rc = rc; } } sqlite3BtreeLeave(p->pSrc); sqlite3_mutex_leave(p->pSrcDb->mutex); return rc; } /* ** Release all resources associated with an sqlite3_backup* handle. */ int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ sqlite3_mutex *mutex; /* Mutex to protect source database */ int rc; /* Value to return */ /* Enter the mutexes */ sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); mutex = p->pSrcDb->mutex; /* Detach this backup from the source pager. */ if( p->pDestDb ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); while( *pp!=p ){ pp = &(*pp)->pNext; } *pp = p->pNext; p->pSrc->nBackup--; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; sqlite3Error(p->pDestDb, rc, 0); /* Exit the mutexes and free the backup context structure. */ sqlite3BtreeLeave(p->pSrc); if( p->pDestDb ){ sqlite3_free(p); } sqlite3_mutex_leave(mutex); return rc; } | > > > | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | assert( rc2==SQLITE_OK ); } if( rc!=SQLITE_LOCKED && rc!=SQLITE_BUSY ){ p->rc = rc; } } sqlite3_mutex_leave(p->pDestDb->mutex); sqlite3BtreeLeave(p->pSrc); sqlite3_mutex_leave(p->pSrcDb->mutex); return rc; } /* ** Release all resources associated with an sqlite3_backup* handle. */ int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ sqlite3_mutex *mutex; /* Mutex to protect source database */ int rc; /* Value to return */ /* Enter the mutexes */ sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); mutex = p->pSrcDb->mutex; sqlite3_mutex_enter(p->pDestDb->mutex); /* Detach this backup from the source pager. */ if( p->pDestDb ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); while( *pp!=p ){ pp = &(*pp)->pNext; } *pp = p->pNext; p->pSrc->nBackup--; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; sqlite3Error(p->pDestDb, rc, 0); /* Exit the mutexes and free the backup context structure. */ sqlite3_mutex_leave(p->pDestDb->mutex); sqlite3BtreeLeave(p->pSrc); if( p->pDestDb ){ sqlite3_free(p); } sqlite3_mutex_leave(mutex); return rc; } |
︙ | ︙ | |||
552 553 554 555 556 557 558 | } sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; } #endif /* SQLITE_OMIT_VACUUM */ | < | 559 560 561 562 563 564 565 | } sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; } #endif /* SQLITE_OMIT_VACUUM */ |
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.426 2009/02/03 21:13:08 drh 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++. |
︙ | ︙ | |||
6880 6881 6882 6883 6884 6885 6886 | ** ** However, the application must guarantee that the destination database ** connection handle is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). Unfortunately SQLite does not currently check ** for this, if the application does use the destination [database connection] ** for some other purpose during a backup operation, things may appear to | | > > | 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 | ** ** However, the application must guarantee that the destination database ** connection handle is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). Unfortunately SQLite does not currently check ** for this, if the application does use the destination [database connection] ** for some other purpose during a backup operation, things may appear to ** work correctly but in fact be subtly malfunctioning. Use of the ** destination database connection while a backup is in progress might ** also cause a mutex deadlock. ** ** Furthermore, if running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the file-system file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). |
︙ | ︙ |