YYDiskCache源码解析

YYDiskCacheYYCache组件中负责磁盘缓存的。

涉及知识点:

  • 磁盘缓存策略的分流优化
  • KVStore非关系型数据存储
  • 线程同步锁(信号量)

由于YYDiskCache是对YYKVStorage的封装调用

YYKVStorage

3种存储方式

1
2
3
4
5
6
7
8
typedef NS_ENUM(NSUInteger, YYKVStorageType) {
/// 文件形式存储
YYKVStorageTypeFile = 0,
/// sqlite 的 blob type.
YYKVStorageTypeSQLite = 1,
/// 根据情况选择文件还是SQLite
YYKVStorageTypeMixed = 2,
};

本地文件路径

1
2
3
4
5
6
7
8
9
/path/
/manifest.sqlite
/manifest.sqlite-shm
/manifest.sqlite-wal
/data/
/e10adc3949ba59abbe56e057f20f883e
/e10adc3949ba59abbe56e057f20f883e
/trash/
/unused_file_or_folder

YYKVStorage会根据存储方式进行数据的增删改查;

YYKVStorage 不是线程安全的

数据库

初始化

1
2
3
4
5
6
7
8
9
10
11
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);

日志模式采用wal方式;sqlite3.7版本之后支持;

检查点

1
2
3
4
5
// 在合适的时机,将 `sqlite-wal` 文件合并到 `sqlite` 文件。因为`sqlite-wal`文件过大会影响性能
- (void)_dbCheckpoint {
if (![self _dbCheck]) return;
sqlite3_wal_checkpoint(_db, NULL);
}

YYKVStorageItem

数据流context

1
2
3
4
5
6
7
8
9
@interface YYKVStorageItem : NSObject
@property (nonatomic, strong) NSString *key; ///< key
@property (nonatomic, strong) NSData *value; ///< value
@property (nullable, nonatomic, strong) NSString *filename; ///< filename (nil if inline)
@property (nonatomic) int size; ///< value's size in bytes
@property (nonatomic) int modTime; ///< modification unix timestamp
@property (nonatomic) int accessTime; ///< last access unix timestamp
@property (nullable, nonatomic, strong) NSData *extendedData; ///< extended data (nil if no extended data)
@end

YYDiskCache

线程同步

1
2
#define Lock() dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER)
#define Unlock() dispatch_semaphore_signal(self->_lock)

读写的时候都用到了该锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)setObject:(id<NSCoding>)object forKey:(NSString *)key
{
...
Lock();
[_kv saveItemWithKey:key value:value filename:filename extendedData:extendedData];
Unlock();
}

- (id<NSCoding>)objectForKey:(NSString *)key {
Lock();
YYKVStorageItem *item = [_kv getItemForKey:key];
Unlock();
...
}

自动清理

YYDiskCache也使用了LRU的算法,定时清理

成长

  • 磁盘缓存的解决方案
  • 信号量实现线程锁
  • 数据库wal的存储方式
  • 封装同步执行和异步执行的思路