整体思路

从作者的《YYCache 设计思路》一文中可以看出,作者在设计YYDiskCache之前做了充分的测试:iPhone 6 64G 下,SQLite 写入性能比直接写文件要高,但读取性能取决于数据大小:当单条数据小于 20K 时,数据越小 SQLite 读取性能越高;单条数据大于 20K 时,直接写为文件速度会更快一些。

YYDiskCache的磁盘缓存结合使用了文件储存和数据库储存。

个人理解:在进行磁盘缓存的时候,会判断要储存数据的大小,如果数据小于20K,则直接存入数据库(数据储存到inline_data字段,此时filename为空)。如果数据大于20K,先把数据以文件形式进行存储,然后再在数据库中储存对应的文件名(此时inline_data为NULL,filename为文件地址),具体的可以结合下文中提到的磁盘缓存的文件结构来看。

磁盘缓存的核心类是YYKVStorage,他主要封装了文件储存操作和SQLite数据库的操作。YYDiskCache是对YYKVStorage的封装,抛出的API和内存缓存相似,都有数据读写和修剪内存。

磁盘缓存的文件结构
/*File:/path//manifest.sqlite/manifest.sqlite-shm/manifest.sqlite-wal/data//e10adc3949ba59abbe56e057f20f883e/e10adc3949ba59abbe56e057f20f883e/trash//unused_file_or_folderSQL: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);*/

这个结构我们不需要多说什么,只提一个小点,作者在path路径下面设计了一个/data/和一个/trash/。删除文件是一个比较耗时的操作,在删除文件的时候,先进行文件的移动,然后在一个子线程中处理要删掉的文件,提高了整体的效率。

实现 LRU

磁盘缓存对缓存淘汰算法的实现就比较简单了,因为每次存储都有对应的数据库记录,而且表中设计了last_access_time这个字段,我们可以直接使用数据库的排序语句就可以找到最不常用的文件了。

代码分析

1.

- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql {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);if (result != SQLITE_OK) {if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));return NULL;}CFDictionarySetValue(_dbStmtCache, (__bridge const void *)(sql), stmt);} else {sqlite3_reset(stmt);}return stmt;
}

这个方法是提前生成了sql语句的句柄,可以理解成提前把sql语句编译成字节码留给后面的执行函数(当前不执行)。同时,作者使用
_dbStmtCache对语句进行缓存,下次使用时可以更快度的加载出来。

2.

- (BOOL)_dbClose {if (!_db) return YES;int  result = 0;BOOL retry = NO;BOOL stmtFinalized = NO;if (_dbStmtCache) CFRelease(_dbStmtCache);_dbStmtCache = NULL;do {retry = NO;result = sqlite3_close(_db);// 状态为busy或者lockif (result == SQLITE_BUSY || result == SQLITE_LOCKED) {if (!stmtFinalized) {stmtFinalized = YES;sqlite3_stmt *stmt;//sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);//表示从数据库pDb中对应的pStmt语句开始一个个往下找出相应prepared语句,如果pStmt为nil,那么就从pDb的第一个prepared语句开始。while ((stmt = sqlite3_next_stmt(_db, nil)) != 0) {//释放数据库中的prepared语句资源sqlite3_finalize(stmt);retry = YES;}}} else if (result != SQLITE_OK) {if (_errorLogsEnabled) {NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);}}} while (retry);_db = NULL;return YES;
}

这个是关闭数据库的方法,_dbStmtCache中缓存了我们使用的句柄,所以首先要释放掉了_dbStmtCache

在真正关闭数据库的代码中使用了do-while循环,因为一次访问数据库并不一定成功,数据库可能是busy或者lock的状态,所以要使用一个循环来多次访问。

如果为能关闭数据库,作者使用了sqlite3_next_stmt一个个的找出prepared语句,并使用sqlite3_finalize释放了prepared资源(防止内存泄露)。

其他的就没什么好说的了,主要就是一些sql语句的用法,这些大家看一下,碰到陌生的api谷歌一下就有了 ~ 具体的文件的操作,比较常用,看起来就容易很多。

YYCache 源码学习(二):YYDiskCache相关推荐

  1. YYCache 源码学习(一):YYMemoryCache

    其实最近是在重新熟练Swift的使用,我想出了一个比较实用的方法,那就是一边看OC的项目,看懂之后用Swift实现一遍.这样既学习了优秀的源码又练习了Swift,一举两得. 之前看过几篇文章是剖析YY ...

  2. Golang源码学习(二)----Go源码学习基础

    ### 本文源码版本为 GO 1.17.8 Windows/amd64: ### 可能参与对比的版本:GO 1.16.2 Linux/amd64一.Golang的编译器究竟是如何工作的? (学习源码有 ...

  3. SocketServer源码学习(二)

    SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler 在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过 ...

  4. 使用base标签后图片无法加载_Spring 源码学习(二)-默认标签解析

    `Spring` 解析默认标签~ 从上一篇笔记可以看出,在容器注册 bean 信息的时候,做了很多解析操作,而 xml 文件中包含了很多标签.属性,例如 bean . import 标签, meta ...

  5. ROS源码学习 二、线程池

    2021SC@SDUSC 目录 1.写在前面 2.ROS线程池概述 3.ROS线程池模型 4.ROS线程池源码详解 5.总结 1.写在前面 ROS作为一个操作系统,其职责是协调具有不同功能的node之 ...

  6. Box2d源码学习二内存管理之SOA的实现

    本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8258166 SOA,全称small object al ...

  7. java集合类程序代码_java集合类源码学习二

    我们查看Collection接口的hierarchy时候,可以看到AbstractCollection这样一个抽象类,它实现了Collection接口的部分方法,Collection集合系列的各个集合 ...

  8. Thrift源码学习二——Server层

    Thrift 提供了如图五种模式:TSimpleServer.TNonblockingServer.THsHaServer.TThreadPoolServer.TThreadSelectorServe ...

  9. erlang底层c定时器设计-Erlang源码学习二

    Erlang底层的定时器实现位于源码的erts/emulator/beam/time.c文件,用时间轮的方式动态添加和删除定时器,结构体名为typedef struct ErtsTimerWheel_ ...

  10. yara 源码学习(二) 规则编译部分

    yara规则的详细信息请参考: https://yara.readthedocs.io/en/stable/writingrules.html 根据官方文档,yara规则长这个样子: [1]:yara ...

最新文章

  1. RecyclerView滑动到指定位置,并置顶
  2. 一种Android闪屏页实现方法(偏门别类)
  3. java label覆盖_java – 将JLabel置于JLabel之上,其中包含图像
  4. 【BootStrap】初步教程
  5. cstring越界_CString和char*的转换
  6. DockerFile构建
  7. 无论如何都是为了测试傻瓜搜索引擎
  8. 编程猫海龟编辑器python_编程猫海龟编辑器
  9. Python+Opencv简易车牌识别(二):形态学运算,HSV颜色空间筛选与图像分割
  10. 产品需求文档写作方法(一)写前准备+梳理需求
  11. 记录平台调用支付中心接口
  12. java war 打包、解压命令
  13. AngularJS - uib-datepicker-popup - 日期控件
  14. 一个案例,看懂用户画像如何做出效益
  15. 蓝桥杯最后一天复习?各大算法四步法教你轻松秒杀各种题型
  16. MFRC522应用详解
  17. OCR识别之LEADTOOLS介绍
  18. 利用随机森林进行特征重要性排序
  19. 什么是MVC和MVVC,以及它们的区别
  20. 解决Origin导出图片失真问题

热门文章

  1. JavaOne美国之行–走势篇
  2. 取消 AndroidStudio 启动时自动打开上次关闭的项目
  3. Android UI之ImageView
  4. android 将byte[]保存到手机
  5. Service生命周期
  6. JVM学习笔记之-StringTable String的基本特性,内存分配,基本操作,拼接操作,intern()的使用,垃圾回收 ,G1中的String去重操作
  7. win10安装tensorflow (cpu版)
  8. NOIP 2017 时间复杂度 (模拟)
  9. 近期打算及毕业前要补完的题
  10. java servlet上传centos服务器