|
@@ -19,6 +19,9 @@
|
|
|
#import "sqlite3.h"
|
|
|
#endif
|
|
|
|
|
|
+
|
|
|
+static const NSUInteger kMaxErrorRetryCount = 8;
|
|
|
+static const NSTimeInterval kMinRetryTimeInterval = 2.0;
|
|
|
static const int kPathLengthMax = PATH_MAX - 64;
|
|
|
static NSString *const kDBFileName = @"manifest.sqlite";
|
|
|
static NSString *const kDBShmFileName = @"manifest.sqlite-shm";
|
|
@@ -26,6 +29,7 @@ static NSString *const kDBWalFileName = @"manifest.sqlite-wal";
|
|
|
static NSString *const kDataDirectoryName = @"data";
|
|
|
static NSString *const kTrashDirectoryName = @"trash";
|
|
|
|
|
|
+
|
|
|
/*
|
|
|
File:
|
|
|
/path/
|
|
@@ -81,6 +85,8 @@ static UIApplication *_YYSharedApplication() {
|
|
|
|
|
|
sqlite3 *_db;
|
|
|
CFMutableDictionaryRef _dbStmtCache;
|
|
|
+ NSTimeInterval _dbLastOpenErrorTime;
|
|
|
+ NSUInteger _dbOpenErrorCount;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -94,13 +100,19 @@ static UIApplication *_YYSharedApplication() {
|
|
|
CFDictionaryKeyCallBacks keyCallbacks = kCFCopyStringDictionaryKeyCallBacks;
|
|
|
CFDictionaryValueCallBacks valueCallbacks = {0};
|
|
|
_dbStmtCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &keyCallbacks, &valueCallbacks);
|
|
|
+ _dbLastOpenErrorTime = 0;
|
|
|
+ _dbOpenErrorCount = 0;
|
|
|
return YES;
|
|
|
} else {
|
|
|
_db = NULL;
|
|
|
if (_dbStmtCache) CFRelease(_dbStmtCache);
|
|
|
_dbStmtCache = NULL;
|
|
|
+ _dbLastOpenErrorTime = CACurrentMediaTime();
|
|
|
+ _dbOpenErrorCount++;
|
|
|
|
|
|
- NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result);
|
|
|
+ if (_errorLogsEnabled) {
|
|
|
+ NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result);
|
|
|
+ }
|
|
|
return NO;
|
|
|
}
|
|
|
}
|
|
@@ -128,15 +140,25 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
}
|
|
|
} else if (result != SQLITE_OK) {
|
|
|
- NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);
|
|
|
+ if (_errorLogsEnabled) {
|
|
|
+ NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);
|
|
|
+ }
|
|
|
}
|
|
|
} while (retry);
|
|
|
_db = NULL;
|
|
|
return YES;
|
|
|
}
|
|
|
|
|
|
-- (BOOL)_dbIsReady {
|
|
|
- return (_db);
|
|
|
+- (BOOL)_dbCheck {
|
|
|
+ if (!_db) {
|
|
|
+ if (_dbOpenErrorCount < kMaxErrorRetryCount &&
|
|
|
+ CACurrentMediaTime() - _dbLastOpenErrorTime > kMinRetryTimeInterval) {
|
|
|
+ return [self _dbOpen] && [self _dbInitialize];
|
|
|
+ } else {
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return YES;
|
|
|
}
|
|
|
|
|
|
- (BOOL)_dbInitialize {
|
|
@@ -145,14 +167,14 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (void)_dbCheckpoint {
|
|
|
- if (![self _dbIsReady]) return;
|
|
|
+ if (![self _dbCheck]) return;
|
|
|
// Cause a checkpoint to occur, merge `sqlite-wal` file to `sqlite` file.
|
|
|
sqlite3_wal_checkpoint(_db, NULL);
|
|
|
}
|
|
|
|
|
|
- (BOOL)_dbExecute:(NSString *)sql {
|
|
|
if (sql.length == 0) return NO;
|
|
|
- if (![self _dbIsReady]) return NO;
|
|
|
+ if (![self _dbCheck]) return NO;
|
|
|
|
|
|
char *error = NULL;
|
|
|
int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error);
|
|
@@ -165,7 +187,7 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql {
|
|
|
- if (![self _dbIsReady] || sql.length == 0 || !_dbStmtCache) return NULL;
|
|
|
+ if (![self _dbCheck] || sql.length == 0 || !_dbStmtCache) return NULL;
|
|
|
sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql));
|
|
|
if (!stmt) {
|
|
|
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
|
|
@@ -239,7 +261,7 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (BOOL)_dbUpdateAccessTimeWithKeys:(NSArray *)keys {
|
|
|
- if (![self _dbIsReady]) return NO;
|
|
|
+ if (![self _dbCheck]) return NO;
|
|
|
int t = (int)time(NULL);
|
|
|
NSString *sql = [NSString stringWithFormat:@"update manifest set last_access_time = %d where key in (%@);", t, [self _dbJoinedKeys:keys]];
|
|
|
|
|
@@ -275,7 +297,7 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (BOOL)_dbDeleteItemWithKeys:(NSArray *)keys {
|
|
|
- if (![self _dbIsReady]) return NO;
|
|
|
+ if (![self _dbCheck]) return NO;
|
|
|
NSString *sql = [NSString stringWithFormat:@"delete from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
|
|
|
sqlite3_stmt *stmt = NULL;
|
|
|
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
|
|
@@ -362,7 +384,7 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (NSMutableArray *)_dbGetItemWithKeys:(NSArray *)keys excludeInlineData:(BOOL)excludeInlineData {
|
|
|
- if (![self _dbIsReady]) return nil;
|
|
|
+ if (![self _dbCheck]) return nil;
|
|
|
NSString *sql;
|
|
|
if (excludeInlineData) {
|
|
|
sql = [NSString stringWithFormat:@"select key, filename, size, modification_time, last_access_time, extended_data from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
|
|
@@ -436,7 +458,7 @@ static UIApplication *_YYSharedApplication() {
|
|
|
}
|
|
|
|
|
|
- (NSMutableArray *)_dbGetFilenameWithKeys:(NSArray *)keys {
|
|
|
- if (![self _dbIsReady]) return nil;
|
|
|
+ if (![self _dbCheck]) return nil;
|
|
|
NSString *sql = [NSString stringWithFormat:@"select filename from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
|
|
|
sqlite3_stmt *stmt = NULL;
|
|
|
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
|