Merge "libutils: fix cache removal when callback invalidates the key"

This commit is contained in:
Sergio Giro 2015-11-20 17:09:10 +00:00 committed by Gerrit Code Review
commit b0df9dca7c
2 changed files with 39 additions and 1 deletions

View file

@ -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;
} }

View file

@ -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);