Merge "libutils: fix cache removal when callback invalidates the key"
This commit is contained in:
commit
b0df9dca7c
2 changed files with 39 additions and 1 deletions
|
|
@ -200,11 +200,11 @@ bool LruCache<TKey, TValue>::remove(const TKey& key) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Entry* entry = *find_result;
|
Entry* entry = *find_result;
|
||||||
|
mSet->erase(entry);
|
||||||
if (mListener) {
|
if (mListener) {
|
||||||
(*mListener)(entry->key, entry->value);
|
(*mListener)(entry->key, entry->value);
|
||||||
}
|
}
|
||||||
detachFromCache(*entry);
|
detachFromCache(*entry);
|
||||||
mSet->erase(entry);
|
|
||||||
delete entry;
|
delete entry;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,13 @@ struct ComplexValue {
|
||||||
|
|
||||||
ssize_t ComplexValue::instanceCount = 0;
|
ssize_t ComplexValue::instanceCount = 0;
|
||||||
|
|
||||||
|
struct KeyWithPointer {
|
||||||
|
int *ptr;
|
||||||
|
bool operator ==(const KeyWithPointer& other) const {
|
||||||
|
return *ptr == *other.ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,6 +91,10 @@ template<> inline android::hash_t hash_type(const ComplexKey& value) {
|
||||||
return hash_type(value.k);
|
return hash_type(value.k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline android::hash_t hash_type(const KeyWithPointer& value) {
|
||||||
|
return hash_type(*value.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
|
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
|
||||||
public:
|
public:
|
||||||
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
|
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
|
||||||
|
|
@ -98,6 +109,14 @@ public:
|
||||||
StringValue lastValue;
|
StringValue lastValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class InvalidateKeyCallback : public OnEntryRemoved<KeyWithPointer, StringValue> {
|
||||||
|
public:
|
||||||
|
void operator()(KeyWithPointer& k, StringValue&) {
|
||||||
|
delete k.ptr;
|
||||||
|
k.ptr = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class LruCacheTest : public testing::Test {
|
class LruCacheTest : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
|
|
@ -293,6 +312,25 @@ TEST_F(LruCacheTest, CallbackOnClear) {
|
||||||
EXPECT_EQ(3, callback.callbackCount);
|
EXPECT_EQ(3, callback.callbackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LruCacheTest, CallbackRemovesKeyWorksOK) {
|
||||||
|
LruCache<KeyWithPointer, StringValue> cache(1);
|
||||||
|
InvalidateKeyCallback callback;
|
||||||
|
cache.setOnEntryRemovedListener(&callback);
|
||||||
|
KeyWithPointer key1;
|
||||||
|
key1.ptr = new int(1);
|
||||||
|
KeyWithPointer key2;
|
||||||
|
key2.ptr = new int(2);
|
||||||
|
|
||||||
|
cache.put(key1, "one");
|
||||||
|
// As the size of the cache is 1, the put will call the callback.
|
||||||
|
// Make sure everything goes smoothly even if the callback invalidates
|
||||||
|
// the key (b/24785286)
|
||||||
|
cache.put(key2, "two");
|
||||||
|
EXPECT_EQ(1U, cache.size());
|
||||||
|
EXPECT_STREQ("two", cache.get(key2));
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(LruCacheTest, IteratorCheck) {
|
TEST_F(LruCacheTest, IteratorCheck) {
|
||||||
LruCache<int, int> cache(100);
|
LruCache<int, int> cache(100);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue