1 thilo.boehm 1.2 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 thilo.boehm 1.2 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //////////////////////////////////////////////////////////////////////////
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32
33 #include <Pegasus/Common/SCMOClassCache.h>
34 #include <Pegasus/Common/CIMNameCast.h>
35
36 PEGASUS_NAMESPACE_BEGIN
37
38 PEGASUS_USING_STD;
39
40 SCMOClassCache* SCMOClassCache::_theInstance = 0;
41
42 void SCMOClassCache::destroy()
43 thilo.boehm 1.2 {
44 delete _theInstance;
45 _theInstance=0;
46 }
47
48 SCMOClassCache* SCMOClassCache::getInstance()
49 {
50 if(_theInstance == NULL)
51 {
52 _theInstance = new SCMOClassCache();
53 }
54 return _theInstance;
55 }
56
57 SCMOClassCache::~SCMOClassCache()
58 {
59 // Signal to all callers and work in progress that the SMOClassCache
60 // will be destroyed soon.
61 // As from now, no other caller can get the the lock. They are blocked out.
62 _dying = true;
63
64 thilo.boehm 1.2 // Cleanup the class cache
65 for (Uint32 i = 0 ; i < PEGASUS_SCMO_CLASS_CACHE_SIZE; i++)
66 {
67 delete _theCache[i].data;
68 }
69 }
70
71 Uint64 SCMOClassCache::_generateKey(
72 const char* className,
73 Uint32 classNameLen,
74 const char* nameSpaceName,
75 Uint32 nameSpaceNameLen)
76 {
77 Uint64 key = 0;
78
79 key = (Uint64(classNameLen) << 48 ) |
80 (Uint64(className[0]) << 40 ) |
81 (Uint64(className[classNameLen-1]) << 32 ) |
82 (Uint64(nameSpaceNameLen) << 16 ) |
83 (Uint64(nameSpaceName[0]) << 8 ) |
84 Uint64(nameSpaceName[nameSpaceNameLen-1]);
85 thilo.boehm 1.2
86 return key;
87 }
88
89 inline Boolean SCMOClassCache::_lockEntry(Uint32 index)
90 {
91 // The lock is implemented as a spin loop, since the action to
92 // verify for the right cache entry is very short.
93
94 if ( _dying )
95 {
96 // The cache is going to be destroyed.
97 // The caller will never get the lock.
98 return false;
99 }
100
101 while ( true )
102 {
103 if ( _dying )
104 {
105 // The cache is going to be destroyed.
106 thilo.boehm 1.2 // The caller will never get the lock.
|
108 thilo.boehm 1.2 }
109
110 // If the lock counter not 1,an other caller is reading the entry.
111 if ( _theCache[index].lock.get() == 1 )
112 {
113 // Decrement the atomic lock counter and test if we do have lock:
114 // _theCache[index].lock == 0
115 if ( _theCache[index].lock.decAndTestIfZero() )
116 {
117 // We do have lock!
118 return true;
119 }
120 }
121 // I did not get the lock. So signal the scheduer to change the active
122 // thread to allow other threads to proceed. This also prevents from
123 // looping in a tight loop that causes a dead look due to the
124 // lock obtaining thread does not get any time ot finsh his work.
125 #ifdef PEGASUS_DEBUG
126 _contentionCount.inc();
127 #endif
128 Threads::yield();
129 thilo.boehm 1.2 }
130 return false;
131 }
132
133 inline Boolean SCMOClassCache::_sameSCMOClass(
134 const char* nsName,
135 Uint32 nsNameLen,
136 const char* className,
137 Uint32 classNameLen,
138 SCMOClass* theClass)
139 {
140 if (_equalNoCaseUTF8Strings(
141 theClass->cls.hdr->className,
142 theClass->cls.base,
143 className,
144 classNameLen))
145 {
146 return _equalNoCaseUTF8Strings(
147 theClass->cls.hdr->nameSpace,
148 theClass->cls.base,
149 nsName,
150 thilo.boehm 1.2 nsNameLen);
151 }
152
153 return false;
154 }
155
156 SCMOClass SCMOClassCache::_addClassToCache(
157 const char* nsName,
158 Uint32 nsNameLen,
159 const char* className,
160 Uint32 classNameLen,
161 Uint64 theKey)
162 {
163 WriteLock modifyLock(_modifyCacheLock);
164
165 if ( _dying )
166 {
167 // The cache is going to be destroyed.
168 return SCMOClass();
169 }
170
171 thilo.boehm 1.2 Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
172 Uint32 nextIndex = startIndex;
173 // The number of used entries is form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
174 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
175
176 // This constallation would cause an infitloop below.
177 // A miss read of global variables has happen
178 if (nextIndex > usedEntries)
179 {
180 // start from the beginning
181 startIndex = 0;
182 nextIndex = 0;
183 }
184
185 // Check the cache if the class was already added while waiting for the
186 // modifyLock.
187 //
188 // Note: The lock for each cache entry must not be obtained,
189 // because it is used to signal a modify operation, that some
190 // body is reading it. Due to we are the modify task, we know
191 // that we are reading the cache entries!
192 thilo.boehm 1.2 //
193 for (Uint32 i = 0; i < usedEntries; i++)
194 {
195 // Does the key match for the entry and the requested class ?
196 if (0 != _theCache[nextIndex].key &&
197 theKey == _theCache[nextIndex].key)
198 {
199 // To get sure we found the right class, compare name space
200 // and class name.
201 if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
202 _theCache[nextIndex].data))
203 {
204 // The entry was added while waiting for the modify lock.
205 // The modify lock is destroyed automaticaly !
206 #ifdef PEGASUS_DEBUG
207 _cacheReadHit++;
208 #endif
209 _lastSuccessIndex = nextIndex;
210 return SCMOClass(*_theCache[nextIndex].data);
211 }
212 }
213 thilo.boehm 1.2
214 // go to the next used entries.
215 nextIndex = (nextIndex + 1) % usedEntries;
216 }
217
218 PEGASUS_ASSERT(_resolveCallBack);
219
220 #ifdef PEGASUS_DEBUG
221 _cacheReadMiss++;
222 #endif
223
224 SCMOClass tmp = _resolveCallBack(
225 CIMNamespaceNameCast(String(nsName,nsNameLen)),
226 CIMNameCast(String(className,classNameLen)));
227
228 if (tmp.isEmpty())
229 {
230 // The requested class was not found !
231 // The modify lock is destroyed automaticaly !
232 return SCMOClass();
233 }
234 thilo.boehm 1.2
235 SCMOClass* scmoClass = new SCMOClass(tmp);
236
237 _lastWrittenIndex = (_lastWrittenIndex + 1)%PEGASUS_SCMO_CLASS_CACHE_SIZE;
238
239 // Ensure that nobody is reading the enty, so I can write.
240 if (_lockEntry(_lastWrittenIndex))
241 {
242 _theCache[_lastWrittenIndex].key = theKey;
243
244 // If the entry was reused, release old object form the cache.
245 if (0 != _theCache[_lastWrittenIndex].data )
246 {
247 #ifdef PEGASUS_DEBUG
248 _cacheRemoveLRU++;
249 #endif
250 delete _theCache[_lastWrittenIndex].data;
251 }
252
253 _theCache[_lastWrittenIndex].data = scmoClass;
254
255 thilo.boehm 1.2 if (_fillingLevel < PEGASUS_SCMO_CLASS_CACHE_SIZE)
256 {
257 _fillingLevel ++;
258 }
259
260 _lastSuccessIndex = _lastWrittenIndex;
261
262 _unlockEntry(_lastWrittenIndex);
263 }
264 else
265 {
266 // The cache is going to be destroyed.
267 // The lock can not be obtained.
268 delete scmoClass;
269 return SCMOClass();
270 }
271
272 // The modify lock is destroyed automaticaly !
273 return SCMOClass(*scmoClass);
274 }
275
276 thilo.boehm 1.2 SCMOClass SCMOClassCache::getSCMOClass(
277 const char* nsName,
278 Uint32 nsNameLen,
279 const char* className,
280 Uint32 classNameLen)
281 {
282 Uint64 theKey;
283
284 // Due to the _lastSuccessIndex may contain an invalid value,
285 // use the modulo to ensure it the index is in a valid range.
286 Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
287 Uint32 nextIndex = startIndex;
288 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
289 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
290
291 // This constallation would cause an infitloop below.
292 // A miss read of global variables has happen
293 if (nextIndex > usedEntries)
294 {
295 // start from the beginning
296 startIndex = 0;
297 thilo.boehm 1.2 nextIndex = 0;
298 }
299
300 if (nsName && className && nsNameLen && classNameLen)
301 {
302 theKey = _generateKey(className,classNameLen,nsName,nsNameLen);
303
304 // The counter i is never used as index.
305 // It is used to ensure to look through all used entries.
306 for (Uint32 i = 0; i < usedEntries; i++)
307 {
308 if(_lockEntry(nextIndex))
309 {
310 // does the key match for the entry and the requested class ?
311 if ( 0 != _theCache[nextIndex].key &&
312 theKey == _theCache[nextIndex].key)
313 {
314 // To get sure we found the right class, compare name space
315 // and class name.
316 if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
317 _theCache[nextIndex].data))
318 thilo.boehm 1.2 {
319 // Yes, we got it !
320 SCMOClass theClass(*_theCache[nextIndex].data);
321 _lastSuccessIndex = nextIndex;
322 #ifdef PEGASUS_DEBUG
323 _cacheReadHit++;
324 #endif
325 _unlockEntry(nextIndex);
326 return theClass;
327 }
328 }
329 // It was the wrong entry, go to the next.
330 _unlockEntry(nextIndex);
331 }
332 else
333 {
334 // The cache is going to be destroyed.
335 // The lock can not be obtained. Give up.
336 return SCMOClass();
337 }
338 // It was the wrong entry, go to the next used entry..
339 thilo.boehm 1.2 nextIndex = (nextIndex + 1) % usedEntries;
340
341 }
342
343 // If we end up here, the class is not in the cache !
344 // We have to get it from the repositroy and add it into the cache.
345 return _addClassToCache(nsName,nsNameLen,className,classNameLen,theKey);
346 }
347
348 return SCMOClass();
349 }
350
351 void SCMOClassCache::removeSCMOClass(
352 CIMNamespaceName cimNameSpace,
353 CIMName cimClassName)
354 {
355
356 if (cimClassName.isNull() || cimNameSpace.isNull())
357 {
358 return ;
359 }
360 thilo.boehm 1.2
361 CString nsName = cimNameSpace.getString().getCString();
362 Uint32 nsNameLen = strlen(nsName);
363 CString clsName = cimClassName.getString().getCString();
364 Uint32 clsNameLen = strlen(clsName);
365
366 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
367 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
368
369 Uint64 theKey = _generateKey(clsName,clsNameLen,nsName,nsNameLen);
370
371 // A straight forward loop through all used entries,
372 // ignoring the last success.
373 for (Uint32 i = 0; i < usedEntries; i++)
374 {
375 if(_lockEntry(i))
376 {
377 // does the key match for the entry and the requested class ?
378 if ( 0 != _theCache[i].key && theKey == _theCache[i].key)
379 {
380 // To get sure we found the right class, compare name space
381 thilo.boehm 1.2 // and class name.
382 if (_sameSCMOClass(nsName,nsNameLen,clsName,clsNameLen,
383 _theCache[i].data))
384 {
385 // Yes, we got it !
386 _theCache[i].key = 0;
387 delete _theCache[i].data;
388 _theCache[i].data = 0;
389 _unlockEntry(i);
390 return;
391 }
392 }
393 // It was the wrong entry, go to the next.
394 _unlockEntry(i);
395 }
396 else
397 {
398 // We do not get the lock, if the cache is going to be destroyed.
399 return;
400 }
401 }
402 thilo.boehm 1.2 }
403
404 void SCMOClassCache::clear()
405 {
406 WriteLock modifyLock(_modifyCacheLock);
407
408 if ( _dying )
409 {
410 // The cache is going to be destroyed.
411 return ;
412 }
413
414 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
415 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
416
417 // A straight forwar loop through all used entries,
418 // ignoring the last success.
419 for (Uint32 i = 0; i < usedEntries; i++)
420 {
421 if(_lockEntry(i))
422 {
423 thilo.boehm 1.2 _theCache[i].key = 0;
424 delete _theCache[i].data;
425 _theCache[i].data = 0;
426 _unlockEntry(i);
427 }
428 else
429 {
430 // We do not get the lock, if the cache is going to be destroyed.
431 return;
432 }
433 }
434 // Reset all controll data
435 _fillingLevel = 0;
436 _lastSuccessIndex = 0;
437 _lastWrittenIndex = PEGASUS_SCMO_CLASS_CACHE_SIZE-1;
438
439
440 }
441 #ifdef PEGASUS_DEBUG
442 void SCMOClassCache::DisplayCacheStatistics()
443 {
444 thilo.boehm 1.2 PEGASUS_STD(cout) << "SCMOClass Cache Statistics:" <<
445 PEGASUS_STD(endl);
446 PEGASUS_STD(cout) << " Size (current/max): " <<
447 _fillingLevel << "/" << PEGASUS_SCMO_CLASS_CACHE_SIZE <<
448 PEGASUS_STD(endl);
449 PEGASUS_STD(cout) << " Requests satisfied from cache: " <<
450 _cacheReadHit << PEGASUS_STD(endl);
451 PEGASUS_STD(cout) << " Requests *not* satisfied from cache: " <<
452 _cacheReadMiss << " (implies write to cache)" << PEGASUS_STD(endl);
453 PEGASUS_STD(cout) <<
454 " Cache entries \"aged out\" due to cache size constraints: " <<
455 _cacheRemoveLRU << PEGASUS_STD(endl);
456 PEGASUS_STD(cout) << " Number of lock contentions: " <<
457 _contentionCount.get() << PEGASUS_STD(endl);
458
459 }
460 #endif
461
462 PEGASUS_NAMESPACE_END
|