From 5bc20b852b907c5a68335ecfee2db59455448c8a Mon Sep 17 00:00:00 2001 From: Jasio Wu Date: Thu, 21 May 2020 21:26:38 +0800 Subject: [PATCH] Prevent WAL locking by resetting prepared statements after use Merge pull request #129 --- YYCache/YYKVStorage.m | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/YYCache/YYKVStorage.m b/YYCache/YYKVStorage.m index 501dfdd..89ed7bb 100644 --- a/YYCache/YYKVStorage.m +++ b/YYCache/YYKVStorage.m @@ -169,7 +169,10 @@ - (BOOL)_dbInitialize { - (void)_dbCheckpoint { if (![self _dbCheck]) return; // Cause a checkpoint to occur, merge `sqlite-wal` file to `sqlite` file. - sqlite3_wal_checkpoint(_db, NULL); + int result = sqlite3_wal_checkpoint(_db, NULL); + if (result != SQLITE_OK && _errorLogsEnabled) { + NSLog(@"%s line:%d sqlite WAL checkpoint error (%d)", __FUNCTION__, __LINE__, result); + } } - (BOOL)_dbExecute:(NSString *)sql { @@ -197,7 +200,14 @@ - (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql { } CFDictionarySetValue(_dbStmtCache, (__bridge const void *)(sql), stmt); } else { - sqlite3_reset(stmt); + if (sqlite3_stmt_busy(stmt)) { + //just in case someone will forget to sqlite3_reset cached statement + //causing WAL file lock + if (_errorLogsEnabled) { + NSLog(@"%s line:%d WARN: cached statement for query \"%@\" was not reset.", __FUNCTION__, __LINE__, sql); + } + sqlite3_reset(stmt); + } } return stmt; } @@ -239,6 +249,7 @@ - (BOOL)_dbSaveWithKey:(NSString *)key value:(NSData *)value fileName:(NSString sqlite3_bind_blob(stmt, 7, extendedData.bytes, (int)extendedData.length, 0); int result = sqlite3_step(stmt); + sqlite3_reset(stmt); if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite insert error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; @@ -253,6 +264,7 @@ - (BOOL)_dbUpdateAccessTimeWithKey:(NSString *)key { sqlite3_bind_int(stmt, 1, (int)time(NULL)); sqlite3_bind_text(stmt, 2, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); + sqlite3_reset(stmt); if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite update error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; @@ -289,6 +301,7 @@ - (BOOL)_dbDeleteItemWithKey:(NSString *)key { sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); + sqlite3_reset(stmt); if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d db delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; @@ -322,6 +335,7 @@ - (BOOL)_dbDeleteItemsWithSizeLargerThan:(int)size { if (!stmt) return NO; sqlite3_bind_int(stmt, 1, size); int result = sqlite3_step(stmt); + sqlite3_reset(stmt); if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; @@ -335,6 +349,7 @@ - (BOOL)_dbDeleteItemsWithTimeEarlierThan:(int)time { if (!stmt) return NO; sqlite3_bind_int(stmt, 1, time); int result = sqlite3_step(stmt); + sqlite3_reset(stmt); if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; @@ -380,6 +395,7 @@ - (YYKVStorageItem *)_dbGetItemWithKey:(NSString *)key excludeInlineData:(BOOL)e if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } } + sqlite3_reset(stmt); return item; } @@ -428,12 +444,14 @@ - (NSData *)_dbGetValueWithKey:(NSString *)key { if (result == SQLITE_ROW) { const void *inline_data = sqlite3_column_blob(stmt, 0); int inline_data_bytes = sqlite3_column_bytes(stmt, 0); + sqlite3_reset(stmt); if (!inline_data || inline_data_bytes <= 0) return nil; return [NSData dataWithBytes:inline_data length:inline_data_bytes]; } else { if (result != SQLITE_DONE) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } + sqlite3_reset(stmt); return nil; } } @@ -447,6 +465,7 @@ - (NSString *)_dbGetFilenameWithKey:(NSString *)key { if (result == SQLITE_ROW) { char *filename = (char *)sqlite3_column_text(stmt, 0); if (filename && *filename != 0) { + sqlite3_reset(stmt); return [NSString stringWithUTF8String:filename]; } } else { @@ -454,6 +473,7 @@ - (NSString *)_dbGetFilenameWithKey:(NSString *)key { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } } + sqlite3_reset(stmt); return nil; } @@ -512,6 +532,7 @@ - (NSMutableArray *)_dbGetFilenamesWithSizeLargerThan:(int)size { break; } } while (1); + sqlite3_reset(stmt); return filenames; } @@ -538,6 +559,7 @@ - (NSMutableArray *)_dbGetFilenamesWithTimeEarlierThan:(int)time { break; } } while (1); + sqlite3_reset(stmt); return filenames; } @@ -570,6 +592,7 @@ - (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeAscWithLimit:(int)count { break; } } while (1); + sqlite3_reset(stmt); return items; } @@ -581,9 +604,12 @@ - (int)_dbGetItemCountWithKey:(NSString *)key { int result = sqlite3_step(stmt); if (result != SQLITE_ROW) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); + sqlite3_reset(stmt); return -1; } - return sqlite3_column_int(stmt, 0); + int count = sqlite3_column_int(stmt, 0); + sqlite3_reset(stmt); + return count; } - (int)_dbGetTotalItemSize { @@ -593,9 +619,12 @@ - (int)_dbGetTotalItemSize { int result = sqlite3_step(stmt); if (result != SQLITE_ROW) { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); + sqlite3_reset(stmt); return -1; } - return sqlite3_column_int(stmt, 0); + int size = sqlite3_column_int(stmt, 0); + sqlite3_reset(stmt); + return size; } - (int)_dbGetTotalItemCount { @@ -607,7 +636,9 @@ - (int)_dbGetTotalItemCount { if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return -1; } - return sqlite3_column_int(stmt, 0); + int count = sqlite3_column_int(stmt, 0); + sqlite3_reset(stmt); + return count; }