Test interaction of incremental io and other database writes. (CVS 3922)

FossilOrigin-Name: 4516416b4d38679ea7d259155f241e54c4c58d7d
This commit is contained in:
danielk1977
2007-05-04 18:36:44 +00:00
parent ca5557f91d
commit dcbb5d3f47
8 changed files with 311 additions and 60 deletions
+21 -18
View File
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.373 2007/05/04 13:15:56 drh Exp $
** $Id: btree.c,v 1.374 2007/05/04 18:36:45 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -395,7 +395,7 @@ struct BtCursor {
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#ifndef SQLITE_OMIT_INCRBLOB
u8 cacheOverflow; /* True to use aOverflow */
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
};
@@ -765,6 +765,9 @@ static void clearCursorPosition(BtCursor *pCur){
static int restoreOrClearCursorPositionX(BtCursor *pCur){
int rc;
assert( pCur->eState==CURSOR_REQUIRESEEK );
if( pCur->isIncrblobHandle ){
return SQLITE_ABORT;
}
pCur->eState = CURSOR_INVALID;
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip);
if( rc==SQLITE_OK ){
@@ -3185,7 +3188,7 @@ static int copyPayload(
** appear on the main page or be scattered out on multiple overflow
** pages.
**
** If the BtCursor.cacheOverflow flag is set, and the current
** If the BtCursor.isIncrblobHandle flag is set, and the current
** cursor entry uses one or more overflow pages, this function
** allocates space for and lazily popluates the overflow page-list
** cache array (BtCursor.aOverflow). Subsequent calls use this
@@ -3254,14 +3257,14 @@ static int accessPayload(
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
#ifndef SQLITE_OMIT_INCRBLOB
/* If the cacheOverflow flag is set and the BtCursor.aOverflow[]
/* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
** has not been allocated, allocate it now. The array is sized at
** one entry for each overflow page in the overflow chain. The
** page number of the first overflow page is stored in aOverflow[0],
** etc. A value of 0 in the aOverflow[] array means "not yet known"
** (the cache is lazily populated).
*/
if( pCur->cacheOverflow && !pCur->aOverflow ){
if( pCur->isIncrblobHandle && !pCur->aOverflow ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
if( nOvfl && !pCur->aOverflow ){
@@ -6989,23 +6992,23 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
** Only the data content may only be modified, it is not possible
** to change the length of the data stored.
*/
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
BtShared *pBt = pCsr->pBtree->pBt;
assert(pCsr->isIncrblobHandle);
if( pCsr->eState==CURSOR_REQUIRESEEK ){
return SQLITE_ABORT;
}
/* Check some preconditions:
** (a) a write-transaction is open,
** (b) the cursor is open for writing,
** (c) there is no read-lock on the table being modified and
** (d) the cursor points at a valid row of an intKey table.
** (a) the cursor is open for writing,
** (b) there is no read-lock on the table being modified and
** (c) the cursor points at a valid row of an intKey table.
*/
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before writing to a blob */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
assert( !pBt->readOnly );
if( !pCsr->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
return SQLITE_READONLY;
}
assert( !pBt->readOnly && pBt->inTransaction==TRANS_WRITE );
if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
@@ -7027,9 +7030,9 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
** sqlite3BtreePutData()).
*/
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
assert(!pCur->cacheOverflow);
assert(!pCur->isIncrblobHandle);
assert(!pCur->aOverflow);
pCur->cacheOverflow = 1;
pCur->isIncrblobHandle = 1;
}
#endif
+2 -2
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.78 2007/05/02 16:48:37 danielk1977 Exp $
** @(#) $Id: btree.h,v 1.79 2007/05/04 18:36:45 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -142,7 +142,7 @@ int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*);
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *);
#ifdef SQLITE_TEST
+2 -3
View File
@@ -12,7 +12,7 @@
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id: tclsqlite.c,v 1.184 2007/05/04 13:15:56 drh Exp $
** $Id: tclsqlite.c,v 1.185 2007/05/04 18:36:45 danielk1977 Exp $
*/
#include "tcl.h"
#include <errno.h>
@@ -120,10 +120,9 @@ struct SqliteDb {
};
struct IncrblobChannel {
SqliteDb *pDb; /* Associated database connection */
sqlite3_blob *pBlob; /* sqlite3 blob handle */
SqliteDb *pDb; /* Associated database connection */
int iSeek; /* Current seek offset */
Tcl_Channel channel; /* Channel identifier */
IncrblobChannel *pNext; /* Linked list of all open incrblob channels */
IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */
+98 -1
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.242 2007/05/02 16:51:59 drh Exp $
** $Id: test1.c,v 1.243 2007/05/04 18:36:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1465,6 +1465,99 @@ static int test_table_column_metadata(
}
#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
** sqlite3_blob_read CHANNEL OFFSET N
*/
static int test_blob_read(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
Tcl_Channel channel;
ClientData instanceData;
sqlite3_blob *pBlob;
int notUsed;
int nByte;
int iOffset;
unsigned char *zBuf;
int rc;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
return TCL_ERROR;
}
channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), &notUsed);
if( !channel
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte)
|| nByte<0 || iOffset<0
){
return TCL_ERROR;
}
instanceData = Tcl_GetChannelInstanceData(channel);
pBlob = *((sqlite3_blob **)instanceData);
zBuf = (unsigned char *)Tcl_Alloc(nByte);
rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
if( rc==SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte));
}else{
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
}
Tcl_Free((char *)zBuf);
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
/*
** sqlite3_blob_write CHANNEL OFFSET DATA
*/
static int test_blob_write(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
Tcl_Channel channel;
ClientData instanceData;
sqlite3_blob *pBlob;
int notUsed;
int iOffset;
int rc;
unsigned char *zBuf;
int nBuf;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA");
return TCL_ERROR;
}
channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), &notUsed);
if( !channel
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
|| iOffset<0
){
return TCL_ERROR;
}
instanceData = Tcl_GetChannelInstanceData(channel);
pBlob = *((sqlite3_blob **)instanceData);
zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
}
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
#endif
/*
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
@@ -4500,6 +4593,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_libversion_number", test_libversion_number, 0 },
#ifdef SQLITE_ENABLE_COLUMN_METADATA
{ "sqlite3_table_column_metadata", test_table_column_metadata, 0 },
#endif
#ifndef SQLITE_OMIT_INCRBLOB
{ "sqlite3_blob_read", test_blob_read, 0 },
{ "sqlite3_blob_write", test_blob_write, 0 },
#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
+41 -17
View File
@@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: vdbeblob.c,v 1.7 2007/05/04 13:15:57 drh Exp $
** $Id: vdbeblob.c,v 1.8 2007/05/04 18:36:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -244,32 +244,56 @@ int sqlite3_blob_close(sqlite3_blob *pBlob){
return sqlite3_finalize(pStmt);
}
int blobReadWrite(
sqlite3_blob *pBlob,
void *z,
int n,
int iOffset,
int (*xCall)(BtCursor*, u32, u32, void*)
){
int rc;
Incrblob *p = (Incrblob *)pBlob;
Vdbe *v = (Vdbe *)(p->pStmt);
sqlite3 *db;
/* If there is no statement handle, then the blob-handle has
** already been invalidated. Return SQLITE_ABORT in this case.
*/
if( !v ) return SQLITE_ABORT;
/* Request is out of range. Return a transient error. */
if( (iOffset+n)>p->nByte ){
return SQLITE_ERROR;
}
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
** returned, clean-up the statement handle.
*/
db = v->db;
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
if( rc==SQLITE_ABORT ){
sqlite3VdbeFinalize(v);
p->pStmt = 0;
}else{
v->rc = rc;
}
return sqlite3ApiExit(db, rc);
}
/*
** Read data from a blob handle.
*/
int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
int rc = SQLITE_ERROR;
Incrblob *p = (Incrblob *)pBlob;
Vdbe *v = (Vdbe *)(p->pStmt);
if( (iOffset+n)<=p->nByte ){
rc = sqlite3BtreeData(p->pCsr, iOffset+p->iOffset, n, z);
}
v->rc = rc;
return sqlite3ApiExit(v->db, v->rc);
return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
}
/*
** Write data to a blob handle.
*/
int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
int rc = SQLITE_ERROR;
Incrblob *p = (Incrblob *)pBlob;
Vdbe *v = (Vdbe *)(p->pStmt);
if( (iOffset+n)<=p->nByte ){
rc = sqlite3BtreePutData(p->pCsr, iOffset+p->iOffset, n, z);
}
v->rc = rc;
return sqlite3ApiExit(v->db, v->rc);
return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}
/*