comparison UnitTests/MemoryCache.cpp @ 284:06aa7b7b6723

implementation of a single-threaded cache mechanism
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Dec 2012 15:40:18 +0100
parents c9977db00e1d
children 4031f73fe0e4
comparison
equal deleted inserted replaced
283:c9977db00e1d 284:06aa7b7b6723
3 #include <glog/logging.h> 3 #include <glog/logging.h>
4 #include <memory> 4 #include <memory>
5 #include <boost/thread.hpp> 5 #include <boost/thread.hpp>
6 #include <boost/lexical_cast.hpp> 6 #include <boost/lexical_cast.hpp>
7 #include "../Core/IDynamicObject.h" 7 #include "../Core/IDynamicObject.h"
8 #include "../Core/MultiThreading/CacheIndex.h" 8 #include "../Core/Cache/MemoryCache.h"
9 9
10 10
11 TEST(CacheIndex, Basic) 11 TEST(CacheIndex, Basic)
12 { 12 {
13 Orthanc::CacheIndex<std::string> r; 13 Orthanc::CacheIndex<std::string> r;
64 64
65 ASSERT_TRUE(r.IsEmpty()); 65 ASSERT_TRUE(r.IsEmpty());
66 } 66 }
67 67
68 68
69 namespace Orthanc
70 {
71
72 class ICacheProvider
73 {
74 public:
75 virtual ~ICacheProvider()
76 {
77 }
78
79 virtual IDynamicObject* Provide(const std::string& id) = 0;
80 };
81
82 class MemoryCache
83 {
84 private:
85 struct Page
86 {
87 std::string id_;
88 std::auto_ptr<IDynamicObject> content_;
89 };
90
91 ICacheProvider& provider_;
92 size_t cacheSize_;
93 CacheIndex<std::string, Page*> index_;
94
95 Page& Load(const std::string& id)
96 {
97 // Reuse the cache entry if it already exists
98 Page* p = NULL;
99 if (index_.Contains(id, p))
100 {
101 assert(p != NULL);
102 index_.TagAsMostRecent(id);
103 return *p;
104 }
105
106 // The id is not in the cache yet. Make some room if the cache
107 // is full.
108 if (index_.GetSize() == cacheSize_)
109 {
110 index_.RemoveOldest(p);
111 delete p;
112 }
113
114 // Create a new cache page
115 std::auto_ptr<Page> result(new Page);
116 result->id_ = id;
117 result->content_.reset(provider_.Provide(id));
118
119 // Add the newly create page to the cache
120 p = result.release();
121 index_.Add(id, p);
122 return *p;
123 }
124
125 public:
126 class Accessor
127 {
128 friend class MemoryCache;
129
130 private:
131 Page& element_;
132
133 Accessor(Page& element) :
134 element_(element)
135 {
136 }
137
138 public:
139 const std::string GetId() const
140 {
141 return element_.id_;
142 }
143
144 IDynamicObject& GetContent()
145 {
146 return *element_.content_;
147 }
148
149 const IDynamicObject& GetContent() const
150 {
151 return *element_.content_;
152 }
153 };
154
155 MemoryCache(ICacheProvider& provider,
156 size_t cacheSize) :
157 provider_(provider),
158 cacheSize_(cacheSize)
159 {
160 }
161
162 ~MemoryCache()
163 {
164 while (!index_.IsEmpty())
165 {
166 Page* element = NULL;
167 index_.RemoveOldest(element);
168 assert(element != NULL);
169 delete element;
170 }
171 }
172
173 Accessor* Access(const std::string& id)
174 {
175 Page& element = Load(id);
176 return new Accessor(element);
177 }
178 };
179 }
180
181 69
182 70
183 namespace 71 namespace
184 { 72 {
185 class Integer : public Orthanc::IDynamicObject 73 class Integer : public Orthanc::IDynamicObject
203 { 91 {
204 return value_; 92 return value_;
205 } 93 }
206 }; 94 };
207 95
208 class IntegerProvider : public Orthanc::ICacheProvider 96 class IntegerProvider : public Orthanc::ICachePageProvider
209 { 97 {
210 public: 98 public:
211 std::string log_; 99 std::string log_;
212 100
213 Orthanc::IDynamicObject* Provide(const std::string& s) 101 Orthanc::IDynamicObject* Provide(const std::string& s)