Giter VIP home page Giter VIP logo

yycache's People

Contributors

everettjf avatar gainell avatar ibireme avatar sablib avatar yimingtang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yycache's Issues

cost怎么算的 没看出来。

BenchMark里Value都是NSData:
NSData *value = [NSData dataWithBytes:&i length:sizeof(int)];

然后使用[yy setObject:values[i] forKey:keys[i]];,在setObject:forKey:里:

- (void)setObject:(id)object forKey:(id)key {
    [self setObject:object forKey:key withCost:0];
}

之后就没看见对cost的操作了。都是node直接复制node->_cost = cost

所以不太清楚cost累加的。

我自己写的Cache里,是对CFMutableDictionaryRef转成NSMutableDictionary然后KeyedArchive得到NSData然后算data.length来判断size。

Example of use

Can you please provide an example for how to use YYCache ?

There is a typo in YYMemoryCache.h

Your work is so fantastic.

Line 21:It use LRU (least-recently-used) to remove objects; NSCache's eviction method is non-deterministic.

It should be It uses balabala.
:)

问题请教:

查看diskCache的相关代码:发现存取都要根据一个key来进行,假如我需要查询所有数据,该怎么做呢?

YYKVStorage _dbOpen may case crash when db can't open

你好,感谢你分享的YYCache项目,我们在项目中有使用,在使用过程中我们发现一个问题:
_dbOpen函数在某些情况下由于打开sqlite数据库失败,但是内部状态维护有点问题,具体是场景是:图片缓存被多次清理,在某次清理时打开sqlite数据库返回SQLITE_CANTOPEN,_dbOpen函数返回了NO,但是内部状态,db,_invalidated等状态都标示为打开成功状态,在下次使用图片缓存时由于_dbStmtCache被置为NULL,导致crash。
这里存在的问题还和sqlite的API有关系,int result = sqlite3_open(_dbPath.UTF8String, &_db);在返回失败是,db被赋值了

同步释放这里有点疑惑

链表的单个节点和所有节点释放时,用boolean标明是否同步释放,如果NO应该是dispatch_sync(...)么?
源代码:

if (_lru->_releaseAsynchronously) {
            dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
            dispatch_async(queue, ^{
                [node class]; //hold and release in queue
            });
        } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
            dispatch_async(dispatch_get_main_queue(), ^{    <--------这里,不是应该用dispatch_sync?为啥咧~?
                [node class]; //hold and release in queue
            });
        }

缓存时效的问题

有没有办法设置一些受保护的缓存文件,
后台清除过期文件的的时候,这些文件就算过期了(ageLimit),也避免被清除
因为 现在缓存的清除 完全是自动的

separate YYKVStorage to another project

I'm looking for key value store solution on iOS. Currently I'm using YTKKeyValueStore, which is not maintained for a year and contains some bugs. I'm hoping YYKVStorage can be separated into another independant project, so that it can be used for general key-value store usage.

YYMemoryCache中removeObjectForKey:方法Bug

我看到此方法的实现里这样调用:

[_lru removeNode:node];
_YYLinkedMapNode *node = [_lru removeTailNode];

请问除了将传入的node删除后,为何需要再删除一次尾结点?谢谢!

YYMemoryCache sync set method bug

YY 大神你好,最近我也在完善我自己写的一个 SwiftCache,在对比测试各个 cache 库时,发现了一个问题,不知是有意为之增加同步效率,还是疏漏。

- (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
...
    if (_lru->_totalCost > _costLimit) {
        dispatch_async(_queue, ^{
            [self trimToCost:_costLimit];
        });
    }
...
}

具体问题在 memoryCache 的同步写入的操作(上述代码),同步写入完成之后,有一个淘汰的过程,这时在淘汰 cost 时采用的是异步主线程淘汰,潜在问题在于如果紧接着做同步的读 cache,可能会出现异步主线程的 cost 淘汰还没有执行的情况。

我试图去更改您的代码,想要 PR,如下:

- (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
   ...
    pthread_mutex_unlock(&_lock); // 这里解锁,因为 trimToCost 中有锁

    if (_lru->_totalCost > _costLimit) {
       // 去掉异步 trim
        [self trimToCost:_costLimit];
    }

    pthread_mutex_lock(&_lock); // 这里再次加锁
    ...
}

但发现 if 中的 _lru _totalCost _costLimit 又变成了非线程安全,所以可能需要改的地方比较多,希望您看下是是否需要更正。
不胜感激。

YYCache如何缓存一个模型

比如我写了个Model,我想用YYCache来缓存,但是提示警告
[TestModel encodeWithCoder:]: unrecognized selector sent to instance 0x15e4ac6c0
2016-03-21 16:47:43.069 WisdomCommunity[2247:640281] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
求指导方法

看源码的一个疑惑

  • (void)_trimToCost:(NSUInteger)costLimit {
    BOOL finish = NO;
    OSSpinLockLock(&_lock);
    if (costLimit == 0) {
    [_lru removeAll];
    finish = YES;
    } else if (_lru->_totalCost <= costLimit) {
    finish = YES;
    }
    OSSpinLockUnlock(&_lock);
    if (finish) return;

    NSMutableArray *holder = [NSMutableArray new];
    while (!finish) {
    if (OSSpinLockTry(&_lock)) {
    if (_lru->_totalCost > costLimit) {
    _YYLinkedMapNode *node = [_lru removeTailNode];
    if (node) [holder addObject:node];
    } else {
    finish = YES;
    }
    OSSpinLockUnlock(&_lock);
    } else {
    usleep(10 * 1000); //10 ms
    }
    }
    if (holder.count) {
    dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
    dispatch_async(queue, ^{
    [holder count]; // release in queue
    });
    }
    }

这段代码,最后释放数组的时候,调用数组的count方法,怎么会就释放了数组了呢?

求解。。

清理磁盘存储的时候,经常会崩溃在这一句。

sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql));

具体在下面这个函数中,报错是Thread34:EXC_BAD_ACCESS

- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql { if (![self _dbIsReady]) 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; }

内存缓存和磁盘缓存锁的使用

为什么内存缓存中使用pthread_mutex_t,进行加锁而磁盘缓存中使用dispatch_semaphore_t信号量进行加锁呢?希望能解答疑惑,拜托拜托

有个语法错误

-(NSMutableArray *)_dbGetItemWithKeys:(NSArray *)keys excludeInlineData:(BOOL)excludeInlineData 方法中SQL语句

where key in (%@);

in 中的参数如果是字符串,需要单引号,否则stmt会失败。

报错在这个方法中,不知道什么原因,使用 diskcache,遵守了协议,重写了归档方法

  • (int)_dbGetItemCountWithKey:(NSString *)key {
    NSString *sql = @"select count(key) from manifest where key = ?1;";
    sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
    if (!stmt) return -1;
    sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
    int result = sqlite3_step(stmt);
    if (result != SQLITE_ROW) {
    if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", FUNCTION, LINE, result, sqlite3_errmsg(_db));
    return -1;
    }
    return sqlite3_column_int(stmt, 0);
    }

锁的选择

MemoryCache中用pthread_mutex_lock锁,
DiskCache中对数据库操作部分用的GCD的信号量。

请问为什么这样选择的?有什么原则吗?

在个人中心里面清空了所有的Cache,但在进入收藏的时候,个人资料缓存还是没有清空,请问有没可以立即同步的选项

在个人中心里面清空了所有的Cache,但在进入收藏的时候,个人资料缓存还是没有清空,请问有没可以立即同步的选项?
我用YYCache做了登录之后的个人资料,cookie的保存. 然后,我在每次请求数据的时候,将保存的数据加入到请求头(cookie)里面,用来验证用户.
但我在别的页面清楚所有的Cache之后(RemoveAll),再请求数据发现,并没有清除掉, 用户信息还是保留着.
所以,我想问一下有没有立即执行的选项.

关于在 removeObjectForKey 释放 node 的问题

if (node) {
    [_lru removeNode:node];
    _YYLinkedMapNode *node = [_lru removeTailNode];
    if (_lru->_releaseAsynchronously) {
        dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
        dispatch_async(queue, ^{
            [node class]; //hold and release in queue
        });
    } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [node class]; //hold and release in queue
        });
    }
}

我最近在学习 iOS 的内存管理知识,这个地方我有一些不解,想请教一下您。
_YYLinkedMapNode *node = [_lru removeTailNode]; 这里的 node 是被注册到了 autoreleasepool 吧?

在接下来的 dispatch_async GCD 操作是为了什么呢?
不是会有 ARC 来帮助自动 release 没有用的内存么?

还是说想根据自定义的需求,指定在某个线程下完成释放?但是在 autoreleasepool 中的释放并不是立即进行的么?

如何实现一个页面一张表,以及关联查询功能

如题,因为如果不同页面数据都放在一张表的话,key值有可能会有重复,所以想每个页面建一张表用于区分;同时,请问题如果放在了不同表中,如果进行访问;或者能不能以多个键值作为联合key检索数据

mutex应该被destroy

在你的应用中,使用了mutex来做为线程锁。在init方法中,你创建了一个mutex,但是没有任何地方释放此mutex,你应该在dealloc或别的适当的地方使用pthread_mutex_destroy(&_lock)来释放这个创建的mutex。

能直接获取缓存 file 的 path 吗?

在我的业务中,需要知道 file 的 path,但好似 Storage 里面才有 path, YYCache 不能获取

另外,我想问一下,如何解决 imageIO_PNG_data 不断增大的问题,png 图片设置后,无法在内存中释放

问个问题,当工程中有time.h文件使用YYCache报错怎么处理

使用第三方的ffmpeg中有time.h文件,这样会和YYCache中使用的time()函数冲突,导致这样的错误
YYKVStorage.m:201:26: Implicit declaration of function 'time' is invalid in C99
Declaration of 'time' must be imported from module 'Darwin.C.time' before it is required
,我查看工程中ffmpeg中这个time.h并没有使用,暂时处理方式是删除这个time.h的引用。

问一下,有没有更好的处理方式 ?毕竟我的处理方式并不是一个真正解决问题的方法!

[YYKVStorage] initWithPath should return error when directory already exists

The file creation part from YYKVStorage.m:

    NSError *error = nil;
    if (![[NSFileManager defaultManager] createDirectoryAtPath:path
                                   withIntermediateDirectories:YES
                                                    attributes:nil
                                                         error:&error] ||
        ![[NSFileManager defaultManager] createDirectoryAtPath:[path stringByAppendingPathComponent:kDataDirectoryName]
                                   withIntermediateDirectories:YES
                                                    attributes:nil
                                                         error:&error] ||
        ![[NSFileManager defaultManager] createDirectoryAtPath:[path stringByAppendingPathComponent:kTrashDirectoryName]
                                   withIntermediateDirectories:YES
                                                    attributes:nil
                                                         error:&error]) {
        NSLog(@"YYKVStorage init error:%@", error);
        return nil;
    }

This will not result in an error if directory already exists.

今天看了 下 “YYKVStorage”类,请教几个问题。

  1. "- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql "
    执行这个函数时候,拿到 “sqlite3_stmt” stmt 时候,为什么要执行 sqlite3_reset(stmt)?
  2. 在执行完 “ sqlite3_step(stmt)” 时, 为什么有时候不执行 “sqlite3_finalize(stmt)”?
    比如执行 “- (BOOL)_dbUpdateAccessTimeWithKey:(NSString *)key”
    我看了部分文档,介绍说要执行的。
  3. 为什么我们执行“remove...”操作后,要执行 “sqlite3_wal_checkpoint(_db, NULL)” 。
    我们每次删除的是“-wal”文件的内容吗,删除完 要同步下数据库吗?

关于DiskCache跟MemoryCache的问题

YY大神,我在看源码的时候发现在YYDiskCache类中有大量的操作是有withBlock的,而YYMemoryCache中同样的几个方法是没有的,这是为什么呀?

YYDiskCache在移除数据时是否与LRU策略相反了?

你好,YYKVStorage.m 中获取最近访问数据时,是否应该使用 asc 而不是 desc。最近的时间值更大。使用 desc 导致每次移除时把最近使用的元素优先移除掉了。

- (BOOL)removeItemsToFitCount:(int)maxCount {
        items = [self _dbGetItemSizeInfoOrderByTimeDescWithLimit:perCount];
- (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeDescWithLimit:(int)count {
    NSString *sql = @"select key, filename, size from manifest order by last_access_time desc limit ?1;";
    sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];

测试代码如下:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *docDir = [(NSArray*)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject];
        NSString *testDir = [docDir stringByAppendingPathComponent:@"testDir"];
        NSLog(@"testDir = %@", testDir);

        YYDiskCache *diskCache = [[YYDiskCache alloc]initWithPath:testDir inlineThreshold:0];
        diskCache.customFileNameBlock = ^(NSString *key){
            return [key stringByAppendingPathExtension:@"txt"];
        };

        [diskCache setObject:@"hello" forKey:@"1"];
        [diskCache setObject:@"world" forKey:@"2"];

        NSLog(@"total count : %@",@([diskCache totalCount]));
//        NSLog(@"key 1 = %@", [diskCache objectForKey:@"1"]);
//        usleep(1000000);
//        NSLog(@"key 2 = %@", [diskCache objectForKey:@"2"]);

        NSLog(@"key 2 = %@", [diskCache objectForKey:@"2"]);
        usleep(1000000);
        NSLog(@"key 1 = %@", [diskCache objectForKey:@"1"]);

        [diskCache trimToCount:1];
        NSLog(@"total count : %@",@([diskCache totalCount]));
        NSLog(@"key 1 = %@", [diskCache objectForKey:@"1"]);
        NSLog(@"key 2 = %@", [diskCache objectForKey:@"2"]);
    });

输出如下:

2016-03-28 00:47:00.696 YYCacheTest[55228:1046537] total count : 2
2016-03-28 00:47:00.697 YYCacheTest[55228:1046537] key 2 = world
2016-03-28 00:47:01.700 YYCacheTest[55228:1046537] key 1 = hello
2016-03-28 00:47:01.701 YYCacheTest[55228:1046537] total count : 1
2016-03-28 00:47:01.701 YYCacheTest[55228:1046537] key 1 = (null)
2016-03-28 00:47:01.702 YYCacheTest[55228:1046537] key 2 = world

在最近访问 key1之后,应该优先移除 key2。但目前是移除了key1的值。

关于countLimit与costLimit

YY大神, 我是这样理解的, countLimit是从节点的个数这个粒度上来限制缓存大小.
但是costLimit是从哪个纬度上来细分的呢?还是我理解得有错误?

some word mistake

Lately I've been read this source code, and then i found some mistakes in the comments(注释),in the code you mean you wanna invoke some method or some block, but you use the word 'revoke',which means 取消、撤销.

请教几个问题

1、看到内存缓存用的是双向链表,请问这么做只是用来按照时间排序的么?
2、cost值其实没看懂,请问cost是什么意思呢,看到赋值为0?

拜读了下YYCache.有些疑惑.

YY大神说YYCache使用了LRU算法, 但是我阅读了下源码, 只发现了维护链表头为最近使用的节点, 但是没有发现对访问频率的统计???还是其它地方实现了等效的功能, 比较疑惑.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.