日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

YYCache 源码学习(二):YYDiskCache

發布時間:2024/4/14 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 YYCache 源码学习(二):YYDiskCache 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
整體思路

從作者的《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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。