1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Add part of the btree layer of the shared-cache feature. (CVS 2848)

FossilOrigin-Name: 2afcad990190af97d1ad0010f211a5ca8f0fd745
This commit is contained in:
danielk1977
2005-12-30 16:28:01 +00:00
parent faa59554c3
commit aef0bf6429
19 changed files with 1014 additions and 278 deletions

View File

@ -1,5 +1,5 @@
C Add\ssupport\sfor\sCREATE\sTABLE\sIF\sNOT\sEXISTS.\s(CVS\s2847)
D 2005-12-29T23:33:54
C Add\spart\sof\sthe\sbtree\slayer\sof\sthe\sshared-cache\sfeature.\s(CVS\s2848)
D 2005-12-30T16:28:02
F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -34,8 +34,8 @@ F src/alter.c 5905a3372379daa4f860199452b4de5a836e53f3
F src/analyze.c ea42005eed52c382fcc7ef66969e7f1858597633
F src/attach.c 07822dbd2dcf6de548aba6cb24142aec800fa3b6
F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
F src/btree.c 2b2651e0f6f9f8c5976b662fbfab7fc8f54f02c9
F src/btree.h 8ff86378bb5af0cde282614c16bf0c0190b6d216
F src/btree.c ccb912b1f27b6de4ed9f8ab5289a5491c9be5bc8
F src/btree.h d6481f9253f0b5fa40b35da4b93a54d0f9c5f9f2
F src/build.c bb4c9df2583246728167659d401fd75aa3d9997f
F src/callback.c 62066afd516f220575e81b1a1239ab92a2eae252
F src/complete.c df1681cef40dec33a286006981845f87b194e7a4
@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c a5629e462560d6aa9be7e0dafb6ed1518bb623bb
F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
F src/main.c ec04b37605752a4294ae98f2b7d78ba62950ba2f
F src/main.c c93f80d1fcaf3ed508d62a163819b10a730c2fb7
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
F src/os.c 7b4a002d9c9421580276db55d2329636a604e8ef
F src/os.h e941992043b127fdb1bd114f0b4319ae1c4562a7
@ -59,7 +59,7 @@ F src/os_unix.c 6394d2fa3a8bfbceb227579b44b4b343b5b54a8f
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 9feb97f49b93d451f8ef7c5dd388e05a44647dc6
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c 5227ea29acbea4b6a9c6f1dfd3e8493de5fc2a93
F src/pager.c 681b4e39d581ead8fd54283176138bec924a4bae
F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f
F src/parse.y fea607bdc0f4440e001ca277a49f507b5a3fb1e5
F src/pragma.c 8883b4d34796efa315bdd0ec1b03f580ef1575b9
@ -68,13 +68,13 @@ F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57
F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
F src/sqlite.h.in 015e02efa9e8bafa31b6c270116369ddff4e9803
F src/sqliteInt.h 3541350fd0617225a61c6ff4af5e6e9d33bc3794
F src/sqlite.h.in ba3a29daa6a16e054191ccb384a981964e882a1d
F src/sqliteInt.h bb648c5274d67060cb13f0cd0da141aff1205358
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c ce481c0a21a20641cdfe87c9cbbb328cfb3a58b9
F src/test1.c 4691cc7235683324791a0be560308ca338de36de
F src/tclsqlite.c 230a367c50d84f15e92545f3d468acf192726696
F src/test1.c 7374e6576e15a85f11d6032ea8a69d99643695b3
F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97
F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
F src/test6.c cb811391ec0b7c75f29e545d4820a9cf19f3637e
@ -88,7 +88,7 @@ F src/vdbe.c 8b0d676bcd8d8b12606f684ea2d7934147b40101
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
F src/vdbeInt.h 9b78ba00cc006bff17e04a54ba3ded9fc7810a10
F src/vdbeapi.c b270b680cbc5d20b5a1abfdb08339667985df94e
F src/vdbeaux.c 9dc10a70f0f697b9ede43237522e93ef863763e1
F src/vdbeaux.c e7c116d4b14868d5fe570e361c6872839b6ab07a
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c deba8d6e3727643924b210a8c531a496c2b8d386
F src/where.c 0296a20c2e2a39c0cb785efe471fd1958a5259f3
@ -96,11 +96,11 @@ F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 55706917a12cd616440d50c35323747b4a9f03c3
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
F test/alter2.test 60ba0a7057dc71ad630a1cc7c487104346849d50
F test/alter3.test d4eecd8dbd008d0e66f1c201fa6dc2edca853c38
F test/alter3.test 6e144ea3dcc395afcc28e794bb532be83dc8fdcb
F test/altermalloc.test 6e1f404ec021eb2ba6582e3c77b0a35cf206b7af
F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0
F test/attach.test dae07fa1554b618b9cc4c7bc349b3bc1a532180e
F test/attach2.test 4c31484096fd24b7b98487f9c6d04d9f3f156c6c
F test/attach2.test 609604393708c3d3227f7c316d15b25d015aa4dd
F test/attach3.test 63013383adc4380af69779f34f4af19bd49f7cbe
F test/attachmalloc.test cdb26c42850f04698377ccec05f5fa89d987837c
F test/auth.test 973ae7274eae32c4453fbbcbd0ec2b80c5b1eeb3
@ -184,7 +184,7 @@ F test/malloc.test a5ed721cf7d1b12602ede4f98c11b65ab1582cc0
F test/malloc2.test e6e321db96d6c94cb18bf82ad7215070c41e624e
F test/malloc3.test 9797d39eca7087a1022bcc0eb0b22215475c9698
F test/malloc4.test 2e29d155eb4b4808019ef47eeedfcbe9e09e0f05
F test/malloc5.test 8dd58affc441a726d16448a7188ab175bc9e7280
F test/malloc5.test cd31d7be49690abc6845baa1f83bfd7b789ee187
F test/manydb.test d81debbf5871242e3b5df1d3bb5e14c50431b6f8
F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea
F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac
@ -204,7 +204,7 @@ F test/pagesize.test cbc6a312b6f6c0f02619b189985df2a14164b690
F test/pragma.test 95ea907adf68459e1be6f310c9ae94d1d59c465b
F test/printf.test 9e10c74e16bf889f8495ddb3d6f5f891e75ff1b7
F test/progress.test 16496001da445e6534afb94562c286708316d82f x
F test/quick.test 4be1733beae790f4a61fb7c7827b396c95375d7e
F test/quick.test 24ef81e4e9c1784e7f081e7ce4576c15659b97a7
F test/quote.test 5891f2338980916cf7415484b4ce785294044adb
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
@ -218,6 +218,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b
F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4
F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
F test/shared.test 1f68f8aecf5064d1da2fb2f316bbb6e70054f08e
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/subquery.test e6de53332c0301b3cfa34edc3f3cd5fa1e859efd
F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
@ -226,7 +227,7 @@ F test/table.test 149b76a28bbe2a1cd799232e4ae5133881e1902a
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
F test/tclsqlite.test 19578d32a7692311918caf0ae3521d19525bcb62
F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875
F test/tester.tcl fae9e5b9ca4cfda10a6a52e95f7ebf731e52f3e5
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
@ -242,7 +243,7 @@ F test/tkt1536.test 83ff7a7b6e248016f8d682d4f7a4ae114070d466
F test/tkt1537.test 8e6c8399b5be8abeaac18ca17133990806b175fa
F test/tkt1567.test 18023cc3626a365f0118e17b66decedec93b1a6f
F test/trace.test 9fd28695c463b90c2d32c387a432e01eb26e8ccf
F test/trans.test 10506dc30305cfb8c4098359f7f6f64786f69c5e
F test/trans.test abd2f74c5685b156d79438e6e812db5bf984eea4
F test/trigger1.test 152aed5a1fa90709fe171f2ca501a6b7f7901479
F test/trigger2.test dea71f4b05e22896e72527278bc8ef71b7475bf2
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
@ -331,7 +332,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P a88580bce045ee1c11cc6fd986ee7bab043ded4f
R 2caf522c84042dde1b412f517fefbe54
U drh
Z a798ff6c2214d388933326d22672d220
P 0bd9e35fd22946640f4fb1c1874922ae096916f7
R 4baca77991845360aad68bb03e406c8e
U danielk1977
Z 2dfbc30edccb7b747e04832859ba5105

View File

@ -1 +1 @@
0bd9e35fd22946640f4fb1c1874922ae096916f7
2afcad990190af97d1ad0010f211a5ca8f0fd745

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.65 2005/12/16 15:24:29 danielk1977 Exp $
** @(#) $Id: btree.h,v 1.66 2005/12/30 16:28:02 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@ -36,10 +36,12 @@
*/
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */
Btree **, /* Return open Btree* here */
int flags /* Flags */
);

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.312 2005/12/16 15:24:29 danielk1977 Exp $
** $Id: main.c,v 1.313 2005/12/30 16:28:02 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -26,15 +26,6 @@
*/
const int sqlite3one = 1;
#ifndef SQLITE_OMIT_GLOBALRECOVER
/*
** Linked list of all open database handles. This is used by the
** sqlite3_global_recover() function. Entries are added to the list
** by openDatabase() and removed by sqlite3_close().
*/
static sqlite3 *pDbList = 0;
#endif
/*
** The version of the library
*/
@ -648,7 +639,7 @@ int sqlite3BtreeFactory(
#endif /* SQLITE_OMIT_MEMORYDB */
}
rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
rc = sqlite3BtreeOpen(zFilename, db, ppBtree, btree_flags);
if( rc==SQLITE_OK ){
sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
sqlite3BtreeSetCacheSize(*ppBtree, nCache);

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.228 2005/12/20 09:19:37 danielk1977 Exp $
** @(#) $Id: pager.c,v 1.229 2005/12/30 16:28:02 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@ -301,12 +301,36 @@ struct Pager {
/*
** These are bits that can be set in Pager.errMask.
**
** TODO: Maybe we just want a variable - Pager.errCode. Can we really
** have two simultaneous error conditions?
**
** Recovering from an SQLITE_FULL, SQLITE_LOCK, SQLITE_CORRUPT or
** SQLITE_IOERR error is not a simple matter, particularly if the pager
** cache is shared between multiple connections.
**
** SQLITE_FULL (PAGER_ERR_FULL):
** Cleared when the transaction is rolled back.
**
** SQLITE_CORRUPT (PAGER_ERR_CORRUPT):
** Cannot be cleared. The upper layer must close the current pager
** and open a new one on the same file to continue.
**
** SQLITE_PROTOCOL (PAGER_ERR_LOCK):
** This error only occurs if an internal error occurs or another process
** is not following the sqlite locking protocol (i.e. someone is
** manipulating the database file using something other than sqlite).
** This is handled in the same way as database corruption - the error
** cannot be cleared except by closing the current pager and opening
** a brand new one on the same file.
**
** SQLITE_IOERR (PAGER_ERR_DISK):
** Cleared when the transaction is rolled back.
*/
#define PAGER_ERR_FULL 0x01 /* a write() failed */
#define PAGER_ERR_MEM 0x02 /* malloc() failed */
#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */
#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */
#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */
#define PAGER_ERR_LOCK 0x02 /* error in the locking protocol */
#define PAGER_ERR_CORRUPT 0x04 /* database or journal corruption */
#define PAGER_ERR_DISK 0x08 /* general disk I/O error - bad hard drive? */
/*
** Journal files begin with the following magic string. The data
@ -465,11 +489,32 @@ static int pager_errcode(Pager *pPager){
if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL;
if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR;
if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL;
if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM;
if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
return rc;
}
/*
** This function should be called when an error occurs within the pager
** code to set the appropriate bits in Pager.errMask.
*/
static int pager_error(Pager *pPager, int rc){
switch( rc ){
case SQLITE_PROTOCOL:
pPager->errMask |= PAGER_ERR_LOCK;
break;
case SQLITE_IOERR:
pPager->errMask |= PAGER_ERR_DISK;
break;
case SQLITE_FULL:
pPager->errMask |= PAGER_ERR_FULL;
break;
case SQLITE_CORRUPT:
pPager->errMask |= PAGER_ERR_CORRUPT;
break;
}
return rc;
}
#ifdef SQLITE_CHECK_PAGES
/*
** Return a 32-bit hash of the page data for pPage.
@ -739,6 +784,9 @@ static int readJournalHdr(
**
** The master journal page checksum is the sum of the bytes in the master
** journal name.
**
** If zMaster is a NULL pointer (occurs for a single database transaction),
** this call is a no-op.
*/
static int writeMasterJournal(Pager *pPager, const char *zMaster){
int rc;
@ -861,29 +909,6 @@ static void pager_reset(Pager *pPager){
assert( pPager->journalOpen==0 );
}
/*
** This function is used to reset the pager after a malloc() failure. This
** doesn't work with in-memory databases. If a malloc() fails when an
** in-memory database is in use it is not possible to recover.
**
** If a transaction or statement transaction is active, it is rolled back.
**
** It is an error to call this function if any pages are in use.
*/
#ifndef SQLITE_OMIT_GLOBALRECOVER
int sqlite3pager_reset(Pager *pPager){
if( pPager ){
if( pPager->nRef || MEMDB ){
return SQLITE_ERROR;
}
pPager->errMask &= ~(PAGER_ERR_MEM);
pager_reset(pPager);
}
return SQLITE_OK;
}
#endif
/*
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
@ -1586,7 +1611,7 @@ int sqlite3pager_open(
int nExtra, /* Extra bytes append to each in-memory page */
int flags /* flags controlling this file */
){
Pager *pPager;
Pager *pPager = 0;
char *zFullPathname = 0;
int nameLen;
OsFile *fd;
@ -1600,17 +1625,24 @@ int sqlite3pager_open(
char zTemp[SQLITE_TEMPNAME_SIZE];
SqliteTsd *pTsd = sqlite3Tsd();
/* If malloc() has already failed return SQLITE_NOMEM. Before even
** testing for this, set *ppPager to NULL so the caller knows the pager
** structure was never allocated.
*/
*ppPager = 0;
memset(&fd, 0, sizeof(fd));
if( sqlite3Tsd()->mallocFailed ){
return SQLITE_NOMEM;
}
memset(&fd, 0, sizeof(fd));
/* Open the pager file and set zFullPathname to point at malloc()ed
** memory containing the complete filename (i.e. including the directory).
*/
if( zFilename && zFilename[0] ){
#ifndef SQLITE_OMIT_MEMORYDB
if( strcmp(zFilename,":memory:")==0 ){
memDb = 1;
zFullPathname = sqliteStrDup("");
rc = SQLITE_OK;
}else
#endif
{
@ -1627,28 +1659,35 @@ int sqlite3pager_open(
tempFile = 1;
}
}
if( !zFullPathname ){
sqlite3OsClose(&fd);
return SQLITE_NOMEM;
}
if( rc!=SQLITE_OK ){
sqlite3OsClose(&fd);
sqliteFree(zFullPathname);
return rc;
}
/* Allocate the Pager structure. As part of the same allocation, allocate
** space for the full paths of the file, directory and journal
** (Pager.zFilename, Pager.zDirectory and Pager.zJournal).
*/
if( zFullPathname ){
nameLen = strlen(zFullPathname);
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
if( pPager==0 ){
}
/* If an error occured in either of the blocks above, free the memory
** pointed to by zFullPathname, free the Pager structure and close the
** file. Since the pager is not allocated there is no need to set
** any Pager.errMask variables.
*/
if( !pPager || !zFullPathname || rc!=SQLITE_OK ){
sqlite3OsClose(&fd);
sqliteFree(zFullPathname);
return SQLITE_NOMEM;
sqliteFree(pPager);
return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc);
}
TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
pPager->zFilename = (char*)&pPager[1];
pPager->zDirectory = &pPager->zFilename[nameLen+1];
pPager->zJournal = &pPager->zDirectory[nameLen+1];
strcpy(pPager->zFilename, zFullPathname);
strcpy(pPager->zDirectory, zFullPathname);
for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
if( i>0 ) pPager->zDirectory[i-1] = 0;
strcpy(pPager->zJournal, zFullPathname);
@ -1762,7 +1801,13 @@ void enable_simulated_io_errors(void){
/*
** Read the first N bytes from the beginning of the file into memory
** that pDest points to. No error checking is done.
** that pDest points to.
**
** No error checking is done. The rational for this is that this function
** may be called even if the file does not exist or contain a header. In
** these cases sqlite3OsRead() will return an error, to which the correct
** response is to zero the memory at pDest and continue. A real IO error
** will presumably recur and be picked up later (Todo: Think about this).
*/
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
memset(pDest, 0, N);
@ -1973,6 +2018,11 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** and their memory is freed. Any attempt to use a page associated
** with this page cache after this function returns will likely
** result in a coredump.
**
** This function always succeeds. If a transaction is active an attempt
** is made to roll it back. If an error occurs during the rollback
** a hot journal may be left in the filesystem but no error is returned
** to the caller.
*/
int sqlite3pager_close(Pager *pPager){
PgHdr *pPg, *pNext;
@ -2037,6 +2087,9 @@ int sqlite3pager_close(Pager *pPager){
*/
#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT
/* Remove the pager from the linked list of pagers starting at
** SqliteTsd.pPager.
*/
if( pPager==pTsd->pPager ){
pTsd->pPager = pPager->pNext;
}else{
@ -2311,6 +2364,9 @@ static int hasHotJournal(Pager *pPager){
/*
** Try to find a page in the cache that can be recycled.
**
** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It
** does not set the pPager->errMask variable.
*/
static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
PgHdr *pPg;
@ -2329,8 +2385,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){
int rc = syncJournal(pPager);
if( rc!=0 ){
sqlite3pager_rollback(pPager);
return SQLITE_IOERR;
return rc;
}
if( pPager->fullSync ){
/* If in full-sync mode, write a new journal header into the
@ -2343,8 +2398,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
assert( pPager->journalOff > 0 );
rc = writeJournalHdr(pPager);
if( rc!=0 ){
sqlite3pager_rollback(pPager);
return SQLITE_IOERR;
return rc;
}
}
pPg = pPager->pFirst;
@ -2363,8 +2417,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
pPg->pDirty = 0;
rc = pager_write_pagelist( pPg );
if( rc!=SQLITE_OK ){
sqlite3pager_rollback(pPager);
return SQLITE_IOERR;
return rc;
}
}
assert( pPg->dirty==0 );
@ -2435,6 +2488,7 @@ int sqlite3pager_release_memory(int nReq){
*/
PgHdr *pTmp;
assert( pPg );
page_remove_from_stmt_list(pPg);
if( pPg==p->pAll ){
p->pAll = pPg->pNextAll;
}else{
@ -2446,23 +2500,22 @@ int sqlite3pager_release_memory(int nReq){
}
if( rc!=SQLITE_OK ){
/* Assert that fsync() was enabled and the error was an io-error
** or a full database. Nothing else should be able to wrong in
** pager_recycle.
/* An error occured whilst writing to the database file or
** journal in pager_recycle(). The error is not returned to the
** caller of this function. Instead, set the Pager.errMask variable.
** The error will be returned to the user (or users, in the case
** of a shared pager cache) of the pager for which the error occured.
*/
assert( i && (rc==SQLITE_IOERR || rc==SQLITE_FULL) );
/* TODO: Figure out what to do about this. The IO-error
** belongs to the connection that is executing a transaction.
*/
assert(0);
assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
assert( p->state>=PAGER_RESERVED );
pager_error(p, rc);
}
}
}
return nReleased;
}
#endif
#endif /* SQLITE_OMIT_MEMORY_MANAGEMENT */
/*
** Acquire a page.
@ -2513,7 +2566,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( !pPager->noReadlock ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
return rc;
return pager_error(pPager, rc);
}
}
@ -2538,7 +2591,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( rc!=SQLITE_OK ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
return rc;
return pager_error(pPager, rc);
}
pPager->state = PAGER_EXCLUSIVE;
@ -2567,7 +2620,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
rc = pager_playback(pPager);
if( rc!=SQLITE_OK ){
return rc;
return pager_error(pPager, rc);
}
}
pPg = 0;
@ -2588,7 +2641,6 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
+ sizeof(u32) + pPager->nExtra
+ MEMDB*sizeof(PgHistory) );
if( pPg==0 ){
// pPager->errMask |= PAGER_ERR_MEM;
return SQLITE_NOMEM;
}
memset(pPg, 0, sizeof(*pPg));
@ -2606,7 +2658,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}else{
rc = pager_recycle(pPager, 1, &pPg);
if( rc!=SQLITE_OK ){
return rc;
return pager_error(pPager, rc);
}
assert(pPg) ;
}
@ -2662,7 +2714,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( sqlite3OsFileSize(pPager->fd,&fileSize)!=SQLITE_OK
|| fileSize>=pgno*pPager->pageSize ){
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
return rc;
return pager_error(pPager, rc);
}else{
clear_simulated_io_error();
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.151 2005/12/20 09:19:37 danielk1977 Exp $
** @(#) $Id: sqlite.h.in,v 1.152 2005/12/30 16:28:02 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@ -1338,6 +1338,14 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
int sqlite3_release_memory(int);
/*
** This function is only available if the library is compiled without
** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or
** disable (if the argument is true or false, respectively) the
** "shared pager" feature.
*/
int sqlite3_enable_shared_cache(int);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.445 2005/12/29 23:33:54 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.446 2005/12/30 16:28:02 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -289,6 +289,11 @@ struct SqliteTsd {
Pager *pPager; /* Linked list of all pagers in this thread */
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
u8 useSharedData; /* True if shared pagers and schemas are enabled */
BtShared *pBtree;
#endif
#ifdef SQLITE_MEMDEBUG
i64 nMaxAlloc; /* High water mark of SqliteTsd.nAlloc */
int mallocAllowed; /* assert() in sqlite3Malloc() if not set */

View File

@ -11,7 +11,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.141 2005/12/19 14:18:11 danielk1977 Exp $
** $Id: tclsqlite.c,v 1.142 2005/12/30 16:28:02 danielk1977 Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@ -1754,11 +1754,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** $db soft_heap_limit N
**
** Set the soft-heap-limit for this thread. Note that the limit is
** per-thread, not per-database. An empty string is returned.
** per-thread, not per-database. The previous limit is returned.
*/
case DB_SOFT_HEAP_LIMIT: {
#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT
int n;
int ret;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BYTES");
return TCL_ERROR;
@ -1766,8 +1767,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( Tcl_GetIntFromObj(interp, objv[2], &n) ){
return TCL_ERROR;
}
ret = sqlite3Tsd()->nSoftHeapLimit;
sqlite3_soft_heap_limit(n);
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
#endif
break;
}

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.177 2005/12/20 09:19:37 danielk1977 Exp $
** $Id: test1.c,v 1.178 2005/12/30 16:28:02 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -890,6 +890,38 @@ static int sqlite_malloc_outstanding(
}
#endif
/*
** Usage: sqlite3_enable_shared_cache BOOLEAN
**
*/
#ifndef SQLITE_OMIT_SHARED_CACHE
static int test_enable_shared_cache(
ClientData clientData,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
int rc;
int enable;
SqliteTsd *pTsd = sqlite3Tsd();
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(pTsd->useSharedData));
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
return TCL_ERROR;
}
rc = sqlite3_enable_shared_cache(enable);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
#endif
/*
** Usage: sqlite_abort
**
@ -3074,6 +3106,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SUBQUERY
Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY);
#else
@ -3250,6 +3288,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
{ "sqlite3_test_errstr", test_errstr, 0 },
{ "tcl_variable_type", tcl_variable_type, 0 },
#ifndef SQLITE_OMIT_SHARED_CACHE
{ "sqlite3_enable_shared_cache", test_enable_shared_cache, 0},
#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test3.c,v 1.63 2005/12/09 20:21:59 drh Exp $
** $Id: test3.c,v 1.64 2005/12/30 16:28:02 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@ -69,7 +69,7 @@ static int btree_open(
}
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
rc = sqlite3BtreeOpen(argv[1], &pBt, flags);
rc = sqlite3BtreeOpen(argv[1], 0, &pBt, flags);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;

View File

@ -926,7 +926,6 @@ static int vdbeCommit(sqlite3 *db){
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
int rc;
sqlite3SafetyOff(db);
rc = db->xCommitCallback(db->pCommitArg);
sqlite3SafetyOn(db);

View File

@ -13,7 +13,7 @@
# file format change that may be used in the future to implement
# "ALTER TABLE ... ADD COLUMN".
#
# $Id: alter3.test,v 1.6 2005/03/29 03:11:00 danielk1977 Exp $
# $Id: alter3.test,v 1.7 2005/12/30 16:28:02 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@ -360,6 +360,7 @@ do_test alter3-8.1 {
CREATE TABLE t4(c1);
}
} {}
set ::sql ""
do_test alter3-8.2 {
set cols c1
for {set i 2} {$i < 100} {incr i} {

View File

@ -12,13 +12,12 @@
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.33 2005/12/06 17:19:12 danielk1977 Exp $
# $Id: attach2.test,v 1.34 2005/12/30 16:28:02 danielk1977 Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Ticket #354
#
# Databases test.db and test2.db contain identical schemas. Make
@ -157,7 +156,7 @@ proc lock_status {testnum db expected_result} {
# If the database was compiled with OMIT_TEMPDB set, then
# the lock_status list will not contain an entry for the temp
# db. But the test code doesn't know this, so it's easiest
# to filter it out here.
# to filter it out of the $expected_result list here.
ifcapable !tempdb {
set expected_result [concat \
[lrange $expected_result 0 1] \

View File

@ -9,7 +9,10 @@
#
#***********************************************************************
#
# $Id: malloc5.test,v 1.2 2005/12/20 09:19:38 danielk1977 Exp $
# This file contains test cases focused on the two memory-management APIs,
# sqlite3_soft_heap_limit() and sqlite3_release_memory().
#
# $Id: malloc5.test,v 1.3 2005/12/30 16:28:02 danielk1977 Exp $
#---------------------------------------------------------------------------
# NOTES ON EXPECTED BEHAVIOUR
@ -19,6 +22,13 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if memory debugging is turned on.
if {[info command sqlite_malloc_stat]==""} {
puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
finish_test
return
}
do_test malloc5-1.1 {
# Simplest possible test. Call [db release_memory] when there is exactly
# one unused page in a single pager cache. This test case set's the
@ -159,6 +169,11 @@ sqlite_malloc_outstanding -clearmaxbytes
# and tests to see that this limit is not exceeded at any point during
# transaction execution.
#
# Before executing malloc5-4.* we save the value of the current soft heap
# limit in variable ::soft_limit. The original value is restored after
# running the tests.
#
set ::soft_limit [db soft_heap_limit -1]
do_test malloc5-4.1 {
execsql {BEGIN;}
execsql {DELETE FROM abc;}
@ -188,8 +203,8 @@ do_test malloc5-4.3 {
}
} [list 20000 [expr int(20000.0 * 4999.5)] [expr int(20000.0 * 4999.5)]]
# Unset the soft-heap-limit value.
db soft_heap_limit -1
# Restore the soft heap limit.
db soft_heap_limit $::soft_limit
finish_test

View File

@ -6,7 +6,25 @@
#***********************************************************************
# This file runs all tests.
#
# $Id: quick.test,v 1.38 2005/12/15 10:11:32 danielk1977 Exp $
# $Id: quick.test,v 1.39 2005/12/30 16:28:02 danielk1977 Exp $
proc lshift {lvar} {
upvar $lvar l
set ret [lindex $l 0]
set l [lrange $l 1 end]
return $ret
}
while {[set arg [lshift argv]] != ""} {
switch -- $arg {
-sharedpagercache {
sqlite3_enable_shared_cache 1
}
default {
set argv [linsert $argv 0 $arg]
break
}
}
}
set testdir [file dirname $argv0]
source $testdir/tester.tcl

205
test/shared.test Normal file
View File

@ -0,0 +1,205 @@
# 2005 December 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 SELECT statement.
#
# $Id: shared.test,v 1.1 2005/12/30 16:28:02 danielk1977 Exp $
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db close
ifcapable !shared_cache {
finish_test
return
}
# Test organization:
#
# shared-1.*: Simple test to verify basic sanity of table level locking when
# two connections share a pager cache.
# shared-2.*: Test that a read transaction can co-exist with a
# write-transaction, including a simple test to ensure the
# external locking protocol is still working.
#
do_test shared-1.1 {
# Open a second database on the file test.db. It should use the same pager
# cache and schema as the original connection. Verify that only 1 file is
# opened.
sqlite3 db2 test.db
sqlite3 db test.db
set ::sqlite_open_file_count
} {1}
do_test shared-1.2 {
# Add a table and a single row of data via the first connection.
# Ensure that the second connection can see them.
execsql {
CREATE TABLE abc(a, b, c);
INSERT INTO abc VALUES(1, 2, 3);
} db
execsql {
SELECT * FROM abc;
} db2
} {1 2 3}
do_test shared-1.3 {
# Have the first connection begin a transaction and obtain a read-lock
# on table abc. This should not prevent the second connection from
# querying abc.
execsql {
BEGIN;
SELECT * FROM abc;
}
execsql {
SELECT * FROM abc;
} db2
} {1 2 3}
do_test shared-1.4 {
# Try to insert a row into abc via connection 2. This should fail because
# of the read-lock connection 1 is holding on table abc (obtained in the
# previous test case).
catchsql {
INSERT INTO abc VALUES(4, 5, 6);
} db2
} {1 {database is locked}}
do_test shared-1.5 {
# Using connection 2 (the one without the open transaction), create a
# new table and add a row to it. This is permitted as the transaction
# started by connection 1 is currently a read transaction.
execsql {
CREATE TABLE def(d, e, f);
INSERT INTO def VALUES('I', 'II', 'III');
} db2
} {}
do_test shared-1.6 {
# Upgrade connection 1's transaction to a write transaction. Insert
# a row into table def - the table just created by connection 2.
#
# Connection 1 is able to see table def, even though it was created
# "after" the connection 1 transaction was started. This is because no
# lock was established on the sqlite_master table.
# Todo: Remove this. Because the implementation does not include
# shared-schemas yet, we need to run some query (that will fail at
# OP_VerifyCookie) so that connection 1 picks up the schema change
# made via connection 2. Otherwise the sqlite3_prepare("INSERT INTO def...")
# below will fail.
execsql {
SELECT * FROM sqlite_master;
}
execsql {
INSERT INTO def VALUES('IV', 'V', 'VI');
}
} {}
do_test shared-1.7 {
# Read from the sqlite_master table with connection 1 (inside the
# transaction). Then test that we can no longer create a table
# with connection 2. This is because of the read-lock on sqlite_master.
execsql {
SELECT * FROM sqlite_master;
}
catchsql {
CREATE TABLE ghi(g, h, i);
} db2
} {1 {database is locked}}
do_test shared-1.8 {
# Check that connection 2 can read the sqlite_master table. Then
# create a table using connection 1 (this should write-lock the
# sqlite_master table). Then try to read sqlite_master again using
# connection 2 and verify that the write-lock prevents this.
execsql {
SELECT * FROM sqlite_master;
} db2
execsql {
CREATE TABLE ghi(g, h, i);
}
catchsql {
SELECT * FROM sqlite_master;
} db2
} {1 {database is locked}}
do_test shared-1.9 {
# Commit the connection 1 transaction.
execsql {
COMMIT;
}
} {}
do_test shared-2.1 {
# Open connection db3 to the database. Use a different path to the same
# file so that db3 does *not* share the same pager cache as db and db2
# (there should be two open file handles).
sqlite3 db3 ./test.db
set ::sqlite_open_file_count
} {2}
do_test shared-2.2 {
# Start read transactions on db and db2 (the shared pager cache). Ensure
# db3 cannot write to the database.
execsql {
BEGIN;
SELECT * FROM abc;
}
execsql {
BEGIN;
SELECT * FROM abc;
} db2
catchsql {
INSERT INTO abc VALUES(1, 2, 3);
} db2
} {1 {database is locked}}
do_test shared-2.3 {
# Turn db's transaction into a write-transaction. db3 should still be
# able to read from table def (but will not see the new row). Connection
# db2 should not be able to read def (because of the write-lock).
# Todo: The failed "INSERT INTO abc ..." statement in the above test
# has started a write-transaction on db2 (should this be so?). This
# would prevent connection db from starting a write-transaction. So roll the
# db2 transaction back and replace it with a new read transaction.
execsql {
ROLLBACK;
BEGIN;
SELECT * FROM abc;
} db2
execsql {
INSERT INTO def VALUES('VII', 'VIII', 'IX');
}
concat [
catchsql { SELECT * FROM def; } db3
] [
catchsql { SELECT * FROM def; } db2
]
} {0 {I II III IV V VI} 1 {database is locked}}
do_test shared-2.4 {
# Commit the open transaction on db. db2 still holds a read-transaction.
# This should prevent db3 from writing to the database, but not from
# reading.
execsql {
COMMIT;
}
concat [
catchsql { SELECT * FROM def; } db3
] [
catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3
]
} {0 {I II III IV V VI VII VIII IX} 1 {database is locked}}
catch {db close}
catch {db2 close}
catch {db3 close}
finish_test
sqlite3_enable_shared_cache $::enable_shared_cache

View File

@ -11,7 +11,7 @@
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.54 2005/12/09 14:39:05 danielk1977 Exp $
# $Id: tester.tcl,v 1.55 2005/12/30 16:28:02 danielk1977 Exp $
# Make sure tclsqlite3 was compiled correctly. Abort now with an
# error message if not.
@ -440,6 +440,7 @@ proc copy_file {from to} {
#
proc check_for_leaks {} {
set ret [list]
set cnt 0
foreach alloc [sqlite_malloc_outstanding] {
foreach {nBytes file iLine userstring backtrace} $alloc {}
set stack [list]
@ -447,6 +448,7 @@ proc check_for_leaks {} {
# The first command in this block will probably fail on windows. This
# means there will be no stack dump available.
if {$cnt < 25} {
catch {
set stuff [eval "exec addr2line -e ./testfixture -f $backtrace"]
foreach {func line} $stuff {
@ -460,6 +462,8 @@ proc check_for_leaks {} {
}
}
}
incr cnt
}
if {!$skip} {
lappend ret [list $nBytes $file $iLine $userstring $stack]

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.26 2005/03/29 03:11:00 danielk1977 Exp $
# $Id: trans.test,v 1.27 2005/12/30 16:28:02 danielk1977 Exp $
set testdir [file dirname $argv0]
@ -97,6 +97,7 @@ do_test trans-3.2 {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 5 10}}
do_test trans-3.3 {
catchsql {
SELECT a FROM one ORDER BY a;
@ -135,6 +136,7 @@ do_test trans-3.9 {
do_test trans-3.10 {
execsql {END TRANSACTION}
} {}
do_test trans-3.11 {
set v [catch {execsql {
SELECT a FROM two ORDER BY a;