1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Ensure the mutex used to protect the linked list of all main database files opened by a single ota vfs is allocated.

FossilOrigin-Name: 9c8682d6650a94e11f9bec5baff69ed9668874fa
This commit is contained in:
dan
2015-02-19 19:59:35 +00:00
parent 138bf3bc7f
commit 942b0a68ea
4 changed files with 185 additions and 125 deletions

View File

@@ -100,7 +100,10 @@ proc create_ota5 {filename} {
#
proc run_ota {target ota} {
sqlite3ota ota $target $ota
while { [ota step]=="SQLITE_OK" } {}
while 1 {
set rc [ota step]
if {$rc!="SQLITE_OK"} break
}
ota close
}

View File

@@ -103,12 +103,12 @@
** keys mapped to values as follows:
**
** OTA_STATE_STAGE:
** May be set to integer values 1, 2 or 3. As follows:
** 0: Nothing at all has been done.
** May be set to integer values 1, 2, 4 or 5. As follows:
** 1: the *-ota file is currently under construction.
** 2: the *-ota file has been constructed, but not yet moved
** to the *-wal path.
** 3: the checkpoint is underway.
** 4: the checkpoint is underway.
** 5: the ota update has been checkpointed.
**
** OTA_STATE_TBL:
** Only valid if STAGE==1. The target database name of the table
@@ -128,8 +128,11 @@
** ota update.
**
** OTA_STATE_CKPT:
** Valid if STAGE==3. The blob to pass to sqlite3ckpt_start() to resume
** the incremental checkpoint.
** Valid if STAGE==4. The 64-bit checksum associated with the wal-index
** header created by recovering the *-wal file. This is used to detect
** cases when another client appends frames to the *-wal file in the
** middle of an incremental checkpoint (an incremental checkpoint cannot
** be continued if this happens).
**
** OTA_STATE_COOKIE:
** Valid if STAGE==1. The current change-counter cookie value in the
@@ -153,8 +156,9 @@
#define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state" \
"(k INTEGER PRIMARY KEY, v)"
typedef struct OtaState OtaState;
typedef struct OtaFrame OtaFrame;
typedef struct OtaObjIter OtaObjIter;
typedef struct OtaState OtaState;
typedef struct ota_vfs ota_vfs;
typedef struct ota_file ota_file;
@@ -213,7 +217,6 @@ struct OtaObjIter {
int iTnum; /* Root page of current object */
int iPkTnum; /* If eType==EXTERNAL, root of PK index */
int bUnique; /* Current index is unique */
int iVisit; /* Number of points visited, incl. current */
/* Statements created by otaObjIterPrepareAll() */
int nCol; /* Number of columns in current object */
@@ -244,7 +247,21 @@ struct OtaObjIter {
#define OTA_PK_VTAB 5
typedef struct OtaFrame OtaFrame;
/*
** Within the OTA_STAGE_OAL stage, each call to sqlite3ota_step() performs
** one of the following operations.
*/
#define OTA_INSERT 1 /* Insert on a main table b-tree */
#define OTA_DELETE 2 /* Delete a row from a main table b-tree */
#define OTA_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */
#define OTA_IDX_INSERT 4 /* Insert on an aux. index b-tree */
#define OTA_UPDATE 5 /* Update a row in a main table b-tree */
/*
** A single step of an incremental checkpoint - frame iWalFrame of the wal
** file should be copied to page iDbPage of the database file.
*/
struct OtaFrame {
u32 iDbPage;
u32 iWalFrame;
@@ -279,6 +296,9 @@ struct sqlite3ota {
i64 iWalCksum;
};
/*
** An ota VFS is implemented using an instance of this structure.
*/
struct ota_vfs {
sqlite3_vfs base; /* ota VFS shim methods */
sqlite3_vfs *pRealVfs; /* Underlying VFS */
@@ -286,6 +306,10 @@ struct ota_vfs {
ota_file *pMain; /* Linked list of main db files */
};
/*
** Each file opened by an ota VFS is represented by an instance of
** the following structure.
*/
struct ota_file {
sqlite3_file base; /* sqlite3_file methods */
sqlite3_file *pReal; /* Underlying file handle */
@@ -459,7 +483,7 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){
pIter->bCleanup = 0;
rc = sqlite3_step(pIter->pTblIter);
if( rc!=SQLITE_ROW ){
rc = sqlite3_reset(pIter->pTblIter);
rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
pIter->zTbl = 0;
}else{
pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
@@ -474,7 +498,7 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){
if( rc==SQLITE_OK ){
rc = sqlite3_step(pIter->pIdxIter);
if( rc!=SQLITE_ROW ){
rc = sqlite3_reset(pIter->pIdxIter);
rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg);
pIter->bCleanup = 1;
pIter->zIdx = 0;
}else{
@@ -492,7 +516,6 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){
otaObjIterFinalize(pIter);
p->rc = rc;
}
pIter->iVisit++;
return rc;
}
@@ -528,6 +551,30 @@ static int otaObjIterFirst(sqlite3ota *p, OtaObjIter *pIter){
return otaObjIterNext(p, pIter);
}
/*
** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs,
** an error code is stored in the OTA handle passed as the first argument.
**
** If an error has already occurred (p->rc is already set to something other
** than SQLITE_OK), then this function returns NULL without modifying the
** stored error code. In this case it still calls sqlite3_free() on any
** printf() parameters associated with %z conversions.
*/
static char *otaMPrintf(sqlite3ota *p, const char *zFmt, ...){
char *zSql = 0;
va_list ap;
va_start(ap, zFmt);
zSql = sqlite3_vmprintf(zFmt, ap);
if( p->rc==SQLITE_OK ){
if( zSql==0 ) p->rc = SQLITE_NOMEM;
}else{
sqlite3_free(zSql);
zSql = 0;
}
va_end(ap);
return zSql;
}
/*
** Argument zFmt is a sqlite3_mprintf() style format string. The trailing
** arguments are the usual subsitution values. This function performs
@@ -541,19 +588,29 @@ static int otaObjIterFirst(sqlite3ota *p, OtaObjIter *pIter){
static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
char *zSql = sqlite3_vmprintf(zFmt, ap);
if( p->rc==SQLITE_OK ){
char *zSql = sqlite3_vmprintf(zFmt, ap);
if( zSql==0 ){
p->rc = SQLITE_NOMEM;
}else{
p->rc = sqlite3_exec(p->db, zSql, 0, 0, &p->zErrmsg);
sqlite3_free(zSql);
}
}
sqlite3_free(zSql);
va_end(ap);
return p->rc;
}
/*
** Attempt to allocate and return a pointer to a zeroed block of nByte
** bytes.
**
** If an error (i.e. an OOM condition) occurs, return NULL and leave an
** error code in the ota handle passed as the first argument. Or, if an
** error has already occurred when this function is called, return NULL
** immediately without attempting the allocation or modifying the stored
** error code.
*/
static void *otaMalloc(sqlite3ota *p, int nByte){
void *pRet = 0;
if( p->rc==SQLITE_OK ){
@@ -587,6 +644,16 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
}
}
/*
** The first argument must be a nul-terminated string. This function
** returns a copy of the string in memory obtained from sqlite3_malloc().
** It is the responsibility of the caller to eventually free this memory
** using sqlite3_free().
**
** If an OOM condition is encountered when attempting to allocate memory,
** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise,
** if the allocation succeeds, (*pRc) is left unchanged.
*/
static char *otaStrndup(const char *zStr, int *pRc){
char *zRet = 0;
@@ -604,6 +671,22 @@ static char *otaStrndup(const char *zStr, int *pRc){
return zRet;
}
/*
** Finalize the statement passed as the second argument.
**
** If the sqlite3_finalize() call indicates that an error occurs, and the
** ota handle error code is not already set, set the error code and error
** message accordingly.
*/
static void otaFinalize(sqlite3ota *p, sqlite3_stmt *pStmt){
sqlite3 *db = sqlite3_db_handle(pStmt);
int rc = sqlite3_finalize(pStmt);
if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
p->rc = rc;
p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
}
/* Determine the type of a table.
**
** peType is of type (int*), a pointer to an output parameter of type
@@ -716,8 +799,7 @@ static void otaTableType(
otaTableType_end: {
int i;
for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
int rc2 = sqlite3_finalize(aStmt[i]);
if( p->rc==SQLITE_OK ) p->rc = rc2;
otaFinalize(p, aStmt[i]);
}
}
}
@@ -737,7 +819,6 @@ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
sqlite3_stmt *pStmt = 0;
int nCol = 0;
int i; /* for() loop iterator variable */
int rc2; /* sqlite3_finalize() return value */
int bOtaRowid = 0; /* If input table has column "ota_rowid" */
int iOrder = 0;
@@ -821,37 +902,12 @@ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
}
}
rc2 = sqlite3_finalize(pStmt);
if( p->rc==SQLITE_OK ) p->rc = rc2;
otaFinalize(p, pStmt);
}
return p->rc;
}
/*
** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs,
** an error code is stored in the OTA handle passed as the first argument.
**
** If an error has already occurred (p->rc is already set to something other
** than SQLITE_OK), then this function returns NULL without modifying the
** stored error code. In this case it still calls sqlite3_free() on any
** printf() parameters associated with %z conversions.
*/
static char *otaMPrintf(sqlite3ota *p, const char *zFmt, ...){
char *zSql = 0;
va_list ap;
va_start(ap, zFmt);
zSql = sqlite3_vmprintf(zFmt, ap);
if( p->rc==SQLITE_OK ){
if( zSql==0 ) p->rc = SQLITE_NOMEM;
}else{
sqlite3_free(zSql);
zSql = 0;
}
va_end(ap);
return zSql;
}
/*
** This function constructs and returns a pointer to a nul-terminated
** string containing some SQL clause or list based on one or more of the
@@ -1082,6 +1138,23 @@ static void otaBadControlError(sqlite3ota *p){
}
/*
** Return a nul-terminated string containing the comma separated list of
** assignments that should be included following the "SET" keyword of
** an UPDATE statement used to update the table object that the iterator
** passed as the second argument currently points to if the ota_control
** column of the data_xxx table entry is set to zMask.
**
** The memory for the returned string is obtained from sqlite3_malloc().
** It is the responsibility of the caller to eventually free it using
** sqlite3_free().
**
** If an OOM error is encountered when allocating space for the new
** string, an error code is left in the ota handle passed as the first
** argument and NULL is returned. Or, if an error has already occurred
** when this function is called, NULL is returned immediately, without
** attempting the allocation or modifying the stored error code.
*/
static char *otaObjIterGetSetlist(
sqlite3ota *p,
OtaObjIter *pIter,
@@ -1115,6 +1188,21 @@ static char *otaObjIterGetSetlist(
return zList;
}
/*
** Return a nul-terminated string consisting of nByte comma separated
** "?" expressions. For example, if nByte is 3, return a pointer to
** a buffer containing the string "?,?,?".
**
** The memory for the returned string is obtained from sqlite3_malloc().
** It is the responsibility of the caller to eventually free it using
** sqlite3_free().
**
** If an OOM error is encountered when allocating space for the new
** string, an error code is left in the ota handle passed as the first
** argument and NULL is returned. Or, if an error has already occurred
** when this function is called, NULL is returned immediately, without
** attempting the allocation or modifying the stored error code.
*/
static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){
char *zRet = 0;
int nByte = nBind*2 + 1;
@@ -1149,8 +1237,6 @@ static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){
const char *zSep = "PRIMARY KEY(";
sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */
sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */
int rc; /* sqlite3_finalize() return code */
p->rc = prepareFreeAndCollectError(p->db, &pXList, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
@@ -1167,8 +1253,7 @@ static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){
break;
}
}
rc = sqlite3_finalize(pXList);
if( p->rc==SQLITE_OK ) p->rc = rc;
otaFinalize(p, pXList);
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
if( sqlite3_column_int(pXInfo, 5) ){
@@ -1180,17 +1265,11 @@ static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){
}
}
z = otaMPrintf(p, "%z)", z);
rc = sqlite3_finalize(pXInfo);
if( p->rc==SQLITE_OK ) p->rc = rc;
otaFinalize(p, pXInfo);
}
return z;
}
static void otaFinalize(sqlite3ota *p, sqlite3_stmt *pStmt){
int rc = sqlite3_finalize(pStmt);
if( p->rc==SQLITE_OK ) p->rc = rc;
}
/*
** This function creates the second imposter table used when writing to
** a table b-tree where the table has an external primary key. If the
@@ -1216,13 +1295,9 @@ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){
sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */
const char *zIdx = 0; /* Name of PK index */
sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */
int rc;
const char *zComma = "";
char *zCols = 0; /* Used to build up list of table cols */
char *zPk = 0; /* Used to build up table PK declaration */
char *zSql = 0; /* CREATE TABLE statement */
/* Figure out the name of the primary key index for the current table.
** This is needed for the argument to "PRAGMA index_xinfo". Set
@@ -1257,20 +1332,14 @@ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){
}
}
zCols = otaMPrintf(p, "%z, id INTEGER", zCols);
rc = sqlite3_finalize(pXInfo);
if( p->rc==SQLITE_OK ) p->rc = rc;
otaFinalize(p, pXInfo);
zSql = otaMPrintf(p,
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
otaMPrintfExec(p,
"CREATE TABLE ota_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
zCols, zPk
);
assert( (zSql==0)==(p->rc!=SQLITE_OK) );
if( zSql ){
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
p->rc = sqlite3_exec(p->db, zSql, 0, 0, &p->zErrmsg);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
}
sqlite3_free(zSql);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
}
}
@@ -1283,26 +1352,16 @@ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){
**
** The iterator passed as the second argument is guaranteed to point to
** a table (not an index) when this function is called. This function
** attempts to create any imposter tables required to write to the main
** attempts to create any imposter table required to write to the main
** table b-tree of the table before returning. Non-zero is returned if
** imposter tables are created, or zero otherwise.
** an imposter table are created, or zero otherwise.
**
** The required imposter tables depend on the type of table that the
** iterator currently points to.
**
** OTA_PK_NONE, OTA_PK_IPK, OTA_PK_WITHOUT_ROWID:
** A single imposter table is required. With the same schema as
** the actual target table (less any UNIQUE constraints). More
** precisely, the "same schema" means the same columns, types, collation
** sequences and primary key declaration.
**
** OTA_PK_VTAB:
** No imposters required.
**
** OTA_PK_EXTERNAL:
** Two imposters are required. The first has the same schema as the
** target database table, with no PRIMARY KEY or UNIQUE clauses. The
** second is used to access the PK b-tree index on disk.
** An imposter table is required in all cases except OTA_PK_VTAB. Only
** virtual tables are written to directly. The imposter table has the
** same schema as the actual target table (less any UNIQUE constraints).
** More precisely, the "same schema" means the same columns, types,
** collation sequences. For tables that do not have an external PRIMARY
** KEY, it also means the same PRIMARY KEY declaration.
*/
static void otaCreateImposterTable(sqlite3ota *p, OtaObjIter *pIter){
if( p->rc==SQLITE_OK && pIter->eType!=OTA_PK_VTAB ){
@@ -1340,16 +1399,12 @@ static void otaCreateImposterTable(sqlite3ota *p, OtaObjIter *pIter){
}
}
zSql = otaMPrintf(p, "CREATE TABLE \"ota_imp_%w\"(%z)%s",
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
otaMPrintfExec(p, "CREATE TABLE \"ota_imp_%w\"(%z)%s",
pIter->zTbl, zSql,
(pIter->eType==OTA_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "")
);
if( p->rc==SQLITE_OK ){
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
p->rc = sqlite3_exec(p->db, zSql, 0, 0, &p->zErrmsg);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
}
sqlite3_free(zSql);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
}
}
@@ -1547,17 +1602,17 @@ static int otaObjIterPrepareAll(
return p->rc;
}
#define OTA_INSERT 1
#define OTA_DELETE 2
#define OTA_IDX_DELETE 3
#define OTA_IDX_INSERT 4
#define OTA_UPDATE 5
/*
** Set output variable *ppStmt to point to an UPDATE statement that may
** be used to update the imposter table for the main table b-tree of the
** table object that pIter currently points to, assuming that the
** ota_control column of the data_xyz table contains zMask.
*/
static int otaGetUpdateStmt(
sqlite3ota *p,
OtaObjIter *pIter,
const char *zMask,
sqlite3_stmt **ppStmt
sqlite3ota *p, /* OTA handle */
OtaObjIter *pIter, /* Object iterator */
const char *zMask, /* ota_control value ('x.x.') */
sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */
){
if( pIter->pUpdate && strcmp(zMask, pIter->zMask)==0 ){
*ppStmt = pIter->pUpdate;
@@ -2007,7 +2062,7 @@ static void otaIncrSchemaCookie(sqlite3ota *p){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
iCookie = sqlite3_column_int(pStmt, 0);
}
p->rc = sqlite3_finalize(pStmt);
otaFinalize(p, pStmt);
}
if( p->rc==SQLITE_OK ){
otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1);
@@ -2039,19 +2094,14 @@ static void otaSaveState(sqlite3ota *p, int eStage){
OTA_STATE_CKPT, p->iWalCksum,
OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie
)
);
);
assert( pInsert==0 || rc==SQLITE_OK );
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
rc = sqlite3_finalize(pInsert);
}else{
sqlite3_finalize(pInsert);
}
if( rc!=SQLITE_OK ){
p->rc = rc;
}
if( rc!=SQLITE_OK ) p->rc = rc;
}
}
@@ -3103,6 +3153,7 @@ static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
void sqlite3ota_destroy_vfs(const char *zName){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
if( pVfs && pVfs->xOpen==otaVfsOpen ){
sqlite3_mutex_free(((ota_vfs*)pVfs)->mutex);
sqlite3_vfs_unregister(pVfs);
sqlite3_free(pVfs);
}
@@ -3158,18 +3209,24 @@ int sqlite3ota_create_vfs(const char *zName, const char *zParent){
pNew->base.mxPathname = pParent->mxPathname;
pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile;
pNew->pRealVfs = pParent;
pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
memcpy(zSpace, zName, nName);
/* Register the new VFS (not as the default) */
rc = sqlite3_vfs_register(&pNew->base, 0);
/* Allocate the mutex and register the new VFS (not as the default) */
pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
if( pNew->mutex==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_vfs_register(&pNew->base, 0);
}
}
if( rc!=SQLITE_OK ){
sqlite3_mutex_free(pNew->mutex);
sqlite3_free(pNew);
}
}
if( rc!=SQLITE_OK ){
sqlite3_free(pNew);
}
return rc;
}