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