OkHttp源码分析(四)DiskLruCache
来源:互联网 发布:微信mac版 dmg 编辑:程序博客网 时间:2024/06/05 22:36
前一章讲到OKHTTP使用的缓存是DiskLruCache,DispLruCache是以LinkedHashMap为底层实现的磁盘缓存,但是具体是如何缓存的我还是不是很理解,作为程序员,不理解和咸鱼有什么分别。为了不做咸鱼,我们还是看一下源码吧!
public final class DiskLruCache implements Closeable, Flushable { final FileSystem fileSystem; final File directory; private final File journalFile; //DiskLruCache内部日志文件,对cache的每一次读写都对应一条日志记录,DiskLruCache通过分析日志分析和创建cache private final File journalFileTmp; private final File journalFileBackup; private final int appVersion; private long maxSize; final int valueCount; private long size = 0; BufferedSink journalWriter; final LinkedHashMap<String, Entry> lruEntries = new LinkedHashMap<>(0, 0.75f, true); // Must be read and written when synchronized on 'this'. boolean initialized; boolean closed; boolean mostRecentTrimFailed; boolean mostRecentRebuildFailed; /** * To differentiate between old and current snapshots, each entry is given a sequence number each * time an edit is committed. A snapshot is stale if its sequence number is not equal to its * entry's sequence number. */ private long nextSequenceNumber = 0; /** Used to run 'cleanupRunnable' for journal rebuilds. */ private final Executor executor; private final Runnable cleanupRunnable = new Runnable() { public void run() { ...... } }; ... }
LinkedHashMap中的Entry对象,一个Entry对象对应一条cache记录。
一个Entry主要由以下几部分构成:
key:每个cache都有一个key作为其标识符。当前cache的key为其对应URL的MD5字符串
cleanFiles/dirtyFiles:每一个Entry对应多个文件,其对应的文件数由DiskLruCache.valueCount指定。当前在OkHttp中valueCount为2。即每个cache对应2个cleanFiles,2个dirtyFiles。其中第一个cleanFiles/dirtyFiles记录cache的meta数据(如URL,创建时间,SSL握手记录等等),第二个文件记录cache的真正内容。cleanFiles记录处于稳定状态的cache结果,dirtyFiles记录处于创建或更新状态的cache
currentEditor:entry编辑器,对entry的所有操作都是通过其编辑器完成。编辑器内部添加了同步锁。
同时Entry中还加入了清理线程,用来重建精简日志,当冗余日志超过日志文件本身的一般且总条数超过2000时执行
private final class Entry { final String key; /** Lengths of this entry's files. */ final long[] lengths; final File[] cleanFiles; final File[] dirtyFiles; /** True if this entry has ever been published. */ boolean readable; /** The ongoing edit or null if this entry is not being edited. */ Editor currentEditor; /** The sequence number of the most recently committed edit to this entry. */ long sequenceNumber; Entry(String key) { this.key = key; lengths = new long[valueCount]; cleanFiles = new File[valueCount]; dirtyFiles = new File[valueCount]; // The names are repetitive so re-use the same builder to avoid allocations. StringBuilder fileBuilder = new StringBuilder(key).append('.'); int truncateTo = fileBuilder.length(); for (int i = 0; i < valueCount; i++) { fileBuilder.append(i); cleanFiles[i] = new File(directory, fileBuilder.toString()); fileBuilder.append(".tmp"); dirtyFiles[i] = new File(directory, fileBuilder.toString()); fileBuilder.setLength(truncateTo); } }
SnapShot cache快照,记录了特定cache在某一个特定时刻的内容。每次向DiskLruCache请求时返回的都是目标cache的一个快照,相关逻辑在DiskLruCache.get中:
public synchronized Snapshot get(String key) throws IOException { initialize(); checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (entry == null || !entry.readable) return null; Snapshot snapshot = entry.snapshot(); if (snapshot == null) return null; redundantOpCount++; //日志记录 journalWriter.writeUtf8(READ).writeByte(' ').writeUtf8(key).writeByte('\n'); if (journalRebuildRequired()) { executor.execute(cleanupRunnable); } return snapshot; }
总结:
DiskLruCache主要有以下几个特点:
- 通过LinkedHashMap实现LRU替换
- 通过本地维护Cache操作日志保证Cache原子性与可用性,同时为防止日志过分膨胀定时执行日志精简
- 每一个Cache项对应两个状态副本:DIRTY,CLEAN。CLEAN表示当前可用状态Cache,外部访问到的cache快照均为CLEAN状态;DIRTY为更新态Cache。由于更新和创建都只操作DIRTY状态副本,实现了Cache的读写分离
- 每一个Cache项有四个文件,两个状态(DIRTY,CLEAN),每个状态对应两个文件:一个文件存储Cache meta数据,一个文件存储Cache内容数据
- DiskLruCache写cache时根据url的md5值找到Editor(如果没有则创建Editor),根据Editor就得到文件输出流,读cache时同样根据url的md5值找到snapshot对象,用snapshot对象得到文件输入流。
- OkHttp源码分析(四)DiskLruCache
- OkHttp 3.7源码分析(四)——缓存策略
- OkHttp 3.7源码分析(四)——缓存策略
- Android缓存源码分析(DiskLruCache,LruCache)
- DiskLruCache源码分析
- OkHttp3源码分析[DiskLruCache]
- Android DiskLruCache源码分析
- OKHttp源码分析(一)
- OkHttp源码分析(一)
- Okhttp 源码分析(1)----流程分析
- Okhttp源码简单分析(完善ing)
- OKHTTP源码分析(一)异步方法
- OKHttp源码分析(三)缓存
- Okhttp源码分析(五)连接池
- okhttp源码分析(二)-RetryAndFollowUpInterceptor过滤器
- OkHttp源码分析
- OkHttp源码分析
- OkHttp源码分析
- windows 10 python 2.7和python3.6共存解决方法和pip安装
- python matplotlib库
- hdu 5867 Water problem
- Android 中 byte类型数据大于0x7F时的比较
- invalid header field
- OkHttp源码分析(四)DiskLruCache
- 智能一代云平台(三十八):单元测试推动开发,如何避免服务之间依赖拖了工期
- 关于XES格式对并发事件的表达
- linux日志转储及脚本操作
- Animation动画使用注意点
- 第八届福建省大学生程序设计竞赛-重现赛 A Frog
- Java编程思想之对象导论
- Qt 模拟鼠标点击
- 《数据结构》C++代码 堆(优先队列)