diff --git a/rhizome.h b/rhizome.h index 1a6aa3fa..2888179c 100644 --- a/rhizome.h +++ b/rhizome.h @@ -243,8 +243,8 @@ __RHIZOME_INLINE int sqlite_code_busy(int code) return code == SQLITE_BUSY || code == SQLITE_LOCKED; } -sqlite3_stmt *_sqlite_prepare(struct __sourceloc, const char *sqlformat, ...); -sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc, int log_level, strbuf stmt); +sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, sqlite_retry_state *retry, const char *sqlformat, ...); +sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, sqlite_retry_state *retry, strbuf stmt); int _sqlite_retry(struct __sourceloc where, sqlite_retry_state *retry, const char *action); void _sqlite_retry_done(struct __sourceloc where, sqlite_retry_state *retry, const char *action); int _sqlite_step_retry(struct __sourceloc where, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement); @@ -255,8 +255,8 @@ int _sqlite_exec_int64(struct __sourceloc, long long *result, const char *sqlfor int _sqlite_exec_int64_retry(struct __sourceloc, sqlite_retry_state *retry, long long *result, const char *sqlformat,...); int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqlformat,...); -#define sqlite_prepare(fmt,...) _sqlite_prepare(__HERE__, (fmt), ##__VA_ARGS__) -#define sqlite_prepare_loglevel(ll,sb) _sqlite_prepare_loglevel(__HERE__, (ll), (sb)) +#define sqlite_prepare(rs,fmt,...) _sqlite_prepare(__HERE__, (rs), (fmt), ##__VA_ARGS__) +#define sqlite_prepare_loglevel(ll,rs,sb) _sqlite_prepare_loglevel(__HERE__, (ll), (rs), (sb)) #define sqlite_retry(rs,action) _sqlite_retry(__HERE__, (rs), (action)) #define sqlite_retry_done(rs,action) _sqlite_retry_done(__HERE__, (rs), (action)) #define sqlite_step(stmt) _sqlite_step_retry(__HERE__, LOG_LEVEL_ERROR, NULL, (stmt)) diff --git a/rhizome_database.c b/rhizome_database.c index 14f11fad..2f411fb4 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -270,14 +270,14 @@ void _sqlite_retry_done(struct __sourceloc where, sqlite_retry_state *retry, con Returns -1 if an error occurs (logged as an error), otherwise zero with the prepared statement in *statement. */ -sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, const char *sqlformat, ...) +sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, sqlite_retry_state *retry, const char *sqlformat, ...) { strbuf sql = strbuf_alloca(8192); strbuf_va_printf(sql, sqlformat); - return _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, sql); + return _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, retry, sql); } -sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, strbuf stmt) +sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, sqlite_retry_state *retry, strbuf stmt) { sqlite3_stmt *statement = NULL; if (strbuf_overrun(stmt)) { @@ -286,16 +286,23 @@ sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, } if (!rhizome_db && rhizome_opendb() == -1) return NULL; - switch (sqlite3_prepare_v2(rhizome_db, strbuf_str(stmt), -1, &statement, NULL)) { - case SQLITE_OK: - case SQLITE_DONE: - break; - default: - logMessage(log_level, where, "query invalid, %s: %s", sqlite3_errmsg(rhizome_db), strbuf_str(stmt)); - sqlite3_finalize(statement); - return NULL; + while (1) { + switch (sqlite3_prepare_v2(rhizome_db, strbuf_str(stmt), -1, &statement, NULL)) { + case SQLITE_OK: + case SQLITE_DONE: + return statement; + case SQLITE_BUSY: + case SQLITE_LOCKED: + if (retry && _sqlite_retry(where, retry, strbuf_str(stmt))) { + break; // back to sqlite3_prepare_v2() + } + // fall through... + default: + logMessage(log_level, where, "query invalid, %s: %s", sqlite3_errmsg(rhizome_db), strbuf_str(stmt)); + sqlite3_finalize(statement); + return NULL; + } } - return statement; } int _sqlite_step_retry(struct __sourceloc where, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement) @@ -350,7 +357,7 @@ static int _sqlite_vexec_void(struct __sourceloc where, int log_level, sqlite_re { strbuf stmt = strbuf_alloca(8192); strbuf_vsprintf(stmt, sqlformat, ap); - return _sqlite_exec_void_prepared(where, log_level, retry, sqlite_prepare_loglevel(log_level, stmt)); + return _sqlite_exec_void_prepared(where, log_level, retry, _sqlite_prepare_loglevel(where, log_level, retry, stmt)); } /* Convenience wrapper for executing an SQL command that returns no value. @@ -399,7 +406,7 @@ static int _sqlite_vexec_int64(struct __sourceloc where, sqlite_retry_state *ret { strbuf stmt = strbuf_alloca(8192); strbuf_vsprintf(stmt, sqlformat, ap); - sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, stmt); + sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, retry, stmt); if (!statement) return -1; int ret = 0; @@ -465,13 +472,13 @@ int _sqlite_exec_strbuf(struct __sourceloc where, strbuf sb, const char *sqlform { strbuf stmt = strbuf_alloca(8192); strbuf_va_printf(stmt, sqlformat); - sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, stmt); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, &retry, stmt); if (!statement) return -1; int ret = 0; int rowcount = 0; int stepcode; - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; while ((stepcode = _sqlite_step_retry(where, LOG_LEVEL_ERROR, &retry, statement)) == SQLITE_ROW) { int columncount = sqlite3_column_count(statement); if (columncount != 1) { @@ -515,11 +522,10 @@ int rhizome_make_space(int group_priority, long long bytes) return 0; /* Okay, not enough space, so free up some. */ - sqlite3_stmt *statement = sqlite_prepare("select id,length from files where highestpriority < %d order by descending length", group_priority); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "select id,length from files where highestpriority < %d order by descending length", group_priority); if (!statement) return -1; - - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; while (bytes > (rhizome_space - 65536 - rhizome_database_used_bytes()) && sqlite_step_retry(&retry, statement) == SQLITE_ROW ) { @@ -562,10 +568,10 @@ int rhizome_drop_stored_file(const char *id,int maximum_priority) { if (!rhizome_str_is_file_hash(id)) return WHYF("invalid file hash id=%s", alloca_toprint(-1, id, strlen(id))); - sqlite3_stmt *statement = sqlite_prepare("select id from manifests where filehash='%s'", id); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "select id from manifests where filehash='%s'", id); if (!statement) return WHYF("Could not drop stored file id=%s", id); - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; int can_drop = 1; while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { /* Find manifests for this file */ @@ -667,7 +673,7 @@ int rhizome_store_bundle(rhizome_manifest *m) return -1; sqlite3_stmt *stmt; - if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO MANIFESTS(id,manifest,version,inserttime,bar,filesize,filehash) VALUES(?,?,?,?,?,?,?);")) == NULL) + if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO MANIFESTS(id,manifest,version,inserttime,bar,filesize,filehash) VALUES(?,?,?,?,?,?,?);")) == NULL) goto rollback; if (!( sqlite_code_ok(sqlite3_bind_text(stmt, 1, manifestid, -1, SQLITE_TRANSIENT)) && sqlite_code_ok(sqlite3_bind_blob(stmt, 2, m->manifestdata, m->manifest_bytes, SQLITE_TRANSIENT)) @@ -687,7 +693,7 @@ int rhizome_store_bundle(rhizome_manifest *m) // we might need to leave the old file around for a bit // clean out unreferenced files first - if ((stmt = sqlite_prepare("DELETE FROM FILES WHERE inserttime < ? AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);")) == NULL) + if ((stmt = sqlite_prepare(&retry, "DELETE FROM FILES WHERE inserttime < ? AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);")) == NULL) goto rollback; if (!sqlite_code_ok(sqlite3_bind_int64(stmt, 1, (long long)(gettime_ms() - 60000)))) { WHYF("query failed, %s: %s", sqlite3_errmsg(rhizome_db), sqlite3_sql(stmt)); @@ -703,7 +709,7 @@ int rhizome_store_bundle(rhizome_manifest *m) if (closed<1) closed=0; int ciphered=rhizome_manifest_get_ll(m,"cipheredgroup"); if (ciphered<1) ciphered=0; - if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO GROUPLIST(id,closed,ciphered,priority) VALUES (?,?,?,?);")) == NULL) + if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO GROUPLIST(id,closed,ciphered,priority) VALUES (?,?,?,?);")) == NULL) goto rollback; if (!( sqlite_code_ok(sqlite3_bind_text(stmt, 1, manifestid, -1, SQLITE_TRANSIENT)) && sqlite_code_ok(sqlite3_bind_int(stmt, 2, closed)) @@ -720,7 +726,7 @@ int rhizome_store_bundle(rhizome_manifest *m) } if (m->group_count > 0) { - if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO GROUPMEMBERSHIPS(manifestid,groupid) VALUES(?, ?);")) == NULL) + if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO GROUPMEMBERSHIPS(manifestid,groupid) VALUES(?, ?);")) == NULL) goto rollback; int i; for (i=0;igroup_count;i++){ @@ -758,7 +764,8 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch strbuf_sprintf(b, " OFFSET %u", offset); if (strbuf_overrun(b)) RETURN(WHYF("SQL command too long: ", strbuf_str(b))); - sqlite3_stmt *statement = sqlite_prepare("%s", strbuf_str(b)); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b)); if (!statement) return -1; int ret = 0; @@ -775,7 +782,6 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch cli_puts("sender"); cli_delim(":"); cli_puts("recipient"); cli_delim(":"); cli_puts("name"); cli_delim("\n"); // should be last, because name may contain ':' - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { ++rows; if (!( sqlite3_column_count(statement) == 4 @@ -928,7 +934,8 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key) int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); */ - sqlite3_stmt *statement = sqlite_prepare("INSERT OR REPLACE INTO FILES(id,data,length,highestpriority,datavalid,inserttime) VALUES('%s',?,%lld,%d,0,%lld);", + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "INSERT OR REPLACE INTO FILES(id,data,length,highestpriority,datavalid,inserttime) VALUES('%s',?,%lld,%d,0,%lld);", hash, (long long)m->fileLength, priority, (long long)gettime_ms() ); if (!statement) @@ -940,7 +947,6 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key) goto insert_row_fail; } /* Do actual insert, and abort if it fails */ - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; if (_sqlite_exec_void_prepared(__HERE__, LOG_LEVEL_ERROR, &retry, statement) == -1) { insert_row_fail: WHYF("Failed to insert row for fileid=%s", hash); @@ -1111,7 +1117,8 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, if (debug & DEBUG_RHIZOME) DEBUGF("sql query: %s", sqlcmd); int ret = 0; - sqlite3_stmt *statement = sqlite_prepare("%s", strbuf_str(b)); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b)); if (!statement) return -1; int field = 1; @@ -1126,7 +1133,6 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, if (checkVersionP) sqlite3_bind_int64(statement, field++, m->version); size_t rows = 0; - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { ++rows; if (debug & DEBUG_RHIZOME) DEBUGF("Row %d", rows); @@ -1255,13 +1261,13 @@ int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp) unsigned char manifest_id[RHIZOME_MANIFEST_ID_BYTES]; if (fromhexstr(manifest_id, manifestid, RHIZOME_MANIFEST_ID_BYTES) == -1) return WHY("Invalid manifest ID"); - sqlite3_stmt *statement = sqlite_prepare("SELECT id, manifest, version, inserttime FROM manifests WHERE id = ?"); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "SELECT id, manifest, version, inserttime FROM manifests WHERE id = ?"); if (!statement) return -1; char manifestIdUpper[RHIZOME_MANIFEST_ID_STRLEN + 1]; tohex(manifestIdUpper, manifest_id, RHIZOME_MANIFEST_ID_BYTES); sqlite3_bind_text(statement, 1, manifestIdUpper, -1, SQLITE_STATIC); - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; int ret = 0; rhizome_manifest *m = NULL; while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { @@ -1355,7 +1361,8 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsign WHY("Failed to update file priority"); return 0; } - sqlite3_stmt *statement = sqlite_prepare("SELECT id, rowid, length FROM files WHERE id = ? AND datavalid != 0"); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "SELECT id, rowid, length FROM files WHERE id = ? AND datavalid != 0"); if (!statement) return -1; int ret = 0; @@ -1364,7 +1371,6 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsign fileIdUpper[RHIZOME_FILEHASH_STRLEN] = '\0'; str_toupper_inplace(fileIdUpper); sqlite3_bind_text(statement, 1, fileIdUpper, -1, SQLITE_STATIC); - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; int stepcode = sqlite_step_retry(&retry, statement); if (stepcode != SQLITE_ROW) { ret = 0; // no files found diff --git a/rhizome_direct.c b/rhizome_direct.c index 8ef146dc..9d7f2c63 100644 --- a/rhizome_direct.c +++ b/rhizome_direct.c @@ -428,10 +428,9 @@ rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int pref alloca_tohex(low,RHIZOME_MANIFEST_ID_BYTES), alloca_tohex(high,RHIZOME_MANIFEST_ID_BYTES)); - sqlite3_stmt *statement=sqlite_prepare(query); - sqlite3_blob *blob=NULL; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; - + sqlite3_stmt *statement = sqlite_prepare(&retry, query); + sqlite3_blob *blob=NULL; if (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { int ret; @@ -790,7 +789,7 @@ int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTE alloca_tohex(bid_max,RHIZOME_MANIFEST_ID_BYTES), bars_requested); - sqlite3_stmt *statement=sqlite_prepare(query); + sqlite3_stmt *statement=sqlite_prepare(&retry, query); sqlite3_blob *blob=NULL; int bars_written=0; diff --git a/rhizome_http.c b/rhizome_http.c index 028c9005..cf89a268 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -401,12 +401,12 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c return WHY("Not enough space to fit any records"); } - sqlite3_stmt *statement = sqlite_prepare("%s LIMIT %lld,%d", r->source, r->source_index, record_count); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare(&retry, "%s LIMIT %lld,%d", r->source, r->source_index, record_count); if (!statement) return -1; if (debug & DEBUG_RHIZOME_TX) DEBUG(sqlite3_sql(statement)); - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; while( r->buffer_length + r->source_record_size < r->buffer_size && sqlite_step_retry(&retry, statement) == SQLITE_ROW ) {