appium-webdriveragent 3.9.2 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/PrivateHeaders/.DS_Store +0 -0
  2. package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +3 -0
  3. package/README.md +0 -1
  4. package/WebDriverAgent.xcodeproj/project.pbxproj +56 -56
  5. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/elf.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/WebDriverAgent.xcodeproj/xcuserdata/elf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +51 -0
  7. package/WebDriverAgent.xcodeproj/xcuserdata/{kazuaki.xcuserdatad → elf.xcuserdatad}/xcschemes/xcschememanagement.plist +23 -8
  8. package/WebDriverAgentLib/.DS_Store +0 -0
  9. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +0 -17
  10. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +0 -16
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -14
  12. package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h +37 -0
  13. package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +51 -0
  14. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +8 -2
  15. package/WebDriverAgentLib/Commands/FBElementCommands.m +3 -1
  16. package/WebDriverAgentLib/Commands/FBOrientationCommands.m +20 -9
  17. package/WebDriverAgentLib/Commands/FBSessionCommands.m +119 -99
  18. package/WebDriverAgentLib/FBApplication.m +1 -1
  19. package/WebDriverAgentLib/Routing/FBElementCache.m +42 -11
  20. package/WebDriverAgentLib/Routing/FBResponsePayload.m +9 -3
  21. package/WebDriverAgentLib/Routing/FBSession.h +6 -0
  22. package/WebDriverAgentLib/Routing/FBSession.m +45 -55
  23. package/WebDriverAgentLib/Utilities/FBAlertsMonitor.h +1 -3
  24. package/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +6 -13
  25. package/WebDriverAgentLib/Utilities/FBCapabilities.h +23 -0
  26. package/WebDriverAgentLib/Utilities/FBCapabilities.m +23 -0
  27. package/WebDriverAgentLib/Utilities/FBConfiguration.m +6 -1
  28. package/WebDriverAgentLib/Utilities/FBScreenshot.m +125 -14
  29. package/WebDriverAgentLib/Utilities/FBSettings.h +23 -23
  30. package/WebDriverAgentLib/Utilities/FBSettings.m +23 -23
  31. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +16 -0
  32. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +16 -0
  33. package/WebDriverAgentLib/Utilities/FBXPath.m +15 -44
  34. package/WebDriverAgentLib/Utilities/LRUCache/.DS_Store +0 -0
  35. package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h +59 -0
  36. package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +104 -0
  37. package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.h +43 -0
  38. package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.m +59 -0
  39. package/WebDriverAgentLib/Vendor/.DS_Store +0 -0
  40. package/WebDriverAgentRunner/.DS_Store +0 -0
  41. package/WebDriverAgentRunner-Runner.app.zip +0 -0
  42. package/WebDriverAgentTests/IntegrationApp/Resources/.DS_Store +0 -0
  43. package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +20 -16
  44. package/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +2 -1
  45. package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +11 -0
  46. package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h +3 -0
  47. package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m +15 -0
  48. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -0
  49. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -0
  50. package/WebDriverAgentTests/UnitTests/FBSessionTests.m +11 -1
  51. package/WebDriverAgentTests/UnitTests/FBXPathTests.m +3 -1
  52. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +1 -0
  53. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.m +1 -0
  54. package/package.json +3 -3
  55. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  56. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/WorkspaceSettings.xcsettings +0 -20
  57. package/WebDriverAgent.xcodeproj/xcuserdata/kazuaki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -906
  58. package/WebDriverAgentLib/Vendor/YYCache/YYCache.h +0 -206
  59. package/WebDriverAgentLib/Vendor/YYCache/YYCache.m +0 -140
  60. package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.h +0 -412
  61. package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.m +0 -462
  62. package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.h +0 -325
  63. package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.m +0 -1068
  64. package/WebDriverAgentLib/Vendor/YYCache/YYMemoryCache.h +0 -213
  65. package/WebDriverAgentLib/Vendor/YYCache/YYMemoryCache.m +0 -508
@@ -1,1068 +0,0 @@
1
- //
2
- // YYKVStorage.m
3
- // YYCache <https://github.com/ibireme/YYCache>
4
- //
5
- // Created by ibireme on 15/4/22.
6
- // Copyright (c) 2015 ibireme.
7
- //
8
- // This source code is licensed under the MIT-style license found in the
9
- // LICENSE file in the root directory of this source tree.
10
- //
11
-
12
- #import "YYKVStorage.h"
13
- #import <UIKit/UIKit.h>
14
- #import <time.h>
15
-
16
- #if __has_include(<sqlite3.h>)
17
- #import <sqlite3.h>
18
- #else
19
- #import "sqlite3.h"
20
- #endif
21
-
22
-
23
- static const NSUInteger kMaxErrorRetryCount = 8;
24
- static const NSTimeInterval kMinRetryTimeInterval = 2.0;
25
- static const int kPathLengthMax = PATH_MAX - 64;
26
- static NSString *const kDBFileName = @"manifest.sqlite";
27
- static NSString *const kDBShmFileName = @"manifest.sqlite-shm";
28
- static NSString *const kDBWalFileName = @"manifest.sqlite-wal";
29
- static NSString *const kDataDirectoryName = @"data";
30
- static NSString *const kTrashDirectoryName = @"trash";
31
-
32
-
33
- /*
34
- File:
35
- /path/
36
- /manifest.sqlite
37
- /manifest.sqlite-shm
38
- /manifest.sqlite-wal
39
- /data/
40
- /e10adc3949ba59abbe56e057f20f883e
41
- /e10adc3949ba59abbe56e057f20f883e
42
- /trash/
43
- /unused_file_or_folder
44
-
45
- SQL:
46
- create table if not exists manifest (
47
- key text,
48
- filename text,
49
- size integer,
50
- inline_data blob,
51
- modification_time integer,
52
- last_access_time integer,
53
- extended_data blob,
54
- primary key(key)
55
- );
56
- create index if not exists last_access_time_idx on manifest(last_access_time);
57
- */
58
-
59
- /// Returns nil in App Extension.
60
- static UIApplication *_YYSharedApplication() {
61
- static BOOL isAppExtension = NO;
62
- static dispatch_once_t onceToken;
63
- dispatch_once(&onceToken, ^{
64
- Class cls = NSClassFromString(@"UIApplication");
65
- if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES;
66
- if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES;
67
- });
68
- #pragma clang diagnostic push
69
- #pragma clang diagnostic ignored "-Wundeclared-selector"
70
- return isAppExtension ? nil : [UIApplication performSelector:@selector(sharedApplication)];
71
- #pragma clang diagnostic pop
72
- }
73
-
74
-
75
- @implementation YYKVStorageItem
76
- @end
77
-
78
- @implementation YYKVStorage {
79
- dispatch_queue_t _trashQueue;
80
-
81
- NSString *_path;
82
- NSString *_dbPath;
83
- NSString *_dataPath;
84
- NSString *_trashPath;
85
-
86
- sqlite3 *_db;
87
- CFMutableDictionaryRef _dbStmtCache;
88
- NSTimeInterval _dbLastOpenErrorTime;
89
- NSUInteger _dbOpenErrorCount;
90
- }
91
-
92
-
93
- #pragma mark - db
94
-
95
- - (BOOL)_dbOpen {
96
- if (_db) return YES;
97
-
98
- int result = sqlite3_open(_dbPath.UTF8String, &_db);
99
- if (result == SQLITE_OK) {
100
- CFDictionaryKeyCallBacks keyCallbacks = kCFCopyStringDictionaryKeyCallBacks;
101
- CFDictionaryValueCallBacks valueCallbacks = {0};
102
- _dbStmtCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &keyCallbacks, &valueCallbacks);
103
- _dbLastOpenErrorTime = 0;
104
- _dbOpenErrorCount = 0;
105
- return YES;
106
- } else {
107
- _db = NULL;
108
- if (_dbStmtCache) CFRelease(_dbStmtCache);
109
- _dbStmtCache = NULL;
110
- _dbLastOpenErrorTime = CACurrentMediaTime();
111
- _dbOpenErrorCount++;
112
-
113
- if (_errorLogsEnabled) {
114
- NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result);
115
- }
116
- return NO;
117
- }
118
- }
119
-
120
- - (BOOL)_dbClose {
121
- if (!_db) return YES;
122
-
123
- int result = 0;
124
- BOOL retry = NO;
125
- BOOL stmtFinalized = NO;
126
-
127
- if (_dbStmtCache) CFRelease(_dbStmtCache);
128
- _dbStmtCache = NULL;
129
-
130
- do {
131
- retry = NO;
132
- result = sqlite3_close(_db);
133
- if (result == SQLITE_BUSY || result == SQLITE_LOCKED) {
134
- if (!stmtFinalized) {
135
- stmtFinalized = YES;
136
- sqlite3_stmt *stmt;
137
- while ((stmt = sqlite3_next_stmt(_db, nil)) != 0) {
138
- sqlite3_finalize(stmt);
139
- retry = YES;
140
- }
141
- }
142
- } else if (result != SQLITE_OK) {
143
- if (_errorLogsEnabled) {
144
- NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);
145
- }
146
- }
147
- } while (retry);
148
- _db = NULL;
149
- return YES;
150
- }
151
-
152
- - (BOOL)_dbCheck {
153
- if (!_db) {
154
- if (_dbOpenErrorCount < kMaxErrorRetryCount &&
155
- CACurrentMediaTime() - _dbLastOpenErrorTime > kMinRetryTimeInterval) {
156
- return [self _dbOpen] && [self _dbInitialize];
157
- } else {
158
- return NO;
159
- }
160
- }
161
- return YES;
162
- }
163
-
164
- - (BOOL)_dbInitialize {
165
- NSString *sql = @"pragma journal_mode = wal; pragma synchronous = normal; create table if not exists manifest (key text, filename text, size integer, inline_data blob, modification_time integer, last_access_time integer, extended_data blob, primary key(key)); create index if not exists last_access_time_idx on manifest(last_access_time);";
166
- return [self _dbExecute:sql];
167
- }
168
-
169
- - (void)_dbCheckpoint {
170
- if (![self _dbCheck]) return;
171
- // Cause a checkpoint to occur, merge `sqlite-wal` file to `sqlite` file.
172
- sqlite3_wal_checkpoint(_db, NULL);
173
- }
174
-
175
- - (BOOL)_dbExecute:(NSString *)sql {
176
- if (sql.length == 0) return NO;
177
- if (![self _dbCheck]) return NO;
178
-
179
- char *error = NULL;
180
- int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error);
181
- if (error) {
182
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite exec error (%d): %s", __FUNCTION__, __LINE__, result, error);
183
- sqlite3_free(error);
184
- }
185
-
186
- return result == SQLITE_OK;
187
- }
188
-
189
- - (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql {
190
- if (![self _dbCheck] || sql.length == 0 || !_dbStmtCache) return NULL;
191
- sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql));
192
- if (!stmt) {
193
- int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
194
- if (result != SQLITE_OK) {
195
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
196
- return NULL;
197
- }
198
- CFDictionarySetValue(_dbStmtCache, (__bridge const void *)(sql), stmt);
199
- } else {
200
- sqlite3_reset(stmt);
201
- }
202
- return stmt;
203
- }
204
-
205
- - (NSString *)_dbJoinedKeys:(NSArray *)keys {
206
- NSMutableString *string = [NSMutableString new];
207
- for (NSUInteger i = 0,max = keys.count; i < max; i++) {
208
- [string appendString:@"?"];
209
- if (i + 1 != max) {
210
- [string appendString:@","];
211
- }
212
- }
213
- return string;
214
- }
215
-
216
- - (void)_dbBindJoinedKeys:(NSArray *)keys stmt:(sqlite3_stmt *)stmt fromIndex:(int)index{
217
- for (int i = 0, max = (int)keys.count; i < max; i++) {
218
- NSString *key = keys[i];
219
- sqlite3_bind_text(stmt, index + i, key.UTF8String, -1, NULL);
220
- }
221
- }
222
-
223
- - (BOOL)_dbSaveWithKey:(NSString *)key value:(NSData *)value fileName:(NSString *)fileName extendedData:(NSData *)extendedData {
224
- NSString *sql = @"insert or replace into manifest (key, filename, size, inline_data, modification_time, last_access_time, extended_data) values (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
225
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
226
- if (!stmt) return NO;
227
-
228
- int timestamp = (int)time(NULL);
229
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
230
- sqlite3_bind_text(stmt, 2, fileName.UTF8String, -1, NULL);
231
- sqlite3_bind_int(stmt, 3, (int)value.length);
232
- if (fileName.length == 0) {
233
- sqlite3_bind_blob(stmt, 4, value.bytes, (int)value.length, 0);
234
- } else {
235
- sqlite3_bind_blob(stmt, 4, NULL, 0, 0);
236
- }
237
- sqlite3_bind_int(stmt, 5, timestamp);
238
- sqlite3_bind_int(stmt, 6, timestamp);
239
- sqlite3_bind_blob(stmt, 7, extendedData.bytes, (int)extendedData.length, 0);
240
-
241
- int result = sqlite3_step(stmt);
242
- if (result != SQLITE_DONE) {
243
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite insert error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
244
- return NO;
245
- }
246
- return YES;
247
- }
248
-
249
- - (BOOL)_dbUpdateAccessTimeWithKey:(NSString *)key {
250
- NSString *sql = @"update manifest set last_access_time = ?1 where key = ?2;";
251
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
252
- if (!stmt) return NO;
253
- sqlite3_bind_int(stmt, 1, (int)time(NULL));
254
- sqlite3_bind_text(stmt, 2, key.UTF8String, -1, NULL);
255
- int result = sqlite3_step(stmt);
256
- if (result != SQLITE_DONE) {
257
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite update error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
258
- return NO;
259
- }
260
- return YES;
261
- }
262
-
263
- - (BOOL)_dbUpdateAccessTimeWithKeys:(NSArray *)keys {
264
- if (![self _dbCheck]) return NO;
265
- int t = (int)time(NULL);
266
- NSString *sql = [NSString stringWithFormat:@"update manifest set last_access_time = %d where key in (%@);", t, [self _dbJoinedKeys:keys]];
267
-
268
- sqlite3_stmt *stmt = NULL;
269
- int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
270
- if (result != SQLITE_OK) {
271
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
272
- return NO;
273
- }
274
-
275
- [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1];
276
- result = sqlite3_step(stmt);
277
- sqlite3_finalize(stmt);
278
- if (result != SQLITE_DONE) {
279
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite update error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
280
- return NO;
281
- }
282
- return YES;
283
- }
284
-
285
- - (BOOL)_dbDeleteItemWithKey:(NSString *)key {
286
- NSString *sql = @"delete from manifest where key = ?1;";
287
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
288
- if (!stmt) return NO;
289
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
290
-
291
- int result = sqlite3_step(stmt);
292
- if (result != SQLITE_DONE) {
293
- if (_errorLogsEnabled) NSLog(@"%s line:%d db delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
294
- return NO;
295
- }
296
- return YES;
297
- }
298
-
299
- - (BOOL)_dbDeleteItemWithKeys:(NSArray *)keys {
300
- if (![self _dbCheck]) return NO;
301
- NSString *sql = [NSString stringWithFormat:@"delete from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
302
- sqlite3_stmt *stmt = NULL;
303
- int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
304
- if (result != SQLITE_OK) {
305
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
306
- return NO;
307
- }
308
-
309
- [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1];
310
- result = sqlite3_step(stmt);
311
- sqlite3_finalize(stmt);
312
- if (result == SQLITE_ERROR) {
313
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
314
- return NO;
315
- }
316
- return YES;
317
- }
318
-
319
- - (BOOL)_dbDeleteItemsWithSizeLargerThan:(int)size {
320
- NSString *sql = @"delete from manifest where size > ?1;";
321
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
322
- if (!stmt) return NO;
323
- sqlite3_bind_int(stmt, 1, size);
324
- int result = sqlite3_step(stmt);
325
- if (result != SQLITE_DONE) {
326
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
327
- return NO;
328
- }
329
- return YES;
330
- }
331
-
332
- - (BOOL)_dbDeleteItemsWithTimeEarlierThan:(int)time {
333
- NSString *sql = @"delete from manifest where last_access_time < ?1;";
334
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
335
- if (!stmt) return NO;
336
- sqlite3_bind_int(stmt, 1, time);
337
- int result = sqlite3_step(stmt);
338
- if (result != SQLITE_DONE) {
339
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite delete error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
340
- return NO;
341
- }
342
- return YES;
343
- }
344
-
345
- - (YYKVStorageItem *)_dbGetItemFromStmt:(sqlite3_stmt *)stmt excludeInlineData:(BOOL)excludeInlineData {
346
- int i = 0;
347
- char *key = (char *)sqlite3_column_text(stmt, i++);
348
- char *filename = (char *)sqlite3_column_text(stmt, i++);
349
- int size = sqlite3_column_int(stmt, i++);
350
- const void *inline_data = excludeInlineData ? NULL : sqlite3_column_blob(stmt, i);
351
- int inline_data_bytes = excludeInlineData ? 0 : sqlite3_column_bytes(stmt, i++);
352
- int modification_time = sqlite3_column_int(stmt, i++);
353
- int last_access_time = sqlite3_column_int(stmt, i++);
354
- const void *extended_data = sqlite3_column_blob(stmt, i);
355
- int extended_data_bytes = sqlite3_column_bytes(stmt, i++);
356
-
357
- YYKVStorageItem *item = [YYKVStorageItem new];
358
- if (key) item.key = (NSString *)[NSString stringWithUTF8String:key];
359
- if (filename && *filename != 0) item.filename = [NSString stringWithUTF8String:filename];
360
- item.size = size;
361
- if (inline_data_bytes > 0 && inline_data) item.value = [NSData dataWithBytes:inline_data length:inline_data_bytes];
362
- item.modTime = modification_time;
363
- item.accessTime = last_access_time;
364
- if (extended_data_bytes > 0 && extended_data) item.extendedData = [NSData dataWithBytes:extended_data length:extended_data_bytes];
365
- return item;
366
- }
367
-
368
- - (YYKVStorageItem *)_dbGetItemWithKey:(NSString *)key excludeInlineData:(BOOL)excludeInlineData {
369
- NSString *sql = excludeInlineData ? @"select key, filename, size, modification_time, last_access_time, extended_data from manifest where key = ?1;" : @"select key, filename, size, inline_data, modification_time, last_access_time, extended_data from manifest where key = ?1;";
370
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
371
- if (!stmt) return nil;
372
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
373
-
374
- YYKVStorageItem *item = nil;
375
- int result = sqlite3_step(stmt);
376
- if (result == SQLITE_ROW) {
377
- item = [self _dbGetItemFromStmt:stmt excludeInlineData:excludeInlineData];
378
- } else {
379
- if (result != SQLITE_DONE) {
380
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
381
- }
382
- }
383
- return item;
384
- }
385
-
386
- - (NSMutableArray *)_dbGetItemWithKeys:(NSArray *)keys excludeInlineData:(BOOL)excludeInlineData {
387
- if (![self _dbCheck]) return nil;
388
- NSString *sql;
389
- if (excludeInlineData) {
390
- sql = [NSString stringWithFormat:@"select key, filename, size, modification_time, last_access_time, extended_data from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
391
- } else {
392
- sql = [NSString stringWithFormat:@"select key, filename, size, inline_data, modification_time, last_access_time, extended_data from manifest where key in (%@)", [self _dbJoinedKeys:keys]];
393
- }
394
-
395
- sqlite3_stmt *stmt = NULL;
396
- int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
397
- if (result != SQLITE_OK) {
398
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
399
- return nil;
400
- }
401
-
402
- [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1];
403
- NSMutableArray *items = [NSMutableArray new];
404
- do {
405
- result = sqlite3_step(stmt);
406
- if (result == SQLITE_ROW) {
407
- YYKVStorageItem *item = [self _dbGetItemFromStmt:stmt excludeInlineData:excludeInlineData];
408
- if (item) [items addObject:item];
409
- } else if (result == SQLITE_DONE) {
410
- break;
411
- } else {
412
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
413
- items = nil;
414
- break;
415
- }
416
- } while (1);
417
- sqlite3_finalize(stmt);
418
- return items;
419
- }
420
-
421
- - (NSData *)_dbGetValueWithKey:(NSString *)key {
422
- NSString *sql = @"select inline_data from manifest where key = ?1;";
423
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
424
- if (!stmt) return nil;
425
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
426
-
427
- int result = sqlite3_step(stmt);
428
- if (result == SQLITE_ROW) {
429
- const void *inline_data = sqlite3_column_blob(stmt, 0);
430
- int inline_data_bytes = sqlite3_column_bytes(stmt, 0);
431
- if (!inline_data || inline_data_bytes <= 0) return nil;
432
- return [NSData dataWithBytes:inline_data length:inline_data_bytes];
433
- } else {
434
- if (result != SQLITE_DONE) {
435
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
436
- }
437
- return nil;
438
- }
439
- }
440
-
441
- - (NSString *)_dbGetFilenameWithKey:(NSString *)key {
442
- NSString *sql = @"select filename from manifest where key = ?1;";
443
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
444
- if (!stmt) return nil;
445
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
446
- int result = sqlite3_step(stmt);
447
- if (result == SQLITE_ROW) {
448
- char *filename = (char *)sqlite3_column_text(stmt, 0);
449
- if (filename && *filename != 0) {
450
- return [NSString stringWithUTF8String:filename];
451
- }
452
- } else {
453
- if (result != SQLITE_DONE) {
454
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
455
- }
456
- }
457
- return nil;
458
- }
459
-
460
- - (NSMutableArray *)_dbGetFilenameWithKeys:(NSArray *)keys {
461
- if (![self _dbCheck]) return nil;
462
- NSString *sql = [NSString stringWithFormat:@"select filename from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
463
- sqlite3_stmt *stmt = NULL;
464
- int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
465
- if (result != SQLITE_OK) {
466
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
467
- return nil;
468
- }
469
-
470
- [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1];
471
- NSMutableArray *filenames = [NSMutableArray new];
472
- do {
473
- result = sqlite3_step(stmt);
474
- if (result == SQLITE_ROW) {
475
- char *filename = (char *)sqlite3_column_text(stmt, 0);
476
- if (filename && *filename != 0) {
477
- NSString *name = [NSString stringWithUTF8String:filename];
478
- if (name) [filenames addObject:name];
479
- }
480
- } else if (result == SQLITE_DONE) {
481
- break;
482
- } else {
483
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
484
- filenames = nil;
485
- break;
486
- }
487
- } while (1);
488
- sqlite3_finalize(stmt);
489
- return filenames;
490
- }
491
-
492
- - (NSMutableArray *)_dbGetFilenamesWithSizeLargerThan:(int)size {
493
- NSString *sql = @"select filename from manifest where size > ?1 and filename is not null;";
494
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
495
- if (!stmt) return nil;
496
- sqlite3_bind_int(stmt, 1, size);
497
-
498
- NSMutableArray *filenames = [NSMutableArray new];
499
- do {
500
- int result = sqlite3_step(stmt);
501
- if (result == SQLITE_ROW) {
502
- char *filename = (char *)sqlite3_column_text(stmt, 0);
503
- if (filename && *filename != 0) {
504
- NSString *name = [NSString stringWithUTF8String:filename];
505
- if (name) [filenames addObject:name];
506
- }
507
- } else if (result == SQLITE_DONE) {
508
- break;
509
- } else {
510
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
511
- filenames = nil;
512
- break;
513
- }
514
- } while (1);
515
- return filenames;
516
- }
517
-
518
- - (NSMutableArray *)_dbGetFilenamesWithTimeEarlierThan:(int)time {
519
- NSString *sql = @"select filename from manifest where last_access_time < ?1 and filename is not null;";
520
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
521
- if (!stmt) return nil;
522
- sqlite3_bind_int(stmt, 1, time);
523
-
524
- NSMutableArray *filenames = [NSMutableArray new];
525
- do {
526
- int result = sqlite3_step(stmt);
527
- if (result == SQLITE_ROW) {
528
- char *filename = (char *)sqlite3_column_text(stmt, 0);
529
- if (filename && *filename != 0) {
530
- NSString *name = [NSString stringWithUTF8String:filename];
531
- if (name) [filenames addObject:name];
532
- }
533
- } else if (result == SQLITE_DONE) {
534
- break;
535
- } else {
536
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
537
- filenames = nil;
538
- break;
539
- }
540
- } while (1);
541
- return filenames;
542
- }
543
-
544
- - (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeAscWithLimit:(int)count {
545
- NSString *sql = @"select key, filename, size from manifest order by last_access_time asc limit ?1;";
546
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
547
- if (!stmt) return nil;
548
- sqlite3_bind_int(stmt, 1, count);
549
-
550
- NSMutableArray *items = [NSMutableArray new];
551
- do {
552
- int result = sqlite3_step(stmt);
553
- if (result == SQLITE_ROW) {
554
- char *key = (char *)sqlite3_column_text(stmt, 0);
555
- char *filename = (char *)sqlite3_column_text(stmt, 1);
556
- int size = sqlite3_column_int(stmt, 2);
557
- NSString *keyStr = key ? [NSString stringWithUTF8String:key] : nil;
558
- if (keyStr) {
559
- YYKVStorageItem *item = [YYKVStorageItem new];
560
- item.key = key ? (NSString *)[NSString stringWithUTF8String:key] : nil;
561
- item.filename = filename ? [NSString stringWithUTF8String:filename] : nil;
562
- item.size = size;
563
- [items addObject:item];
564
- }
565
- } else if (result == SQLITE_DONE) {
566
- break;
567
- } else {
568
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
569
- items = nil;
570
- break;
571
- }
572
- } while (1);
573
- return items;
574
- }
575
-
576
- - (int)_dbGetItemCountWithKey:(NSString *)key {
577
- NSString *sql = @"select count(key) from manifest where key = ?1;";
578
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
579
- if (!stmt) return -1;
580
- sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
581
- int result = sqlite3_step(stmt);
582
- if (result != SQLITE_ROW) {
583
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
584
- return -1;
585
- }
586
- return sqlite3_column_int(stmt, 0);
587
- }
588
-
589
- - (int)_dbGetTotalItemSize {
590
- NSString *sql = @"select sum(size) from manifest;";
591
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
592
- if (!stmt) return -1;
593
- int result = sqlite3_step(stmt);
594
- if (result != SQLITE_ROW) {
595
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
596
- return -1;
597
- }
598
- return sqlite3_column_int(stmt, 0);
599
- }
600
-
601
- - (int)_dbGetTotalItemCount {
602
- NSString *sql = @"select count(*) from manifest;";
603
- sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
604
- if (!stmt) return -1;
605
- int result = sqlite3_step(stmt);
606
- if (result != SQLITE_ROW) {
607
- if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
608
- return -1;
609
- }
610
- return sqlite3_column_int(stmt, 0);
611
- }
612
-
613
-
614
- #pragma mark - file
615
-
616
- - (BOOL)_fileWriteWithName:(NSString *)filename data:(NSData *)data {
617
- NSString *path = [_dataPath stringByAppendingPathComponent:filename];
618
- return [data writeToFile:path atomically:NO];
619
- }
620
-
621
- - (NSData *)_fileReadWithName:(NSString *)filename {
622
- NSString *path = [_dataPath stringByAppendingPathComponent:filename];
623
- NSData *data = [NSData dataWithContentsOfFile:path];
624
- return data;
625
- }
626
-
627
- - (BOOL)_fileDeleteWithName:(NSString *)filename {
628
- NSString *path = [_dataPath stringByAppendingPathComponent:filename];
629
- return [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
630
- }
631
-
632
- - (BOOL)_fileMoveAllToTrash {
633
- CFUUIDRef uuidRef = CFUUIDCreate(NULL);
634
- CFStringRef uuid = CFUUIDCreateString(NULL, uuidRef);
635
- CFRelease(uuidRef);
636
- NSString *tmpPath = [_trashPath stringByAppendingPathComponent:(__bridge NSString *)(uuid)];
637
- BOOL suc = [[NSFileManager defaultManager] moveItemAtPath:_dataPath toPath:tmpPath error:nil];
638
- if (suc) {
639
- suc = [[NSFileManager defaultManager] createDirectoryAtPath:_dataPath withIntermediateDirectories:YES attributes:nil error:NULL];
640
- }
641
- CFRelease(uuid);
642
- return suc;
643
- }
644
-
645
- - (void)_fileEmptyTrashInBackground {
646
- NSString *trashPath = _trashPath;
647
- dispatch_queue_t queue = _trashQueue;
648
- dispatch_async(queue, ^{
649
- NSFileManager *manager = [NSFileManager new];
650
- NSArray *directoryContents = [manager contentsOfDirectoryAtPath:trashPath error:NULL];
651
- for (NSString *path in directoryContents) {
652
- NSString *fullPath = [trashPath stringByAppendingPathComponent:path];
653
- [manager removeItemAtPath:fullPath error:NULL];
654
- }
655
- });
656
- }
657
-
658
-
659
- #pragma mark - private
660
-
661
- /**
662
- Delete all files and empty in background.
663
- Make sure the db is closed.
664
- */
665
- - (void)_reset {
666
- [[NSFileManager defaultManager] removeItemAtPath:[_path stringByAppendingPathComponent:kDBFileName] error:nil];
667
- [[NSFileManager defaultManager] removeItemAtPath:[_path stringByAppendingPathComponent:kDBShmFileName] error:nil];
668
- [[NSFileManager defaultManager] removeItemAtPath:[_path stringByAppendingPathComponent:kDBWalFileName] error:nil];
669
- [self _fileMoveAllToTrash];
670
- [self _fileEmptyTrashInBackground];
671
- }
672
-
673
- #pragma mark - public
674
-
675
- - (instancetype)init {
676
- @throw [NSException exceptionWithName:@"YYKVStorage init error" reason:@"Please use the designated initializer and pass the 'path' and 'type'." userInfo:nil];
677
- }
678
-
679
- - (instancetype)initWithPath:(NSString *)path type:(YYKVStorageType)type {
680
- if (path.length == 0 || path.length > kPathLengthMax) {
681
- NSLog(@"YYKVStorage init error: invalid path: [%@].", path);
682
- return nil;
683
- }
684
- if (type > YYKVStorageTypeMixed) {
685
- NSLog(@"YYKVStorage init error: invalid type: %lu.", (unsigned long)type);
686
- return nil;
687
- }
688
-
689
- self = [super init];
690
- _path = path.copy;
691
- _type = type;
692
- _dataPath = [path stringByAppendingPathComponent:kDataDirectoryName];
693
- _trashPath = [path stringByAppendingPathComponent:kTrashDirectoryName];
694
- _trashQueue = dispatch_queue_create("com.ibireme.cache.disk.trash", DISPATCH_QUEUE_SERIAL);
695
- _dbPath = [path stringByAppendingPathComponent:kDBFileName];
696
- _errorLogsEnabled = YES;
697
- NSError *error = nil;
698
- if (![[NSFileManager defaultManager] createDirectoryAtPath:path
699
- withIntermediateDirectories:YES
700
- attributes:nil
701
- error:&error] ||
702
- ![[NSFileManager defaultManager] createDirectoryAtPath:[path stringByAppendingPathComponent:kDataDirectoryName]
703
- withIntermediateDirectories:YES
704
- attributes:nil
705
- error:&error] ||
706
- ![[NSFileManager defaultManager] createDirectoryAtPath:[path stringByAppendingPathComponent:kTrashDirectoryName]
707
- withIntermediateDirectories:YES
708
- attributes:nil
709
- error:&error]) {
710
- NSLog(@"YYKVStorage init error:%@", error);
711
- return nil;
712
- }
713
-
714
- if (![self _dbOpen] || ![self _dbInitialize]) {
715
- // db file may broken...
716
- [self _dbClose];
717
- [self _reset]; // rebuild
718
- if (![self _dbOpen] || ![self _dbInitialize]) {
719
- [self _dbClose];
720
- NSLog(@"YYKVStorage init error: fail to open sqlite db.");
721
- return nil;
722
- }
723
- }
724
- [self _fileEmptyTrashInBackground]; // empty the trash if failed at last time
725
- return self;
726
- }
727
-
728
- - (void)dealloc {
729
- UIBackgroundTaskIdentifier taskID = [_YYSharedApplication() beginBackgroundTaskWithExpirationHandler:^{}];
730
- [self _dbClose];
731
- if (taskID != UIBackgroundTaskInvalid) {
732
- [_YYSharedApplication() endBackgroundTask:taskID];
733
- }
734
- }
735
-
736
- - (BOOL)saveItem:(YYKVStorageItem *)item {
737
- return [self saveItemWithKey:item.key value:item.value filename:item.filename extendedData:item.extendedData];
738
- }
739
-
740
- - (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value {
741
- return [self saveItemWithKey:key value:value filename:nil extendedData:nil];
742
- }
743
-
744
- - (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value filename:(NSString *)filename extendedData:(NSData *)extendedData {
745
- if (key.length == 0 || value.length == 0) return NO;
746
- if (_type == YYKVStorageTypeFile && filename.length == 0) {
747
- return NO;
748
- }
749
-
750
- if (filename.length) {
751
- if (![self _fileWriteWithName:filename data:value]) {
752
- return NO;
753
- }
754
- if (![self _dbSaveWithKey:key value:value fileName:filename extendedData:extendedData]) {
755
- [self _fileDeleteWithName:filename];
756
- return NO;
757
- }
758
- return YES;
759
- } else {
760
- if (_type != YYKVStorageTypeSQLite) {
761
- NSString *fname = [self _dbGetFilenameWithKey:key];
762
- if (fname) {
763
- [self _fileDeleteWithName:fname];
764
- }
765
- }
766
- return [self _dbSaveWithKey:key value:value fileName:nil extendedData:extendedData];
767
- }
768
- }
769
-
770
- - (BOOL)removeItemForKey:(NSString *)key {
771
- if (key.length == 0) return NO;
772
- switch (_type) {
773
- case YYKVStorageTypeSQLite: {
774
- return [self _dbDeleteItemWithKey:key];
775
- }
776
- case YYKVStorageTypeFile:
777
- case YYKVStorageTypeMixed: {
778
- NSString *filename = [self _dbGetFilenameWithKey:key];
779
- if (filename) {
780
- [self _fileDeleteWithName:filename];
781
- }
782
- return [self _dbDeleteItemWithKey:key];
783
- }
784
- default: return NO;
785
- }
786
- }
787
-
788
- - (BOOL)removeItemForKeys:(NSArray *)keys {
789
- if (keys.count == 0) return NO;
790
- switch (_type) {
791
- case YYKVStorageTypeSQLite: {
792
- return [self _dbDeleteItemWithKeys:keys];
793
- }
794
- case YYKVStorageTypeFile:
795
- case YYKVStorageTypeMixed: {
796
- NSArray *filenames = [self _dbGetFilenameWithKeys:keys];
797
- for (NSString *filename in filenames) {
798
- [self _fileDeleteWithName:filename];
799
- }
800
- return [self _dbDeleteItemWithKeys:keys];
801
- }
802
- default: return NO;
803
- }
804
- }
805
-
806
- - (BOOL)removeItemsLargerThanSize:(int)size {
807
- if (size == INT_MAX) return YES;
808
- if (size <= 0) return [self removeAllItems];
809
-
810
- switch (_type) {
811
- case YYKVStorageTypeSQLite: {
812
- if ([self _dbDeleteItemsWithSizeLargerThan:size]) {
813
- [self _dbCheckpoint];
814
- return YES;
815
- }
816
- } break;
817
- case YYKVStorageTypeFile:
818
- case YYKVStorageTypeMixed: {
819
- NSArray *filenames = [self _dbGetFilenamesWithSizeLargerThan:size];
820
- for (NSString *name in filenames) {
821
- [self _fileDeleteWithName:name];
822
- }
823
- if ([self _dbDeleteItemsWithSizeLargerThan:size]) {
824
- [self _dbCheckpoint];
825
- return YES;
826
- }
827
- } break;
828
- }
829
- return NO;
830
- }
831
-
832
- - (BOOL)removeItemsEarlierThanTime:(int)time {
833
- if (time <= 0) return YES;
834
- if (time == INT_MAX) return [self removeAllItems];
835
-
836
- switch (_type) {
837
- case YYKVStorageTypeSQLite: {
838
- if ([self _dbDeleteItemsWithTimeEarlierThan:time]) {
839
- [self _dbCheckpoint];
840
- return YES;
841
- }
842
- } break;
843
- case YYKVStorageTypeFile:
844
- case YYKVStorageTypeMixed: {
845
- NSArray *filenames = [self _dbGetFilenamesWithTimeEarlierThan:time];
846
- for (NSString *name in filenames) {
847
- [self _fileDeleteWithName:name];
848
- }
849
- if ([self _dbDeleteItemsWithTimeEarlierThan:time]) {
850
- [self _dbCheckpoint];
851
- return YES;
852
- }
853
- } break;
854
- }
855
- return NO;
856
- }
857
-
858
- - (BOOL)removeItemsToFitSize:(int)maxSize {
859
- if (maxSize == INT_MAX) return YES;
860
- if (maxSize <= 0) return [self removeAllItems];
861
-
862
- int total = [self _dbGetTotalItemSize];
863
- if (total < 0) return NO;
864
- if (total <= maxSize) return YES;
865
-
866
- NSArray *items = nil;
867
- BOOL suc = NO;
868
- do {
869
- int perCount = 16;
870
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
871
- for (YYKVStorageItem *item in items) {
872
- if (total > maxSize) {
873
- if (item.filename) {
874
- [self _fileDeleteWithName:item.filename];
875
- }
876
- suc = [self _dbDeleteItemWithKey:item.key];
877
- total -= item.size;
878
- } else {
879
- break;
880
- }
881
- if (!suc) break;
882
- }
883
- } while (total > maxSize && items.count > 0 && suc);
884
- if (suc) [self _dbCheckpoint];
885
- return suc;
886
- }
887
-
888
- - (BOOL)removeItemsToFitCount:(int)maxCount {
889
- if (maxCount == INT_MAX) return YES;
890
- if (maxCount <= 0) return [self removeAllItems];
891
-
892
- int total = [self _dbGetTotalItemCount];
893
- if (total < 0) return NO;
894
- if (total <= maxCount) return YES;
895
-
896
- NSArray *items = nil;
897
- BOOL suc = NO;
898
- do {
899
- int perCount = 16;
900
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
901
- for (YYKVStorageItem *item in items) {
902
- if (total > maxCount) {
903
- if (item.filename) {
904
- [self _fileDeleteWithName:item.filename];
905
- }
906
- suc = [self _dbDeleteItemWithKey:item.key];
907
- total--;
908
- } else {
909
- break;
910
- }
911
- if (!suc) break;
912
- }
913
- } while (total > maxCount && items.count > 0 && suc);
914
- if (suc) [self _dbCheckpoint];
915
- return suc;
916
- }
917
-
918
- - (BOOL)removeAllItems {
919
- if (![self _dbClose]) return NO;
920
- [self _reset];
921
- if (![self _dbOpen]) return NO;
922
- if (![self _dbInitialize]) return NO;
923
- return YES;
924
- }
925
-
926
- - (void)removeAllItemsWithProgressBlock:(void(^)(int removedCount, int totalCount))progress
927
- endBlock:(void(^)(BOOL error))end {
928
-
929
- int total = [self _dbGetTotalItemCount];
930
- if (total <= 0) {
931
- if (end) end(total < 0);
932
- } else {
933
- int left = total;
934
- int perCount = 32;
935
- NSArray *items = nil;
936
- BOOL suc = NO;
937
- do {
938
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
939
- for (YYKVStorageItem *item in items) {
940
- if (left > 0) {
941
- if (item.filename) {
942
- [self _fileDeleteWithName:item.filename];
943
- }
944
- suc = [self _dbDeleteItemWithKey:item.key];
945
- left--;
946
- } else {
947
- break;
948
- }
949
- if (!suc) break;
950
- }
951
- if (progress) progress(total - left, total);
952
- } while (left > 0 && items.count > 0 && suc);
953
- if (suc) [self _dbCheckpoint];
954
- if (end) end(!suc);
955
- }
956
- }
957
-
958
- - (YYKVStorageItem *)getItemForKey:(NSString *)key {
959
- if (key.length == 0) return nil;
960
- YYKVStorageItem *item = [self _dbGetItemWithKey:key excludeInlineData:NO];
961
- if (item) {
962
- [self _dbUpdateAccessTimeWithKey:key];
963
- if (item.filename) {
964
- item.value = [self _fileReadWithName:item.filename];
965
- if (!item.value) {
966
- [self _dbDeleteItemWithKey:key];
967
- item = nil;
968
- }
969
- }
970
- }
971
- return item;
972
- }
973
-
974
- - (YYKVStorageItem *)getItemInfoForKey:(NSString *)key {
975
- if (key.length == 0) return nil;
976
- YYKVStorageItem *item = [self _dbGetItemWithKey:key excludeInlineData:YES];
977
- return item;
978
- }
979
-
980
- - (NSData *)getItemValueForKey:(NSString *)key {
981
- if (key.length == 0) return nil;
982
- NSData *value = nil;
983
- switch (_type) {
984
- case YYKVStorageTypeFile: {
985
- NSString *filename = [self _dbGetFilenameWithKey:key];
986
- if (filename) {
987
- value = [self _fileReadWithName:filename];
988
- if (!value) {
989
- [self _dbDeleteItemWithKey:key];
990
- value = nil;
991
- }
992
- }
993
- } break;
994
- case YYKVStorageTypeSQLite: {
995
- value = [self _dbGetValueWithKey:key];
996
- } break;
997
- case YYKVStorageTypeMixed: {
998
- NSString *filename = [self _dbGetFilenameWithKey:key];
999
- if (filename) {
1000
- value = [self _fileReadWithName:filename];
1001
- if (!value) {
1002
- [self _dbDeleteItemWithKey:key];
1003
- value = nil;
1004
- }
1005
- } else {
1006
- value = [self _dbGetValueWithKey:key];
1007
- }
1008
- } break;
1009
- }
1010
- if (value) {
1011
- [self _dbUpdateAccessTimeWithKey:key];
1012
- }
1013
- return value;
1014
- }
1015
-
1016
- - (NSArray *)getItemForKeys:(NSArray *)keys {
1017
- if (keys.count == 0) return nil;
1018
- NSMutableArray *items = [self _dbGetItemWithKeys:keys excludeInlineData:NO];
1019
- if (_type != YYKVStorageTypeSQLite) {
1020
- for (NSInteger i = 0, max = items.count; i < max; i++) {
1021
- YYKVStorageItem *item = items[i];
1022
- if (item.filename) {
1023
- item.value = [self _fileReadWithName:item.filename];
1024
- if (!item.value) {
1025
- if (item.key) [self _dbDeleteItemWithKey:item.key];
1026
- [items removeObjectAtIndex:i];
1027
- i--;
1028
- max--;
1029
- }
1030
- }
1031
- }
1032
- }
1033
- if (items.count > 0) {
1034
- [self _dbUpdateAccessTimeWithKeys:keys];
1035
- }
1036
- return items.count ? items : nil;
1037
- }
1038
-
1039
- - (NSArray *)getItemInfoForKeys:(NSArray *)keys {
1040
- if (keys.count == 0) return nil;
1041
- return [self _dbGetItemWithKeys:keys excludeInlineData:YES];
1042
- }
1043
-
1044
- - (NSDictionary *)getItemValueForKeys:(NSArray *)keys {
1045
- NSMutableArray *items = (NSMutableArray *)[self getItemForKeys:keys];
1046
- NSMutableDictionary *kv = [NSMutableDictionary new];
1047
- for (YYKVStorageItem *item in items) {
1048
- if (item.key && item.value) {
1049
- [kv setObject:item.value forKey:item.key];
1050
- }
1051
- }
1052
- return kv.count ? kv : nil;
1053
- }
1054
-
1055
- - (BOOL)itemExistsForKey:(NSString *)key {
1056
- if (key.length == 0) return NO;
1057
- return [self _dbGetItemCountWithKey:key] > 0;
1058
- }
1059
-
1060
- - (int)getItemsCount {
1061
- return [self _dbGetTotalItemCount];
1062
- }
1063
-
1064
- - (int)getItemsSize {
1065
- return [self _dbGetTotalItemSize];
1066
- }
1067
-
1068
- @end