(file) Return to SCMOClassCache.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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 karl        1.3.4.1 // This code implements part of PEP#348 - The CMPI infrastructure using SCMO
 31                     // (Single Chunk Memory Objects).
 32                     // The design document can be found on the OpenPegasus website openpegasus.org
 33                     // at https://collaboration.opengroup.org/pegasus/pp/documents/21210/PEP_348.pdf
 34                     //
 35 thilo.boehm 1.2     //%/////////////////////////////////////////////////////////////////////////////
 36                     
 37                     
 38                     #include <Pegasus/Common/SCMOClassCache.h>
 39                     #include <Pegasus/Common/CIMNameCast.h>
 40                     
 41                     PEGASUS_NAMESPACE_BEGIN
 42                     
 43                     PEGASUS_USING_STD;
 44                     
 45                     SCMOClassCache* SCMOClassCache::_theInstance = 0;
 46                     
 47                     void SCMOClassCache::destroy()
 48                     {
 49                         delete _theInstance;
 50                         _theInstance=0;
 51                     }
 52                     
 53                     SCMOClassCache* SCMOClassCache::getInstance()
 54                     {
 55                         if(_theInstance == NULL)
 56 thilo.boehm 1.2         {
 57                             _theInstance = new SCMOClassCache();
 58                         }
 59                         return _theInstance;
 60                     }
 61                     
 62                     SCMOClassCache::~SCMOClassCache()
 63                     {
 64                         // Signal to all callers and work in progress that the SMOClassCache
 65                         // will be destroyed soon.
 66                         // As from now, no other caller can get the the lock. They are blocked out.
 67                         _dying = true;
 68                     
 69                         // Cleanup the class cache
 70                         for (Uint32 i = 0 ; i < PEGASUS_SCMO_CLASS_CACHE_SIZE; i++)
 71                         {
 72                             delete _theCache[i].data;
 73                         }
 74                     }
 75                     
 76                     Uint64 SCMOClassCache::_generateKey(
 77 thilo.boehm 1.2         const char* className,
 78                         Uint32 classNameLen,
 79                         const char* nameSpaceName,
 80                         Uint32 nameSpaceNameLen)
 81                     {
 82                         Uint64 key = 0;
 83                     
 84                         key  =  (Uint64(classNameLen) << 48 ) |
 85                                 (Uint64(className[0]) << 40 ) |
 86                                 (Uint64(className[classNameLen-1]) << 32 ) |
 87                                 (Uint64(nameSpaceNameLen) << 16 ) |
 88                                 (Uint64(nameSpaceName[0]) << 8 ) |
 89                                 Uint64(nameSpaceName[nameSpaceNameLen-1]);
 90                     
 91                         return key;
 92                     }
 93                     
 94                     inline Boolean SCMOClassCache::_lockEntry(Uint32 index)
 95                     {
 96                         // The lock is implemented as a spin loop, since the action to
 97                         // verify for the right cache entry is very short.
 98 thilo.boehm 1.2     
 99                         if ( _dying )
100                         {
101                             // The cache is going to be destroyed.
102                             // The caller will never get the lock.
103                             return false;
104                         }
105                     
106                         while ( true )
107                         {
108                             if ( _dying )
109                             {
110                                 // The cache is going to be destroyed.
111                                 // The caller will never get the lock.
112 sahana.prabhakar 1.3                 break;
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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2