1 karl 1.5 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.1 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.5 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.1 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 mike 1.1 #ifndef PegasusRepository_ObjectCache_h
35 #define PegasusRepository_ObjectCache_h
36
37 #include <Pegasus/Common/Config.h>
38 #include <Pegasus/Common/CIMClass.h>
39 #include <Pegasus/Common/CIMInstance.h>
40 #include <Pegasus/Common/HashTable.h>
|
41 mike 1.6 #include <Pegasus/Common/Mutex.h>
|
42 mike 1.1 #include <Pegasus/Repository/Linkage.h>
43
44 PEGASUS_NAMESPACE_BEGIN
45
46 Uint32 ObjectCacheHash(const String& str);
47
48 template<class OBJECT>
49 class PEGASUS_REPOSITORY_LINKAGE ObjectCache
50 {
51 public:
52
53 ObjectCache(size_t maxEntries);
54
55 void put(const String& path, OBJECT& object);
56
57 bool get(const String& path, OBJECT& object);
58
59 bool evict(const String& path);
60
|
61 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
|
62 kumpf 1.7 void DisplayCacheStatistics()
|
63 dave.sudlik 1.3 {
|
64 kumpf 1.4 PEGASUS_STD(cout) << " Size (current/max): " << _numEntries <<
65 "/" << _maxEntries << PEGASUS_STD(endl);
66 PEGASUS_STD(cout) << " Requests satisfied from cache: " <<
67 _cacheReadHit << PEGASUS_STD(endl);
68 PEGASUS_STD(cout) << " Requests *not* satisfied from cache: " <<
69 _cacheReadMiss << " (implies write to cache)" << PEGASUS_STD(endl);
70 PEGASUS_STD(cout) <<
71 " Cache entries \"aged out\" due to cache size constraints: " <<
72 _cacheRemoveLRU << PEGASUS_STD(endl);
|
73 dave.sudlik 1.3 }
74 #endif
75
76
|
77 mike 1.1 private:
78
79 static Uint32 _hash(const String& s)
80 {
|
81 kumpf 1.7 return ObjectCacheHash(s);
|
82 mike 1.1 }
83
84 static bool _equal(const String& s1, const String& s2)
85 {
86 return String::equalNoCase(s1, s2);
87 }
88
89 struct Entry
90 {
|
91 kumpf 1.7 Uint32 code;
92 String path;
93 OBJECT object;
94 Entry* hashNext;
95 Entry* queueNext;
96 Entry* queuePrev;
|
97 mike 1.1
|
98 kumpf 1.7 Entry(Uint32 code_, const String& path_, OBJECT& object_) :
99 code(code_), path(path_), object(object_.clone()) { }
|
100 mike 1.1 };
101
102 enum { NUM_CHAINS = 128 };
103
104 Entry* _chains[NUM_CHAINS];
105 Entry* _front;
106 Entry* _back;
107 size_t _numEntries;
108 size_t _maxEntries;
109 Mutex _mutex;
|
110 dave.sudlik 1.3
111 #ifdef PEGASUS_DEBUG
112 Uint32 _cacheReadHit;
113 Uint32 _cacheReadMiss;
114 Uint32 _cacheRemoveLRU;
115 #endif
116
117
|
118 mike 1.1 };
119
120 template<class OBJECT>
|
121 kumpf 1.7 ObjectCache<OBJECT>::ObjectCache(size_t maxEntries)
122 : _front(0), _back(0), _numEntries(0), _maxEntries(maxEntries)
|
123 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
124 , _cacheReadHit(0), _cacheReadMiss(0), _cacheRemoveLRU(0)
125 #endif
|
126 mike 1.1 {
127 memset(_chains, 0, sizeof(_chains));
128 }
129
130 template<class OBJECT>
131 void ObjectCache<OBJECT>::put(const String& path, OBJECT& object)
132 {
133 if (_maxEntries == 0)
|
134 kumpf 1.7 return;
|
135 mike 1.1
|
136 kumpf 1.8 AutoMutex lock(_mutex);
|
137 mike 1.1
138 //// Update object if it is already in cache:
139
140 Uint32 code = _hash(path);
141 Uint32 index = code % NUM_CHAINS;
142
143 for (Entry* p = _chains[index]; p; p = p->hashNext)
144 {
145 if (code == p->code && _equal(p->path, path))
|
146 kumpf 1.7 {
147 // Update the repository.
148 p->object = object.clone();
149 return;
150 }
|
151 mike 1.1 }
152
153 //// Add to hash table:
154
155 Entry* entry = new Entry(code, path, object);
156 entry->hashNext = _chains[index];
157 _chains[index] = entry;
158
159 //// Add to back of FIFO queue:
160
161 entry->queueNext = 0;
162
163 if (_back)
164 {
|
165 kumpf 1.7 _back->queueNext = entry;
166 entry->queuePrev = _back;
167 _back = entry;
|
168 mike 1.1 }
169 else
170 {
|
171 kumpf 1.7 _front = entry;
172 _back = entry;
173 entry->queuePrev = 0;
|
174 mike 1.1 }
175
176 _numEntries++;
177
178 //// Evict LRU entry if necessary (from front).
179
180 if (_numEntries > _maxEntries)
181 {
|
182 kumpf 1.7 Entry* entry = _front;
|
183 mike 1.1
|
184 kumpf 1.7 //// Remove from hash table first.
|
185 mike 1.1
|
186 kumpf 1.7 Uint32 index = entry->code % NUM_CHAINS;
187 Entry* hashPrev = 0;
|
188 mike 1.1
|
189 kumpf 1.7 for (Entry* p = _chains[index]; p; p = p->hashNext)
190 {
191 if (p->code == entry->code && _equal(p->path, entry->path))
192 {
193 if (hashPrev)
194 hashPrev->hashNext = p->hashNext;
195 else
196 _chains[index] = p->hashNext;
|
197 mike 1.1
|
198 kumpf 1.7 break;
199 }
|
200 mike 1.1
|
201 kumpf 1.7 hashPrev = p;
202 }
|
203 mike 1.1
|
204 kumpf 1.7 //// Now remove from queue:
|
205 mike 1.1
|
206 kumpf 1.7 _front = entry->queueNext;
|
207 mike 1.1
|
208 kumpf 1.7 if (_front)
209 _front->queuePrev = 0;
|
210 mike 1.1
|
211 kumpf 1.7 delete entry;
212 _numEntries--;
|
213 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
214 _cacheRemoveLRU++;
215 #endif
|
216 mike 1.1 }
217 }
218
219 template<class OBJECT>
220 bool ObjectCache<OBJECT>::get(const String& path, OBJECT& object)
221 {
222 if (_maxEntries == 0)
|
223 kumpf 1.7 return false;
|
224 mike 1.1
|
225 kumpf 1.8 AutoMutex lock(_mutex);
|
226 mike 1.1
227 //// Search cache for object.
228
229 Uint32 code = _hash(path);
230 Uint32 index = code % NUM_CHAINS;
231
232 for (Entry* p = _chains[index]; p; p = p->hashNext)
233 {
234 if (code == p->code && _equal(p->path, path))
|
235 kumpf 1.7 {
236 object = p->object.clone();
|
237 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
238 _cacheReadHit++;
239 #endif
|
240 kumpf 1.7 return true;
241 }
|
242 mike 1.1 }
243
244 /// Not found!
245
|
246 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
247 _cacheReadMiss++;
248 #endif
|
249 mike 1.1 return false;
250 }
251
252 template<class OBJECT>
253 bool ObjectCache<OBJECT>::evict(const String& path)
254 {
255 if (_maxEntries == 0)
|
256 kumpf 1.7 return false;
|
257 mike 1.1
|
258 kumpf 1.8 AutoMutex lock(_mutex);
|
259 mike 1.1
260 //// Find and remove the given element.
261
262 Uint32 code = _hash(path);
263 Uint32 index = code % NUM_CHAINS;
264 Entry* hashPrev = 0;
265
266 for (Entry* p = _chains[index]; p; p = p->hashNext)
267 {
268 if (code == p->code && _equal(p->path, path))
|
269 kumpf 1.7 {
270 // Remove from hash chain:
|
271 mike 1.1
272 if (hashPrev)
273 hashPrev->hashNext = p->hashNext;
274 else
275 _chains[index] = p->hashNext;
276
|
277 kumpf 1.7 // Remove from queue:
|
278 mike 1.1
|
279 kumpf 1.7 if (p->queuePrev)
280 p->queuePrev->queueNext = p->queueNext;
281 else
282 _front = p->queueNext;
|
283 mike 1.1
|
284 kumpf 1.7 if (p->queueNext)
285 p->queueNext->queuePrev = p->queuePrev;
286 else
287 _back = p->queuePrev;
|
288 mike 1.1
|
289 kumpf 1.7 // Delete the entry and update the number of entries.
|
290 mike 1.1
|
291 kumpf 1.7 delete p;
292 _numEntries--;
|
293 mike 1.1
|
294 kumpf 1.7 return true;
295 }
|
296 mike 1.1
|
297 kumpf 1.7 hashPrev = p;
|
298 mike 1.1 }
299
300 //// Not found!
301
302 return false;
303 }
304
305 PEGASUS_NAMESPACE_END
306
307 #endif /* PegasusRepository_ObjectCache_h */
|