Igor Tandetnik wrote: > On 2/4/2014 5:23 AM, Yuriy Kaminskiy wrote: >> How sqlite is supposed to behave when >> *) there are read-only transaction; >> *) there are update transaction on other connection; >> *) cache space is exhausted by update transaction; >> *) sqlite was not able to upgrade RESERVED lock to EXCLUSIVE due to >> presence of SHARED lock, even after waiting for busy_timeout; >> ? > > SQLite should return SQLITE_BUSY error for the statement that triggered > the cache spill. From the documentation of sqlite3_step:
> SQLITE_BUSY means that the database engine was unable to acquire the > database locks it needs to do its job. If the statement is a COMMIT or > occurs outside of an explicit transaction, then you can retry the > statement. If the statement is not a COMMIT and occurs within an > explicit transaction then you should rollback the transaction before > continuing. > > This second part is precisely for the case where a statement other than > a COMMIT wants to acquire EXCLUSIVE lock due to cache overflow, and > fails. If I recall previous discussions of this topic correctly, SQLite > cannot guarantee that the in-memory cache is in a good state at this > point, and so the only safe course of action is to discard it by rolling > back. But in fact, it *does not return error* (except for COMMIT). Verified on sqlite 3.7.7 and 3.8.2. >> It can either fail update statement (but I don't see that in test >> below: it >> sleeps for busy_timeout, but *does not* return error), or keep on >> storing data >> in memory [it *does not* write anything] (thus using over specified >> cache size? >> [and eventually overflow virtual memory?]), or what? > > It's supposed to return an error. There might be some flaw in your test; > I myself don't speak Perl (and am too lazy to conduct a test of my own). Phew. Do you speak C? Enjoy. #include <stdio.h> #include <sqlite3.h> #include <assert.h> #include <inttypes.h> int main(int argc, char *argv[]) { sqlite3 *dbh; sqlite3 *dbh2; sqlite3_stmt *sth; sqlite3_stmt *sth2; sqlite3_stmt *ins_sth; char *errmsg; int rc; int i, j; rc = sqlite3_open("ttt.db3", &dbh); assert(rc == SQLITE_OK); rc = sqlite3_open("ttt.db3", &dbh2); assert(rc == SQLITE_OK); rc = sqlite3_busy_timeout(dbh, 10000); assert(rc == SQLITE_OK); rc = sqlite3_busy_timeout(dbh2, 10000); assert(rc == SQLITE_OK); #define sql_exec(dbh, sql) do { \ rc = sqlite3_exec(dbh, sql, NULL, NULL, &errmsg); \ printf("exec: %p, '%s' -> %d\n", dbh, sql, rc); \ assert(errmsg == NULL); \ sqlite3_free(errmsg); \ } while(0) sql_exec(dbh, "PRAGMA page_size = 1024"); sql_exec(dbh, "PRAGMA cache_size = 4"); sql_exec(dbh, "CREATE TABLE IF NOT EXISTS t (i)"); sql_exec(dbh2, "PRAGMA cache_size = 4"); rc = sqlite3_prepare_v2(dbh, "SELECT * FROM t", -1, &sth, NULL); assert(rc == SQLITE_OK); rc = sqlite3_prepare_v2(dbh2, "SELECT * FROM t", -1, &sth2, NULL); assert(rc == SQLITE_OK); rc = sqlite3_prepare_v2(dbh, "INSERT INTO t VALUES(?)", -1, &ins_sth, NULL); assert(rc == SQLITE_OK); sql_exec(dbh, "BEGIN IMMEDIATE"); sql_exec(dbh2, "BEGIN"); rc = sqlite3_step(sth2); assert(rc == SQLITE_DONE || rc == SQLITE_ROW); j = 0; printf("insert...\r"); fflush(stdout); for(i = 0; i < 1000; i++) { rc = sqlite3_bind_int(ins_sth, 1, i); assert(rc == SQLITE_OK); rc = sqlite3_step(ins_sth); assert(rc == SQLITE_DONE); j += sqlite3_changes(dbh); printf("insert: %04d\r", i); fflush(stdout); rc = sqlite3_reset(ins_sth); assert(rc == SQLITE_OK); } printf("insert done\n"); printf("j = %04d\n", j); i = 0; printf("select...\r"); fflush(stdout); while((rc = sqlite3_step(sth)) == SQLITE_ROW) { i++; printf("select: %04d\r", i); fflush(stdout); } printf("select done\n"); printf("i = %04d\n", i); assert(rc == SQLITE_DONE); rc = sqlite3_reset(sth2); assert(rc == SQLITE_OK); rc = sqlite3_reset(sth); assert(rc == SQLITE_OK); sql_exec(dbh2, "COMMIT"); sql_exec(dbh, "COMMIT"); rc = sqlite3_finalize(sth); sth = NULL; assert(rc == SQLITE_OK); rc = sqlite3_finalize(sth2); sth2 = NULL; assert(rc == SQLITE_OK); rc = sqlite3_finalize(ins_sth); ins_sth = NULL; assert(rc == SQLITE_OK); rc = sqlite3_close(dbh); dbh = NULL; assert(rc == SQLITE_OK); rc = sqlite3_close(dbh2); dbh2 = NULL; assert(rc == SQLITE_OK); return 0; } _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users