Skip to content
Browse files

Fixed a problem with SimpleLRUCache that meant cache wasn't being use…

…d correctly
  • Loading branch information...
1 parent 3a46357 commit c47f61429f5457fa1e54e55fafe5a127ad6f798f @alanw alanw committed with Nov 8, 2010
Showing with 107 additions and 80 deletions.
  1. +3 −2 include/Lucene.h
  2. +38 −42 include/SimpleLRUCache.h
  3. +2 −1 src/core/index/TermInfosReader.cpp
  4. +64 −35 src/test/util/SimpleLRUCacheTest.cpp
View
5 include/Lucene.h
@@ -17,6 +17,7 @@
#include <vector>
#include <map>
#include <set>
+#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/weak_ptr.hpp>
@@ -212,8 +213,8 @@ namespace Lucene
typedef Map< String, IndexReaderPtr > MapStringIndexReader;
typedef Map< TermPtr, NumPtr, luceneCompare<TermPtr> > MapTermNum;
- template <typename KEY, typename VALUE> class SimpleLRUCache;
- typedef SimpleLRUCache<TermPtr, TermInfoPtr> TermInfoCache;
+ template < class KEY, class VALUE, class HASH = boost::hash<KEY>, class EQUAL = std::equal_to<KEY> > class SimpleLRUCache;
+ typedef SimpleLRUCache< TermPtr, TermInfoPtr, luceneHash<TermPtr>, luceneEquals<TermPtr> > TermInfoCache;
typedef boost::shared_ptr<TermInfoCache> TermInfoCachePtr;
}
View
80 include/SimpleLRUCache.h
@@ -7,6 +7,7 @@
#ifndef SIMPLELRUCACHE_H
#define SIMPLELRUCACHE_H
+#include "LuceneObject.h"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
@@ -16,21 +17,17 @@
namespace Lucene
{
/// General purpose LRU cache map.
- /// Accessing an entry will keep the entry cached. {@link #get(const KEY&, VALUE&)} and
+ /// Accessing an entry will keep the entry cached. {@link #get(const KEY&)} and
/// {@link #put(const KEY&, const VALUE&)} results in an access to the corresponding entry.
- template <typename KEY, typename VALUE>
- class SimpleLRUCache
+ template <class KEY, class VALUE, class HASH, class EQUAL>
+ class SimpleLRUCache : public LuceneObject
{
public:
- typedef std::pair<KEY, VALUE> cache_item;
- typedef boost::multi_index::multi_index_container< cache_item, boost::multi_index::indexed_by<
- boost::multi_index::hashed_unique< boost::multi_index::member<cache_item, KEY, &cache_item::first> >,
- boost::multi_index::sequenced<> >, Allocator<cache_item> > cache_items;
- typedef typename cache_items::iterator iterator;
- typedef typename cache_items::template nth_index<0>::type hash_index;
- typedef typename hash_index::iterator hash_index_iterator;
- typedef typename cache_items::template nth_index<1>::type sequenced_index;
- typedef typename sequenced_index::iterator sequenced_index_iterator;
+ typedef std::pair<KEY, VALUE> key_value;
+ typedef std::list< key_value > key_list;
+ typedef typename key_list::const_iterator const_iterator;
+ typedef boost::unordered_map< KEY, typename key_list::iterator, HASH, EQUAL, Allocator< std::pair<KEY, typename key_list::iterator> > > map_type;
+ typedef typename map_type::const_iterator map_iterator;
SimpleLRUCache(int32_t cacheSize)
{
@@ -42,58 +39,57 @@ namespace Lucene
}
protected:
- cache_items cacheItems;
int32_t cacheSize;
+ key_list cacheList;
+ map_type cacheMap;
public:
- int32_t size()
+ void put(const KEY& key, const VALUE& value)
{
- return cacheItems.size();
- }
+ cacheList.push_front(std::make_pair(key, value));
+ cacheMap[key] = cacheList.begin();
- bool get(const KEY& key, VALUE& value)
+ if ((int32_t)cacheList.size() > cacheSize)
{
- hash_index& hashIndex = cacheItems.template get<0>();
- hash_index_iterator it1 = hashIndex.find(key);
+ cacheMap.erase(cacheList.back().first);
+ cacheList.pop_back();
+ }
+ }
- if (it1 == hashIndex.end())
- return false;
- value = it1->second;
+ VALUE get(const KEY& key)
+ {
+ map_iterator find = cacheMap.find(key);
+ if (find == cacheMap.end())
+ return VALUE();
- sequenced_index& sequencedIndex = cacheItems.template get<1>();
- sequencedIndex.relocate(sequencedIndex.end(), cacheItems.template project<1>(it1));
+ VALUE value(find->second->second);
+ cacheList.erase(find->second);
+ cacheList.push_front(std::make_pair(key, value));
+ cacheMap[key] = cacheList.begin();
- return true;
+ return value;
}
- void put(const KEY& key, const VALUE& value)
- {
- if (cacheSize > 0 && (int32_t)cacheItems.size() >= cacheSize)
+ bool contains(const KEY& key) const
{
- sequenced_index& sequencedIndex = cacheItems.template get<1>();
- sequencedIndex.erase(sequencedIndex.begin());
+ return (cacheMap.find(key) != cacheMap.end());
}
- hash_index& hashIndex = cacheItems.template get<0>();
- hash_index_iterator it = hashIndex.find(key);
-
- if (it == hashIndex.end())
- cacheItems.insert(std::make_pair(key, value));
- else
- hashIndex.replace(it, std::make_pair(key, value));
+ int32_t size() const
+ {
+ return cacheList.size();
}
- iterator begin()
+ const_iterator begin() const
{
- return cacheItems.begin();
+ return cacheList.begin();
}
- iterator end()
+ const_iterator end() const
{
- return cacheItems.end();
+ return cacheList.end();
}
};
};
-
#endif
View
3 src/core/index/TermInfosReader.cpp
@@ -157,7 +157,8 @@ namespace Lucene
{
cache = resources->termInfoCache;
// check the cache first if the term was recently looked up
- if (cache->get(term, ti))
+ ti = cache->get(term);
+ if (ti)
return ti;
}
View
99 src/test/util/SimpleLRUCacheTest.cpp
@@ -7,36 +7,38 @@
#include "TestInc.h"
#include "LuceneTestFixture.h"
#include "SimpleLRUCache.h"
+#include "Term.h"
using namespace Lucene;
-typedef SimpleLRUCache<int32_t, String> TestLRUCache;
+typedef SimpleLRUCache<int32_t, String> TestLRUSimpleCache;
+typedef SimpleLRUCache< TermPtr, int32_t, luceneHash<TermPtr>, luceneEquals<TermPtr> > TestLRUTermCache;
BOOST_FIXTURE_TEST_SUITE(SimpleLRUCacheTest, LuceneTestFixture)
BOOST_AUTO_TEST_CASE(testCachePut)
{
- TestLRUCache testCache(5);
+ TestLRUSimpleCache testCache(5);
testCache.put(1, L"test 1");
testCache.put(2, L"test 2");
testCache.put(3, L"test 3");
testCache.put(4, L"test 4");
testCache.put(5, L"test 5");
- testCache.put(6, L"test 6"); // should pop off "1"
+ testCache.put(6, L"test 6"); // this should pop off "1" because size = 5
BOOST_CHECK_EQUAL(testCache.size(), 5);
- int32_t expectedKey = 2;
+ int32_t expectedKey = 6;
- // lru = 2, 3, 4, 5, 6
- for (TestLRUCache::iterator cache = testCache.begin(); cache != testCache.end(); ++cache)
- BOOST_CHECK_EQUAL(cache->first, expectedKey++);
+ // lru = 6, 5, 4, 3, 2
+ for (TestLRUSimpleCache::const_iterator cache = testCache.begin(); cache != testCache.end(); ++cache)
+ BOOST_CHECK_EQUAL(cache->first, expectedKey--);
}
BOOST_AUTO_TEST_CASE(testCacheGet)
{
- TestLRUCache testCache(5);
+ TestLRUSimpleCache testCache(5);
testCache.put(1, L"test 1");
testCache.put(2, L"test 2");
@@ -45,32 +47,27 @@ BOOST_AUTO_TEST_CASE(testCacheGet)
testCache.put(5, L"test 5");
BOOST_CHECK_EQUAL(testCache.size(), 5);
-
- String val;
- BOOST_CHECK(testCache.get(2, val));
- BOOST_CHECK_EQUAL(val, L"test 2");
-
- BOOST_CHECK(testCache.get(3, val));
- BOOST_CHECK_EQUAL(val, L"test 3");
+ BOOST_CHECK_EQUAL(testCache.get(2), L"test 2");
+ BOOST_CHECK_EQUAL(testCache.get(3), L"test 3");
}
-BOOST_AUTO_TEST_CASE(testCacheGetNotExists)
+BOOST_AUTO_TEST_CASE(testCacheExists)
{
- TestLRUCache testCache(5);
+ TestLRUSimpleCache testCache(5);
testCache.put(1, L"test 1");
testCache.put(2, L"test 2");
testCache.put(3, L"test 3");
testCache.put(4, L"test 4");
testCache.put(5, L"test 5");
- String val;
- BOOST_CHECK(!testCache.get(7, val)); // doesn't exist
+ BOOST_CHECK(testCache.contains(1));
+ BOOST_CHECK(!testCache.contains(7));
}
BOOST_AUTO_TEST_CASE(testCachePutGet)
{
- TestLRUCache testCache(5);
+ TestLRUSimpleCache testCache(5);
testCache.put(1, L"test 1");
testCache.put(2, L"test 2");
@@ -80,56 +77,88 @@ BOOST_AUTO_TEST_CASE(testCachePutGet)
BOOST_CHECK_EQUAL(testCache.size(), 5);
- String val;
- BOOST_CHECK(testCache.get(2, val));
- BOOST_CHECK(testCache.get(3, val));
+ BOOST_CHECK_EQUAL(testCache.get(2), L"test 2");
+ BOOST_CHECK_EQUAL(testCache.get(3), L"test 3");
testCache.put(6, L"test 6");
testCache.put(7, L"test 7");
testCache.put(8, L"test 8");
- std::vector<int32_t> expectedLRU;
- for (TestLRUCache::iterator cache = testCache.begin(); cache != testCache.end(); ++cache)
- expectedLRU.push_back(cache->first);
+ Collection<int32_t> expectedLRU = Collection<int32_t>::newInstance();
+ for (TestLRUSimpleCache::const_iterator cache = testCache.begin(); cache != testCache.end(); ++cache)
+ expectedLRU.add(cache->first);
BOOST_CHECK_EQUAL(expectedLRU.size(), 5);
- // lru = 5, 2, 3, 6, 7
- BOOST_CHECK_EQUAL(expectedLRU[0], 2);
- BOOST_CHECK_EQUAL(expectedLRU[1], 3);
+ // lru = 8, 7, 6, 3, 2
+ BOOST_CHECK_EQUAL(expectedLRU[0], 8);
+ BOOST_CHECK_EQUAL(expectedLRU[1], 7);
BOOST_CHECK_EQUAL(expectedLRU[2], 6);
- BOOST_CHECK_EQUAL(expectedLRU[3], 7);
- BOOST_CHECK_EQUAL(expectedLRU[4], 8);
+ BOOST_CHECK_EQUAL(expectedLRU[3], 3);
+ BOOST_CHECK_EQUAL(expectedLRU[4], 2);
}
BOOST_AUTO_TEST_CASE(testRandomAccess)
{
const int32_t n = 100;
- TestLRUCache cache(n);
+ TestLRUSimpleCache cache(n);
String value = L"test";
for (int32_t i = 0; i < n; ++i)
cache.put(i, value);
// access every 2nd item in cache
for (int32_t i = 0; i < n; i += 2)
- BOOST_CHECK(cache.get(i, value));
+ BOOST_CHECK_NE(cache.get(i), L"");
// add n/2 elements to cache, the ones that weren't touched in the previous loop should now be thrown away
for (int32_t i = n; i < n + (n / 2); ++i)
cache.put(i, value);
// access every 4th item in cache
for (int32_t i = 0; i < n; i += 4)
- BOOST_CHECK(cache.get(i, value));
+ BOOST_CHECK_NE(cache.get(i), L"");
// add 3/4n elements to cache, the ones that weren't touched in the previous loops should now be thrown away
for (int32_t i = n; i < n + (n * 3 / 4); ++i)
cache.put(i, value);
// access every 4th item in cache
for (int32_t i = 0; i < n; i += 4)
- BOOST_CHECK(cache.get(i, value));
+ BOOST_CHECK_NE(cache.get(i), L"");
+}
+
+BOOST_AUTO_TEST_CASE(testTermCache)
+{
+ TestLRUTermCache testCache(5);
+
+ testCache.put(newLucene<Term>(L"field1", L"text1"), 1);
+ testCache.put(newLucene<Term>(L"field2", L"text2"), 2);
+ testCache.put(newLucene<Term>(L"field3", L"text3"), 3);
+ testCache.put(newLucene<Term>(L"field4", L"text4"), 4);
+ testCache.put(newLucene<Term>(L"field5", L"text5"), 5);
+
+ BOOST_CHECK_EQUAL(testCache.size(), 5);
+
+ BOOST_CHECK_EQUAL(testCache.get(newLucene<Term>(L"field2", L"text2")), 2);
+ BOOST_CHECK_EQUAL(testCache.get(newLucene<Term>(L"field3", L"text3")), 3);
+
+ testCache.put(newLucene<Term>(L"field6", L"text6"), 6);
+ testCache.put(newLucene<Term>(L"field7", L"text7"), 7);
+ testCache.put(newLucene<Term>(L"field8", L"text8"), 8);
+
+ Collection<TermPtr> expectedLRU = Collection<TermPtr>::newInstance();
+ for (TestLRUTermCache::const_iterator cache = testCache.begin(); cache != testCache.end(); ++cache)
+ expectedLRU.add(cache->first);
+
+ BOOST_CHECK_EQUAL(expectedLRU.size(), 5);
+
+ // lru = field8, field7, field6, field3, field2
+ BOOST_CHECK(expectedLRU[0]->equals(newLucene<Term>(L"field8", L"text8")));
+ BOOST_CHECK(expectedLRU[1]->equals(newLucene<Term>(L"field7", L"text7")));
+ BOOST_CHECK(expectedLRU[2]->equals(newLucene<Term>(L"field6", L"text6")));
+ BOOST_CHECK(expectedLRU[3]->equals(newLucene<Term>(L"field3", L"text3")));
+ BOOST_CHECK(expectedLRU[4]->equals(newLucene<Term>(L"field2", L"text2")));
}
BOOST_AUTO_TEST_SUITE_END()

0 comments on commit c47f614

Please sign in to comment.
Something went wrong with that request. Please try again.