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 // Author: Mike Brasher, Inova Europe (mbrasher@bmc.com)
33 //
34 mike 1.1 //%/////////////////////////////////////////////////////////////////////////////
35
36 #ifndef PegasusRepository_ObjectCache_h
37 #define PegasusRepository_ObjectCache_h
38
39 #include <Pegasus/Common/Config.h>
40 #include <Pegasus/Common/CIMClass.h>
41 #include <Pegasus/Common/CIMInstance.h>
42 #include <Pegasus/Common/HashTable.h>
|
43 mike 1.6 #include <Pegasus/Common/Mutex.h>
|
44 mike 1.1 #include <Pegasus/Repository/Linkage.h>
45
46 PEGASUS_NAMESPACE_BEGIN
47
48 Uint32 ObjectCacheHash(const String& str);
49
50 template<class OBJECT>
51 class PEGASUS_REPOSITORY_LINKAGE ObjectCache
52 {
53 public:
54
55 ObjectCache(size_t maxEntries);
56
57 void put(const String& path, OBJECT& object);
58
59 bool get(const String& path, OBJECT& object);
60
61 bool evict(const String& path);
62
|
63 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
64 void DisplayCacheStatistics(void)
65 {
|
66 kumpf 1.4 PEGASUS_STD(cout) << " Size (current/max): " << _numEntries <<
67 "/" << _maxEntries << PEGASUS_STD(endl);
68 PEGASUS_STD(cout) << " Requests satisfied from cache: " <<
69 _cacheReadHit << PEGASUS_STD(endl);
70 PEGASUS_STD(cout) << " Requests *not* satisfied from cache: " <<
71 _cacheReadMiss << " (implies write to cache)" << PEGASUS_STD(endl);
72 PEGASUS_STD(cout) <<
73 " Cache entries \"aged out\" due to cache size constraints: " <<
74 _cacheRemoveLRU << PEGASUS_STD(endl);
|
75 dave.sudlik 1.3 }
76 #endif
77
78
|
79 mike 1.1 private:
80
81 static Uint32 _hash(const String& s)
82 {
83 return ObjectCacheHash(s);
84 }
85
86 static bool _equal(const String& s1, const String& s2)
87 {
88 return String::equalNoCase(s1, s2);
89 }
90
91 struct Entry
92 {
93 Uint32 code;
94 String path;
95 OBJECT object;
96 Entry* hashNext;
97 Entry* queueNext;
98 Entry* queuePrev;
99
100 mike 1.1 Entry(Uint32 code_, const String& path_, OBJECT& object_) :
101 code(code_), path(path_), object(object_.clone()) { }
102 };
103
104 enum { NUM_CHAINS = 128 };
105
106 Entry* _chains[NUM_CHAINS];
107 Entry* _front;
108 Entry* _back;
109 size_t _numEntries;
110 size_t _maxEntries;
111 Mutex _mutex;
|
112 dave.sudlik 1.3
113 #ifdef PEGASUS_DEBUG
114 Uint32 _cacheReadHit;
115 Uint32 _cacheReadMiss;
116 Uint32 _cacheRemoveLRU;
117 #endif
118
119
|
120 mike 1.1 };
121
122 template<class OBJECT>
123 ObjectCache<OBJECT>::ObjectCache(size_t maxEntries) :
124 _front(0), _back(0), _numEntries(0), _maxEntries(maxEntries)
|
125 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
126 , _cacheReadHit(0), _cacheReadMiss(0), _cacheRemoveLRU(0)
127 #endif
|
128 mike 1.1 {
129 memset(_chains, 0, sizeof(_chains));
130 }
131
132 template<class OBJECT>
133 void ObjectCache<OBJECT>::put(const String& path, OBJECT& object)
134 {
135 if (_maxEntries == 0)
136 return;
137
|
138 mike 1.6 _mutex.lock();
|
139 mike 1.1
140 //// Update object if it is already in cache:
141
142 Uint32 code = _hash(path);
143 Uint32 index = code % NUM_CHAINS;
144
145 for (Entry* p = _chains[index]; p; p = p->hashNext)
146 {
147 if (code == p->code && _equal(p->path, path))
148 {
149 // Update the repository.
150 p->object = object.clone();
151 _mutex.unlock();
152 return;
153 }
154 }
155
156 //// Add to hash table:
157
158 Entry* entry = new Entry(code, path, object);
159 entry->hashNext = _chains[index];
160 mike 1.1 _chains[index] = entry;
161
162 //// Add to back of FIFO queue:
163
164 entry->queueNext = 0;
165
166 if (_back)
167 {
168 _back->queueNext = entry;
169 entry->queuePrev = _back;
170 _back = entry;
171 }
172 else
173 {
174 _front = entry;
175 _back = entry;
176 entry->queuePrev = 0;
177 }
178
179 _numEntries++;
180
181 mike 1.1 //// Evict LRU entry if necessary (from front).
182
183 if (_numEntries > _maxEntries)
184 {
185 Entry* entry = _front;
186
187 //// Remove from hash table first.
188
189 Uint32 index = entry->code % NUM_CHAINS;
190 Entry* hashPrev = 0;
191
192 for (Entry* p = _chains[index]; p; p = p->hashNext)
193 {
194 if (p->code == entry->code && _equal(p->path, entry->path))
195 {
196 if (hashPrev)
197 hashPrev->hashNext = p->hashNext;
198 else
199 _chains[index] = p->hashNext;
200
201 break;
202 mike 1.1 }
203
204 hashPrev = p;
205 }
206
207 //// Now remove from queue:
208
209 _front = entry->queueNext;
210
211 if (_front)
212 _front->queuePrev = 0;
213
214 delete entry;
215 _numEntries--;
|
216 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
217 _cacheRemoveLRU++;
218 #endif
|
219 mike 1.1 }
220
221 _mutex.unlock();
222 return;
223 }
224
225 template<class OBJECT>
226 bool ObjectCache<OBJECT>::get(const String& path, OBJECT& object)
227 {
228 if (_maxEntries == 0)
229 return false;
230
|
231 mike 1.6 _mutex.lock();
|
232 mike 1.1
233 //// Search cache for object.
234
235 Uint32 code = _hash(path);
236 Uint32 index = code % NUM_CHAINS;
237
238 for (Entry* p = _chains[index]; p; p = p->hashNext)
239 {
240 if (code == p->code && _equal(p->path, path))
241 {
242 object = p->object.clone();
|
243 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
244 _cacheReadHit++;
245 #endif
|
246 mike 1.1 _mutex.unlock();
247 return true;
248 }
249 }
250
251 /// Not found!
252
|
253 dave.sudlik 1.3 #ifdef PEGASUS_DEBUG
254 _cacheReadMiss++;
255 #endif
|
256 mike 1.1 _mutex.unlock();
257 return false;
258 }
259
260 template<class OBJECT>
261 bool ObjectCache<OBJECT>::evict(const String& path)
262 {
263 if (_maxEntries == 0)
264 return false;
265
|
266 mike 1.6 _mutex.lock();
|
267 mike 1.1
268 //// Find and remove the given element.
269
270 Uint32 code = _hash(path);
271 Uint32 index = code % NUM_CHAINS;
272 Entry* hashPrev = 0;
273
274 for (Entry* p = _chains[index]; p; p = p->hashNext)
275 {
276 if (code == p->code && _equal(p->path, path))
277 {
278 // Remove from hash chain:
279
280 if (hashPrev)
281 hashPrev->hashNext = p->hashNext;
282 else
283 _chains[index] = p->hashNext;
284
285 // Remove from queue:
286
287 if (p->queuePrev)
288 mike 1.1 p->queuePrev->queueNext = p->queueNext;
|
289 mike 1.2 else
290 _front = p->queueNext;
|
291 mike 1.1
292 if (p->queueNext)
293 p->queueNext->queuePrev = p->queuePrev;
|
294 mike 1.2 else
295 _back = p->queuePrev;
|
296 mike 1.1
297 // Delete the entry and update the number of entries.
298
299 delete p;
300 _numEntries--;
301
302 _mutex.unlock();
303 return true;
304 }
305
306 hashPrev = p;
307 }
308
309 //// Not found!
310
311 _mutex.unlock();
312 return false;
313 }
314
315 PEGASUS_NAMESPACE_END
316
317 mike 1.1 #endif /* PegasusRepository_ObjectCache_h */
|