(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 marek       1.5 // 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