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 #ifdef PEGASUS_USE_SCMO_CLASS_CACHE
58
59 SCMOClassCache::~SCMOClassCache()
60 {
61 // Signal to all callers and work in progress that the SMOClassCache
62 // will be destroyed soon.
63 // As from now, no other caller can get the the lock. They are blocked out.
64 thilo.boehm 1.2 _dying = true;
65
66 // Cleanup the class cache
67 for (Uint32 i = 0 ; i < PEGASUS_SCMO_CLASS_CACHE_SIZE; i++)
68 {
69 delete _theCache[i].data;
70 }
71 }
72
73 Uint64 SCMOClassCache::_generateKey(
74 const char* className,
75 Uint32 classNameLen,
76 const char* nameSpaceName,
77 Uint32 nameSpaceNameLen)
78 {
79 Uint64 key = 0;
80
81 key = (Uint64(classNameLen) << 48 ) |
82 (Uint64(className[0]) << 40 ) |
83 (Uint64(className[classNameLen-1]) << 32 ) |
84 (Uint64(nameSpaceNameLen) << 16 ) |
85 thilo.boehm 1.2 (Uint64(nameSpaceName[0]) << 8 ) |
86 Uint64(nameSpaceName[nameSpaceNameLen-1]);
87
88 return key;
89 }
90
91 inline Boolean SCMOClassCache::_lockEntry(Uint32 index)
92 {
93 // The lock is implemented as a spin loop, since the action to
94 // verify for the right cache entry is very short.
95
96 if ( _dying )
97 {
98 // The cache is going to be destroyed.
99 // The caller will never get the lock.
100 return false;
101 }
102
103 while ( true )
104 {
105 if ( _dying )
106 thilo.boehm 1.2 {
107 // The cache is going to be destroyed.
108 // The caller will never get the lock.
109 return false;
110 }
111
112 // If the lock counter not 1,an other caller is reading the entry.
113 if ( _theCache[index].lock.get() == 1 )
114 {
115 // Decrement the atomic lock counter and test if we do have lock:
116 // _theCache[index].lock == 0
117 if ( _theCache[index].lock.decAndTestIfZero() )
118 {
119 // We do have lock!
120 return true;
121 }
122 }
123 // I did not get the lock. So signal the scheduer to change the active
124 // thread to allow other threads to proceed. This also prevents from
125 // looping in a tight loop that causes a dead look due to the
126 // lock obtaining thread does not get any time ot finsh his work.
127 thilo.boehm 1.2 #ifdef PEGASUS_DEBUG
128 _contentionCount.inc();
129 #endif
130 Threads::yield();
131 }
132 return false;
133 }
134
135 inline Boolean SCMOClassCache::_sameSCMOClass(
136 const char* nsName,
137 Uint32 nsNameLen,
138 const char* className,
139 Uint32 classNameLen,
140 SCMOClass* theClass)
141 {
142 if (_equalNoCaseUTF8Strings(
143 theClass->cls.hdr->className,
144 theClass->cls.base,
145 className,
146 classNameLen))
147 {
148 thilo.boehm 1.2 return _equalNoCaseUTF8Strings(
149 theClass->cls.hdr->nameSpace,
150 theClass->cls.base,
151 nsName,
152 nsNameLen);
153 }
154
155 return false;
156 }
157
158 SCMOClass SCMOClassCache::_addClassToCache(
159 const char* nsName,
160 Uint32 nsNameLen,
161 const char* className,
162 Uint32 classNameLen,
163 Uint64 theKey)
164 {
165 WriteLock modifyLock(_modifyCacheLock);
166
167 if ( _dying )
168 {
169 thilo.boehm 1.2 // The cache is going to be destroyed.
170 return SCMOClass();
171 }
172
173 Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
174 Uint32 nextIndex = startIndex;
175 // The number of used entries is form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
176 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
177
178 // This constallation would cause an infitloop below.
179 // A miss read of global variables has happen
180 if (nextIndex > usedEntries)
181 {
182 // start from the beginning
183 startIndex = 0;
184 nextIndex = 0;
185 }
186
187 // Check the cache if the class was already added while waiting for the
188 // modifyLock.
189 //
190 thilo.boehm 1.2 // Note: The lock for each cache entry must not be obtained,
191 // because it is used to signal a modify operation, that some
192 // body is reading it. Due to we are the modify task, we know
193 // that we are reading the cache entries!
194 //
195 for (Uint32 i = 0; i < usedEntries; i++)
196 {
197 // Does the key match for the entry and the requested class ?
198 if (0 != _theCache[nextIndex].key &&
199 theKey == _theCache[nextIndex].key)
200 {
201 // To get sure we found the right class, compare name space
202 // and class name.
203 if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
204 _theCache[nextIndex].data))
205 {
206 // The entry was added while waiting for the modify lock.
207 // The modify lock is destroyed automaticaly !
208 #ifdef PEGASUS_DEBUG
209 _cacheReadHit++;
210 #endif
211 thilo.boehm 1.2 _lastSuccessIndex = nextIndex;
212 return SCMOClass(*_theCache[nextIndex].data);
213 }
214 }
215
216 // go to the next used entries.
217 nextIndex = (nextIndex + 1) % usedEntries;
218 }
219
220 PEGASUS_ASSERT(_resolveCallBack);
221
222 #ifdef PEGASUS_DEBUG
223 _cacheReadMiss++;
224 #endif
225
226 SCMOClass tmp = _resolveCallBack(
227 CIMNamespaceNameCast(String(nsName,nsNameLen)),
228 CIMNameCast(String(className,classNameLen)));
229
230 if (tmp.isEmpty())
231 {
232 thilo.boehm 1.2 // The requested class was not found !
233 // The modify lock is destroyed automaticaly !
234 return SCMOClass();
235 }
236
237 SCMOClass* scmoClass = new SCMOClass(tmp);
238
239 _lastWrittenIndex = (_lastWrittenIndex + 1)%PEGASUS_SCMO_CLASS_CACHE_SIZE;
240
241 // Ensure that nobody is reading the enty, so I can write.
242 if (_lockEntry(_lastWrittenIndex))
243 {
244 _theCache[_lastWrittenIndex].key = theKey;
245
246 // If the entry was reused, release old object form the cache.
247 if (0 != _theCache[_lastWrittenIndex].data )
248 {
249 #ifdef PEGASUS_DEBUG
250 _cacheRemoveLRU++;
251 #endif
252 delete _theCache[_lastWrittenIndex].data;
253 thilo.boehm 1.2 }
254
255 _theCache[_lastWrittenIndex].data = scmoClass;
256
257 if (_fillingLevel < PEGASUS_SCMO_CLASS_CACHE_SIZE)
258 {
259 _fillingLevel ++;
260 }
261
262 _lastSuccessIndex = _lastWrittenIndex;
263
264 _unlockEntry(_lastWrittenIndex);
265 }
266 else
267 {
268 // The cache is going to be destroyed.
269 // The lock can not be obtained.
270 delete scmoClass;
271 return SCMOClass();
272 }
273
274 thilo.boehm 1.2 // The modify lock is destroyed automaticaly !
275 return SCMOClass(*scmoClass);
276 }
277
278 SCMOClass SCMOClassCache::getSCMOClass(
279 const char* nsName,
280 Uint32 nsNameLen,
281 const char* className,
282 Uint32 classNameLen)
283 {
284 Uint64 theKey;
285
286 // Due to the _lastSuccessIndex may contain an invalid value,
287 // use the modulo to ensure it the index is in a valid range.
288 Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
289 Uint32 nextIndex = startIndex;
290 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
291 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
292
293 // This constallation would cause an infitloop below.
294 // A miss read of global variables has happen
295 thilo.boehm 1.2 if (nextIndex > usedEntries)
296 {
297 // start from the beginning
298 startIndex = 0;
299 nextIndex = 0;
300 }
301
302 if (nsName && className && nsNameLen && classNameLen)
303 {
304 theKey = _generateKey(className,classNameLen,nsName,nsNameLen);
305
306 // The counter i is never used as index.
307 // It is used to ensure to look through all used entries.
308 for (Uint32 i = 0; i < usedEntries; i++)
309 {
310 if(_lockEntry(nextIndex))
311 {
312 // does the key match for the entry and the requested class ?
313 if ( 0 != _theCache[nextIndex].key &&
314 theKey == _theCache[nextIndex].key)
315 {
316 thilo.boehm 1.2 // To get sure we found the right class, compare name space
317 // and class name.
318 if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
319 _theCache[nextIndex].data))
320 {
321 // Yes, we got it !
322 SCMOClass theClass(*_theCache[nextIndex].data);
323 _lastSuccessIndex = nextIndex;
324 #ifdef PEGASUS_DEBUG
325 _cacheReadHit++;
326 #endif
327 _unlockEntry(nextIndex);
328 return theClass;
329 }
330 }
331 // It was the wrong entry, go to the next.
332 _unlockEntry(nextIndex);
333 }
334 else
335 {
336 // The cache is going to be destroyed.
337 thilo.boehm 1.2 // The lock can not be obtained. Give up.
338 return SCMOClass();
339 }
340 // It was the wrong entry, go to the next used entry..
341 nextIndex = (nextIndex + 1) % usedEntries;
342
343 }
344
345 // If we end up here, the class is not in the cache !
346 // We have to get it from the repositroy and add it into the cache.
347 return _addClassToCache(nsName,nsNameLen,className,classNameLen,theKey);
348 }
349
350 return SCMOClass();
351 }
352
353 void SCMOClassCache::removeSCMOClass(
354 CIMNamespaceName cimNameSpace,
355 CIMName cimClassName)
356 {
357
358 thilo.boehm 1.2 if (cimClassName.isNull() || cimNameSpace.isNull())
359 {
360 return ;
361 }
362
363 CString nsName = cimNameSpace.getString().getCString();
364 Uint32 nsNameLen = strlen(nsName);
365 CString clsName = cimClassName.getString().getCString();
366 Uint32 clsNameLen = strlen(clsName);
367
368 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
369 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
370
371 Uint64 theKey = _generateKey(clsName,clsNameLen,nsName,nsNameLen);
372
373 // A straight forward loop through all used entries,
374 // ignoring the last success.
375 for (Uint32 i = 0; i < usedEntries; i++)
376 {
377 if(_lockEntry(i))
378 {
379 thilo.boehm 1.2 // does the key match for the entry and the requested class ?
380 if ( 0 != _theCache[i].key && theKey == _theCache[i].key)
381 {
382 // To get sure we found the right class, compare name space
383 // and class name.
384 if (_sameSCMOClass(nsName,nsNameLen,clsName,clsNameLen,
385 _theCache[i].data))
386 {
387 // Yes, we got it !
388 _theCache[i].key = 0;
389 delete _theCache[i].data;
390 _theCache[i].data = 0;
391 _unlockEntry(i);
392 return;
393 }
394 }
395 // It was the wrong entry, go to the next.
396 _unlockEntry(i);
397 }
398 else
399 {
400 thilo.boehm 1.2 // We do not get the lock, if the cache is going to be destroyed.
401 return;
402 }
403 }
404 }
405
406 void SCMOClassCache::clear()
407 {
408 WriteLock modifyLock(_modifyCacheLock);
409
410 if ( _dying )
411 {
412 // The cache is going to be destroyed.
413 return ;
414 }
415
416 // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
417 Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
418
419 // A straight forwar loop through all used entries,
420 // ignoring the last success.
421 thilo.boehm 1.2 for (Uint32 i = 0; i < usedEntries; i++)
422 {
423 if(_lockEntry(i))
424 {
425 _theCache[i].key = 0;
426 delete _theCache[i].data;
427 _theCache[i].data = 0;
428 _unlockEntry(i);
429 }
430 else
431 {
432 // We do not get the lock, if the cache is going to be destroyed.
433 return;
434 }
435 }
436 // Reset all controll data
437 _fillingLevel = 0;
438 _lastSuccessIndex = 0;
439 _lastWrittenIndex = PEGASUS_SCMO_CLASS_CACHE_SIZE-1;
440
441
442 thilo.boehm 1.2 }
443 #ifdef PEGASUS_DEBUG
444 void SCMOClassCache::DisplayCacheStatistics()
445 {
446 PEGASUS_STD(cout) << "SCMOClass Cache Statistics:" <<
447 PEGASUS_STD(endl);
448 PEGASUS_STD(cout) << " Size (current/max): " <<
449 _fillingLevel << "/" << PEGASUS_SCMO_CLASS_CACHE_SIZE <<
450 PEGASUS_STD(endl);
451 PEGASUS_STD(cout) << " Requests satisfied from cache: " <<
452 _cacheReadHit << PEGASUS_STD(endl);
453 PEGASUS_STD(cout) << " Requests *not* satisfied from cache: " <<
454 _cacheReadMiss << " (implies write to cache)" << PEGASUS_STD(endl);
455 PEGASUS_STD(cout) <<
456 " Cache entries \"aged out\" due to cache size constraints: " <<
457 _cacheRemoveLRU << PEGASUS_STD(endl);
458 PEGASUS_STD(cout) << " Number of lock contentions: " <<
459 _contentionCount.get() << PEGASUS_STD(endl);
460
461 }
462 #endif
463 thilo.boehm 1.2
464
465 #else // PEGASUS_USE_SCMO_CLASS_CACHE
466 SCMOClass SCMOClassCache::getSCMOClass(
467 const char* nsName,
468 Uint32 nsNameLen,
469 const char* className,
470 Uint32 classNameLen)
471 {
472 if (nsName && className && nsNameLen && classNameLen)
473 {
474
475 PEGASUS_ASSERT(_resolveCallBack);
476
477
478 SCMOClass tmp = _resolveCallBack(
479 CIMNamespaceNameCast(String(nsName,nsNameLen)),
480 CIMNameCast(String(className,classNameLen)));
481
482 if (tmp->isEpmpty())
483 {
484 thilo.boehm 1.2 // The requested class was not found !
485 // The modify lock is destroyed automaticaly !
486 return SCMOClass();
487 }
488
489 return SCMOClass(tmp);
490 }
491
492 return SCMOClass();
493
494 }
495
496 void SCMOClassCache::removeSCMOClass(
497 CIMNamespaceName cimNameSpace,
498 CIMName cimClassName)
499 {
500 }
501
502
503 void SCMOClassCache::clear()
504 {
505 thilo.boehm 1.2 }
506
507 # ifdef PEGASUS_DEBUG
508 void SCMOClassCache::DisplayCacheStatistics(){}
509 # endif
510
511 #endif
512 PEGASUS_NAMESPACE_END
|