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

Diff for /pegasus/src/Pegasus/Common/SCMOClassCache.cpp between version 1.1 and 1.1.2.8

version 1.1, 2009/09/23 09:27:42 version 1.1.2.8, 2009/12/04 10:44:45
Line 0 
Line 1 
   //%LICENSE////////////////////////////////////////////////////////////////
   //
   // Licensed to The Open Group (TOG) under one or more contributor license
   // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
   // this work for additional information regarding copyright ownership.
   // Each contributor licenses this file to you under the OpenPegasus Open
   // Source License; you may not use this file except in compliance with the
   // License.
   //
   // Permission is hereby granted, free of charge, to any person obtaining a
   // copy of this software and associated documentation files (the "Software"),
   // to deal in the Software without restriction, including without limitation
   // the rights to use, copy, modify, merge, publish, distribute, sublicense,
   // and/or sell copies of the Software, and to permit persons to whom the
   // Software is furnished to do so, subject to the following conditions:
   //
   // The above copyright notice and this permission notice shall be included
   // in all copies or substantial portions of the Software.
   //
   // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   //
   //////////////////////////////////////////////////////////////////////////
   //
   //%/////////////////////////////////////////////////////////////////////////////
   
   
   #include <Pegasus/Common/SCMOClassCache.h>
   #include <Pegasus/Common/CIMNameCast.h>
   
   PEGASUS_NAMESPACE_BEGIN
   
   PEGASUS_USING_STD;
   
   SCMOClassCache* SCMOClassCache::_theInstance = 0;
   
   void SCMOClassCache::destroy()
   {
       delete _theInstance;
       _theInstance=0;
   }
   
   SCMOClassCache* SCMOClassCache::getInstance()
   {
       if(_theInstance == NULL)
       {
           _theInstance = new SCMOClassCache();
       }
       return _theInstance;
   }
   
   #ifdef PEGASUS_USE_SCMO_CLASS_CACHE
   
   SCMOClassCache::~SCMOClassCache()
   {
       // Signal to all callers and work in progress that the SMOClassCache
       // will be destroyed soon.
       // As from now, no other caller can get the the lock. They are blocked out.
       _dying = true;
   
       // Cleanup the class cache
       for (Uint32 i = 0 ; i < PEGASUS_SCMO_CLASS_CACHE_SIZE; i++)
       {
           delete _theCache[i].data;
       }
   }
   
   Uint64 SCMOClassCache::_generateKey(
       const char* className,
       Uint32 classNameLen,
       const char* nameSpaceName,
       Uint32 nameSpaceNameLen)
   {
       Uint64 key = 0;
   
       key  =  (Uint64(classNameLen) << 48 ) |
               (Uint64(className[0]) << 40 ) |
               (Uint64(className[classNameLen-1]) << 32 ) |
               (Uint64(nameSpaceNameLen) << 16 ) |
               (Uint64(nameSpaceName[0]) << 8 ) |
               Uint64(nameSpaceName[nameSpaceNameLen-1]);
   
       return key;
   }
   
   inline Boolean SCMOClassCache::_lockEntry(Uint32 index)
   {
       // The lock is implemented as a spin loop, since the action to
       // verify for the right cache entry is very short.
   
       if ( _dying )
       {
           // The cache is going to be destroyed.
           // The caller will never get the lock.
           return false;
       }
   
       while ( true )
       {
           if ( _dying )
           {
               // The cache is going to be destroyed.
               // The caller will never get the lock.
               return false;
           }
   
           // If the lock counter not 1,an other caller is reading the entry.
           if ( _theCache[index].lock.get() == 1 )
           {
               // Decrement the atomic lock counter and test if we do have lock:
               // _theCache[index].lock == 0
               if ( _theCache[index].lock.decAndTestIfZero() )
               {
                   // We do have lock!
                   return true;
               }
           }
           // I did not get the lock. So signal the scheduer to change the active
           // thread to allow other threads to proceed. This also prevents from
           // looping in a tight loop that causes a dead look due to the
           // lock obtaining thread does not get any time ot finsh his work.
   #ifdef PEGASUS_DEBUG
           _contentionCount.inc();
   #endif
           Threads::yield();
       }
       return false;
   }
   
   inline Boolean SCMOClassCache::_sameSCMOClass(
           const char* nsName,
           Uint32 nsNameLen,
           const char* className,
           Uint32 classNameLen,
           SCMOClass* theClass)
   {
       if (_equalNoCaseUTF8Strings(
               theClass->cls.hdr->className,
               theClass->cls.base,
               className,
               classNameLen))
       {
           return _equalNoCaseUTF8Strings(
                   theClass->cls.hdr->nameSpace,
                   theClass->cls.base,
                   nsName,
                   nsNameLen);
       }
   
       return false;
   }
   
   SCMOClass SCMOClassCache::_addClassToCache(
           const char* nsName,
           Uint32 nsNameLen,
           const char* className,
           Uint32 classNameLen,
           Uint64 theKey)
   {
       WriteLock modifyLock(_modifyCacheLock);
   
       if ( _dying )
       {
           // The cache is going to be destroyed.
           return SCMOClass();
       }
   
       Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
       Uint32 nextIndex = startIndex;
       // The number of used entries is form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
       Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
   
       // This constallation would cause an infitloop below.
       // A miss read of global variables has happen
       if (nextIndex > usedEntries)
       {
           // start from the beginning
           startIndex = 0;
           nextIndex = 0;
       }
   
       // Check the cache if the class was already added while waiting for the
       // modifyLock.
       //
       // Note: The lock for each cache entry must not be obtained,
       //       because it is used to signal a modify operation, that some
       //       body is reading it. Due to we are the modify task, we know
       //       that we are reading the cache entries!
       //
       for (Uint32 i = 0; i < usedEntries; i++)
       {
           // Does the key match for the entry and the requested class ?
           if (0 != _theCache[nextIndex].key &&
               theKey == _theCache[nextIndex].key)
           {
               // To get sure we found the right class, compare name space
               // and class name.
               if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
                                  _theCache[nextIndex].data))
               {
                   // The entry was added while waiting for the modify lock.
                   // The modify lock is destroyed automaticaly !
   #ifdef PEGASUS_DEBUG
                   _cacheReadHit++;
   #endif
                   _lastSuccessIndex = nextIndex;
                   return SCMOClass(*_theCache[nextIndex].data);
               }
           }
   
           // go to the next used entries.
           nextIndex = (nextIndex + 1) % usedEntries;
       }
   
       PEGASUS_ASSERT(_resolveCallBack);
   
   #ifdef PEGASUS_DEBUG
       _cacheReadMiss++;
   #endif
   
       SCMOClass tmp = _resolveCallBack(
            CIMNamespaceNameCast(String(nsName,nsNameLen)),
            CIMNameCast(String(className,classNameLen)));
   
       if (tmp.isEmpty())
       {
            // The requested class was not found !
            // The modify lock is destroyed automaticaly !
            return SCMOClass();
       }
   
       SCMOClass* scmoClass = new SCMOClass(tmp);
   
       _lastWrittenIndex = (_lastWrittenIndex + 1)%PEGASUS_SCMO_CLASS_CACHE_SIZE;
   
       // Ensure that nobody is reading the enty, so I can write.
       if (_lockEntry(_lastWrittenIndex))
       {
           _theCache[_lastWrittenIndex].key = theKey;
   
           // If the entry was reused, release old object form the cache.
           if (0 != _theCache[_lastWrittenIndex].data )
           {
   #ifdef PEGASUS_DEBUG
               _cacheRemoveLRU++;
   #endif
               delete _theCache[_lastWrittenIndex].data;
           }
   
           _theCache[_lastWrittenIndex].data = scmoClass;
   
           if (_fillingLevel  < PEGASUS_SCMO_CLASS_CACHE_SIZE)
           {
               _fillingLevel ++;
           }
   
           _lastSuccessIndex = _lastWrittenIndex;
   
           _unlockEntry(_lastWrittenIndex);
       }
       else
       {
           // The cache is going to be destroyed.
           // The lock can not be obtained.
           delete scmoClass;
           return SCMOClass();
       }
   
       // The modify lock is destroyed automaticaly !
       return SCMOClass(*scmoClass);
   }
   
   SCMOClass SCMOClassCache::getSCMOClass(
           const char* nsName,
           Uint32 nsNameLen,
           const char* className,
           Uint32 classNameLen)
   {
       Uint64 theKey;
   
       // Due to the _lastSuccessIndex may contain an invalid value,
       // use the modulo to ensure it the index is in a valid range.
       Uint32 startIndex =_lastSuccessIndex % PEGASUS_SCMO_CLASS_CACHE_SIZE;
       Uint32 nextIndex = startIndex;
       // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
       Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
   
       // This constallation would cause an infitloop below.
       // A miss read of global variables has happen
       if (nextIndex > usedEntries)
       {
           // start from the beginning
           startIndex = 0;
           nextIndex = 0;
       }
   
       if (nsName && className && nsNameLen && classNameLen)
       {
         theKey = _generateKey(className,classNameLen,nsName,nsNameLen);
   
         // The counter i is never used as index.
         // It is used to ensure to look through all used entries.
         for (Uint32 i = 0; i < usedEntries; i++)
         {
             if(_lockEntry(nextIndex))
             {
                 // does the key match for the entry and the requested class ?
                 if ( 0 != _theCache[nextIndex].key &&
                     theKey == _theCache[nextIndex].key)
                 {
                     // To get sure we found the right class, compare name space
                     // and class name.
                     if (_sameSCMOClass(nsName,nsNameLen,className,classNameLen,
                                        _theCache[nextIndex].data))
                     {
                         // Yes, we got it !
                         SCMOClass theClass(*_theCache[nextIndex].data);
                         _lastSuccessIndex = nextIndex;
   #ifdef PEGASUS_DEBUG
                          _cacheReadHit++;
   #endif
                         _unlockEntry(nextIndex);
                         return theClass;
                     }
                 }
                 // It was the wrong entry, go to the next.
                 _unlockEntry(nextIndex);
             }
             else
             {
                 // The cache is going to be destroyed.
                 // The lock can not be obtained. Give up.
                 return SCMOClass();
             }
             // It was the wrong entry, go to the next used entry..
             nextIndex = (nextIndex + 1) % usedEntries;
   
         }
   
         // If we end up here, the class is not in the cache !
         // We have to get it from the repositroy and add it into the cache.
         return _addClassToCache(nsName,nsNameLen,className,classNameLen,theKey);
       }
   
       return SCMOClass();
   }
   
   void SCMOClassCache::removeSCMOClass(
       CIMNamespaceName cimNameSpace,
       CIMName cimClassName)
   {
   
       if (cimClassName.isNull() || cimNameSpace.isNull())
       {
           return ;
       }
   
      CString nsName = cimNameSpace.getString().getCString();
      Uint32 nsNameLen = strlen(nsName);
      CString clsName = cimClassName.getString().getCString();
      Uint32 clsNameLen = strlen(clsName);
   
      // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
      Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
   
      Uint64  theKey = _generateKey(clsName,clsNameLen,nsName,nsNameLen);
   
      // A straight forward loop through all used entries,
      // ignoring the last success.
      for (Uint32 i = 0; i < usedEntries; i++)
      {
          if(_lockEntry(i))
          {
              // does the key match for the entry and the requested class ?
              if ( 0 != _theCache[i].key && theKey == _theCache[i].key)
              {
                  // To get sure we found the right class, compare name space
                  // and class name.
                  if (_sameSCMOClass(nsName,nsNameLen,clsName,clsNameLen,
                                     _theCache[i].data))
                  {
                      // Yes, we got it !
                      _theCache[i].key = 0;
                      delete _theCache[i].data;
                      _theCache[i].data = 0;
                      _unlockEntry(i);
                      return;
                  }
              }
              // It was the wrong entry, go to the next.
              _unlockEntry(i);
          }
          else
          {
              // We do not get the lock, if the cache is going to be destroyed.
              return;
          }
      }
   }
   
   void SCMOClassCache::clear()
   {
       WriteLock modifyLock(_modifyCacheLock);
   
       if ( _dying )
       {
           // The cache is going to be destroyed.
           return ;
       }
   
       // The number of used entries form 0 to PEGASUS_SCMO_CLASS_CACHE_SIZE
       Uint32 usedEntries = _fillingLevel % (PEGASUS_SCMO_CLASS_CACHE_SIZE + 1);
   
       // A straight forwar loop through all used entries,
       // ignoring the last success.
       for (Uint32 i = 0; i < usedEntries; i++)
       {
           if(_lockEntry(i))
           {
               _theCache[i].key = 0;
               delete _theCache[i].data;
               _theCache[i].data = 0;
               _unlockEntry(i);
           }
           else
           {
               // We do not get the lock, if the cache is going to be destroyed.
               return;
           }
       }
       // Reset all controll data
       _fillingLevel = 0;
       _lastSuccessIndex = 0;
       _lastWrittenIndex = PEGASUS_SCMO_CLASS_CACHE_SIZE-1;
   
   
   }
   #ifdef PEGASUS_DEBUG
   void SCMOClassCache::DisplayCacheStatistics()
   {
       PEGASUS_STD(cout) << "SCMOClass Cache Statistics:" <<
           PEGASUS_STD(endl);
       PEGASUS_STD(cout) << "  Size (current/max): " <<
           _fillingLevel << "/" << PEGASUS_SCMO_CLASS_CACHE_SIZE <<
           PEGASUS_STD(endl);
       PEGASUS_STD(cout) << "  Requests satisfied from cache: " <<
           _cacheReadHit << PEGASUS_STD(endl);
       PEGASUS_STD(cout) << "  Requests *not* satisfied from cache: " <<
           _cacheReadMiss << " (implies write to cache)" << PEGASUS_STD(endl);
       PEGASUS_STD(cout) <<
           "  Cache entries \"aged out\" due to cache size constraints: " <<
           _cacheRemoveLRU << PEGASUS_STD(endl);
       PEGASUS_STD(cout) << "  Number of lock contentions: " <<
           _contentionCount.get() << PEGASUS_STD(endl);
   
   }
   #endif
   
   
   #else // PEGASUS_USE_SCMO_CLASS_CACHE
   SCMOClass SCMOClassCache::getSCMOClass(
           const char* nsName,
           Uint32 nsNameLen,
           const char* className,
           Uint32 classNameLen)
   {
       if (nsName && className && nsNameLen && classNameLen)
       {
   
            PEGASUS_ASSERT(_resolveCallBack);
   
   
             SCMOClass tmp = _resolveCallBack(
                 CIMNamespaceNameCast(String(nsName,nsNameLen)),
                 CIMNameCast(String(className,classNameLen)));
   
             if (tmp->isEpmpty())
             {
                  // The requested class was not found !
                  // The modify lock is destroyed automaticaly !
                  return SCMOClass();
             }
   
             return SCMOClass(tmp);
       }
   
       return SCMOClass();
   
   }
   
   void SCMOClassCache::removeSCMOClass(
       CIMNamespaceName cimNameSpace,
       CIMName cimClassName)
   {
   }
   
   
   void SCMOClassCache::clear()
   {
   }
   
   #  ifdef PEGASUS_DEBUG
   void SCMOClassCache::DisplayCacheStatistics(){}
   #  endif
   
   #endif
   PEGASUS_NAMESPACE_END


Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.8

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2