SBcacheManager.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:23k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  23. #include "SBcacheInternal.h"
  24. #include "SBcacheManager.hpp"    // for this class
  25. #include <list>                  // for STL list template class
  26. #include <vector>                  // for STL list template class
  27. #include <algorithm>
  28. #include <limits.h>              // for ULONG_MAX
  29. #if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2)
  30. #include <strstream>
  31. #else
  32. #include <sstream>               // for basic_ostringstream( )
  33. #endif
  34. static const int CACHE_REF_COUNT_MUTEX_POOL_SIZE = 256;
  35. static const int CACHE_MAX_DIR_ENTRIES = 256;
  36. static const char CACHE_ENTRY_FILE_EXTENSION[] = ".sbc";
  37. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  38. // Shut down the manager
  39. SBcacheManager::~SBcacheManager( )
  40. {
  41.   if ( _cacheDir.length( ) > 0 ) {
  42.     // Lock to be paranoid, makes sure everyone else is done
  43.     if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  44.       Error (110, L"%s%s", L"mutex", L"entry table mutex");
  45.     } else {
  46.       // Write out the index file
  47.       WriteIndex( );
  48.       // Clear the cache entries
  49.       _entryTable.erase (_entryTable.begin( ), _entryTable.end( ));
  50.       _entryLRUList.erase(_entryLRUList.begin(), _entryLRUList.end());
  51.       _curSizeBytes.Reset (0);
  52.       // Clear the directory name
  53.       _cacheDir = "";
  54.       if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS )
  55. Error (111, L"%s%s", L"mutex", L"entry table mutex");
  56.     }
  57.   }
  58. }
  59. // Create the manager
  60. VXIcacheResult SBcacheManager::Create(const SBcacheNString &cacheDir,
  61.       VXIulong              cacheMaxSizeBytes,
  62.       VXIulong              entryMaxSizeBytes,
  63.       VXIulong              entryExpTimeSec,
  64.       VXIbool               unlockEntries,
  65.                                       VXIulong              cacheLowWaterBytes)
  66. {
  67.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  68.   // Avoid double initialization
  69.   if ( _cacheDir.length( ) > 0 ) {
  70.     Error (112, NULL);
  71.     rc = VXIcache_RESULT_FATAL_ERROR;
  72.   }
  73.   // Create the path sequence number
  74.   if (( rc == VXIcache_RESULT_SUCCESS ) &&
  75.       ( _pathSeqNum.Create( ) != VXItrd_RESULT_SUCCESS )) {
  76.     Error (109, L"%s%s", L"mutex", L"path seq num");
  77.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  78.   }
  79.   // Create the entry table mutex
  80.   if (( rc == VXIcache_RESULT_SUCCESS ) &&
  81.       ( _entryTableMutex.Create(L"SBcacheManager entry table mutex") !=
  82. VXItrd_RESULT_SUCCESS )) {
  83.     Error (109, L"%s%s", L"mutex", L"entry table mutex");
  84.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  85.   }
  86.   // Create the mutex pool
  87.   if (( rc == VXIcache_RESULT_SUCCESS ) &&
  88.       ( _refCntMutexPool.Create(L"SBcacheManager refCnt mutex pool",
  89. CACHE_REF_COUNT_MUTEX_POOL_SIZE) )) {
  90.     Error (109, L"%s%s", L"mutex", L"entry table mutex");
  91.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  92.   }
  93.   // Create the cache size
  94.   if (( rc == VXIcache_RESULT_SUCCESS ) &&
  95.       ( _curSizeBytes.Create( ) != VXItrd_RESULT_SUCCESS )) {
  96.     Error (109, L"%s%s", L"mutex", L"cache size mutex");
  97.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  98.   }
  99.   // Create the cache directory if required
  100.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  101.     SBcacheStatInfo statInfo;
  102.     if ( SBcacheStat (cacheDir.c_str( ), &statInfo) ) {
  103.       // Exists, make sure it is a file
  104.       if ( ! SBcacheIsDir(statInfo) ) {
  105. Error (113, L"%s%S", L"cacheDirectory", cacheDir.c_str( ));
  106. rc = VXIcache_RESULT_FATAL_ERROR;
  107.       } else {
  108. // Load the cache index file
  109. rc = ReadIndex (cacheDir);
  110.       }
  111.     } else if ( ! SBcacheMkdir (cacheDir.c_str( )) ) {
  112.       Error (114, L"%s%S", L"cacheDirectory", cacheDir.c_str( ));
  113.       rc = VXIcache_RESULT_FATAL_ERROR;
  114.     }
  115.   }
  116.   // Update data members
  117.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  118.     _cacheDir = cacheDir;
  119.     _maxSizeBytes = cacheMaxSizeBytes;
  120.     _entryMaxSizeBytes = entryMaxSizeBytes;
  121.     _lowWaterBytes = cacheLowWaterBytes;
  122.   }
  123.   _entryReserve = 0;
  124.   ReserveEntries(0); // Disable, for now.
  125.   Diag (SBCACHE_MGR_TAGID, L"Create", L"rc = %d", rc);
  126.   return rc;
  127. }
  128. // NOTE: This is disabled, see above, until SPR is fixed or NPFed.
  129. //
  130. // Interesting trick, we want to reserve a certain amount of memory for N
  131. // entries, but we only have an estimate as to the size of an entry, and we
  132. // can't make all the code use a special allocator.  
  133. // Solution: Make an estimate(E) of how much an entry will take up, and
  134. // grab N * E bytes from the general allocator.  Whenever we add an entry,
  135. // we give back E bytes (if we can), whenver we remove an entry we take E
  136. // bytes (unless we hit the maximum preallocation).  
  137. //
  138. void SBcacheManager::ReserveEntries(int nentries)
  139. {
  140.   for (int i = 0; i < nentries; ++i) {
  141.     SBcacheEntryEstimate* es = new SBcacheEntryEstimate();
  142.     es->next = _entryReserve;
  143.     _entryReserve = es;
  144.   }
  145.   _entriesReserved = nentries;
  146.   _maxEntriesReserved = nentries;
  147. }
  148. void SBcacheManager::EntryAdded()
  149. {
  150.   if (_entriesReserved > 0) {
  151.     SBcacheEntryEstimate* es = _entryReserve;
  152.     _entryReserve = es->next;
  153.     delete es;
  154.     _entriesReserved--;
  155.   } else {
  156.     static int once = 1;
  157.     if (once) {
  158.       once = 0;
  159.     }
  160.   }
  161. }
  162. void SBcacheManager::EntryRemoved()
  163. {
  164.   if (_maxEntriesReserved > _entriesReserved) {
  165.     SBcacheEntryEstimate* es = new SBcacheEntryEstimate();
  166.     es->next = _entryReserve;
  167.     _entryReserve = es;
  168.     _entriesReserved++;
  169.   }
  170. }
  171. // Synchronized table and LRU list
  172. //
  173. bool SBcacheManager::InsertEntry(SBcacheEntry& entry)
  174. {
  175.   SBcacheEntryTable::value_type tableEntry (entry.GetKey(), entry);
  176.   if ( ! _entryTable.insert (tableEntry).second )
  177.     return false;
  178.   _entryLRUList.push_back(entry);
  179.   EntryAdded();
  180.   return true;
  181. }
  182. void SBcacheManager::RemoveEntry(const SBcacheEntry& entry)
  183. {
  184.   SBcacheEntryTable::iterator te = _entryTable.find(entry.GetKey());
  185.   _entryTable.erase(te);
  186.   SBcacheEntryList::iterator vi = _entryLRUList.begin();
  187.   for (; vi != _entryLRUList.end(); ++vi)
  188.     if (entry.Equivalent(*vi)) {
  189.       _entryLRUList.erase(vi);
  190.       break;
  191.     }
  192.   EntryRemoved();
  193. }
  194. void SBcacheManager::TouchEntry(const SBcacheEntry& entry)
  195. {
  196.   SBcacheEntryList::iterator vi = _entryLRUList.begin();
  197.   for (; vi != _entryLRUList.end(); ++vi)
  198.     if (entry.Equivalent(*vi)) {
  199.       _entryLRUList.erase(vi);
  200.       _entryLRUList.push_back(entry);
  201.       break;
  202.     }
  203. }
  204. //#######################################################################
  205. // Note about locking protocol.  THere are three locks in this code:
  206. //   A. The entrytable lock (_entryTableMutex)
  207. //   B. a lock per entry  (GetSizeBytes, Open, Close)
  208. //   C. a lock of _curSizeBytes (atomic operations)
  209. // Currently, both locks A & C are held inside of lock B because an open
  210. // obtains a lock and holds it until the entry is closed.  Therefore,
  211. // a B lock must never be obtained while an A or C lock is held!
  212. //#######################################################################
  213. // Open an entry
  214. VXIcacheResult SBcacheManager::Open(VXIlogInterface       *log,
  215.     const SBcacheString   &moduleName,
  216.     const SBcacheKey      &key,
  217.     VXIcacheOpenMode       mode,
  218.     VXIint32               flags,
  219.     const VXIMap          *properties,
  220.     VXIMap                *streamInfo,
  221.     VXIcacheStream       **stream)
  222. {
  223.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  224.   // Big loop where we attempt to open and re-open the cache entry for
  225.   // as long as we get recoverable errors
  226.   VXIcacheOpenMode finalMode;
  227.   do {
  228.     finalMode = mode;
  229.     rc = VXIcache_RESULT_SUCCESS;
  230.     if ( _entryTableMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) {
  231.       Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
  232.       return VXIcache_RESULT_SYSTEM_ERROR;
  233.     }
  234.     // Find the entry and open it, only need read permission
  235.     bool entryOpened = false;
  236.     SBcacheEntry entry;
  237.     SBcacheEntryTable::iterator vi = _entryTable.find (key);
  238.     if ( vi == _entryTable.end( ) ) {
  239.       rc = VXIcache_RESULT_NOT_FOUND;
  240.     } else {
  241.       entry = (*vi).second;
  242.       finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode);
  243.     }
  244.     if ( _entryTableMutex.EndRead( ) != VXItrd_RESULT_SUCCESS ) {
  245.       Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
  246.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  247.     }
  248.     // For write and read/create mode, create the entry if not found
  249.     if (( rc == VXIcache_RESULT_NOT_FOUND ) && ( mode != CACHE_MODE_READ )) {
  250.       rc = VXIcache_RESULT_SUCCESS;
  251.       // Get write permission
  252.       if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  253. Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
  254. rc = VXIcache_RESULT_SYSTEM_ERROR;
  255.       } else {
  256. // Try to find the entry again, it may have been created by now
  257. vi = _entryTable.find (key);
  258. if ( vi != _entryTable.end( ) ) {
  259.   // Found it this time
  260.   entry = (*vi).second;
  261.   finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode);
  262. } else {
  263.   // Create and open the entry for write
  264.   rc = entry.Create (GetLog( ), GetDiagBase( ),
  265.      _refCntMutexPool.GetMutex( ));
  266.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  267.     finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_WRITE :
  268.  mode);
  269.             // Note entry lock obtained while entrytable lock is held! We
  270.             // can get away with this, because the lock isn't visible to
  271.             // anyone else yet.
  272.     rc = entry.Open (log, moduleName, key,
  273.      GetNewEntryPath (moduleName, key),
  274.      finalMode, flags, _entryMaxSizeBytes, properties,
  275.      streamInfo, stream);
  276.   }
  277.   // Insert the entry
  278.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  279.     entryOpened = true;
  280.     SBcacheEntryTable::value_type tableEntry (key, entry);
  281.     if ( !InsertEntry(entry)) {
  282.       Error (log, 100, NULL);
  283.       (*stream)->Close (true);
  284.       *stream = NULL;
  285.       rc = VXIcache_RESULT_OUT_OF_MEMORY;
  286.     } 
  287.   }
  288. }
  289. if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  290.   Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
  291.   rc = VXIcache_RESULT_SYSTEM_ERROR;
  292. }
  293.       }
  294.     }
  295.     // Open pre-existing entry. Note that this may return
  296.     // VXIcache_RESULT_FAILURE in some cases where we then need to
  297.     // retry the entire process of opening the entry -- that occurs
  298.     // when a writer opens the entry, we attempt to open for read
  299.     // access here before the writer finishes writing the entry, then
  300.     // the writer invalidates the entry on us. When that happens, if
  301.     // we're attempting MODE_READ_CREATE we want to get that invalid
  302.     // entry out of the table and create the entry ourselves returning
  303.     // in WRITE mode, for MODE_READ we just want to see if another
  304.     // writer has created a new entry that is valid for us to use
  305.     // otherwise we bail out with the normal RESULT_NOT_FOUND.
  306.     if (( rc == VXIcache_RESULT_SUCCESS ) && ( ! entryOpened )) {
  307.       // If this is a write over an existing entry, wipe the previous entry
  308.       // accounting from the cache.
  309.       if (finalMode == CACHE_MODE_WRITE)
  310.         _curSizeBytes.Decrement(entry.GetSizeBytes(false));
  311.       rc = entry.Open (log, moduleName, key, entry.GetPath( ), finalMode,
  312.        flags, _entryMaxSizeBytes, properties, streamInfo,
  313.        stream);
  314.       // Don't let a corrupt entry persist
  315.       if (( rc != VXIcache_RESULT_SUCCESS ) &&
  316.   ( rc != VXIcache_RESULT_FAILURE ))
  317. Delete (log, key);
  318.     }
  319.     // Accessed, so move it to the top of the LRU list
  320.     if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  321.       Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
  322.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  323.     } else {
  324.       if (rc == VXIcache_RESULT_SUCCESS)
  325.         TouchEntry(entry);
  326.       if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  327.         Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
  328.         rc = VXIcache_RESULT_SYSTEM_ERROR;
  329.       }
  330.     }
  331.   } while ( rc == VXIcache_RESULT_FAILURE );
  332.   // Finish up returning the stream information
  333.   if (( rc == VXIcache_RESULT_SUCCESS ) && ( streamInfo ) &&
  334.       ( VXIMapSetProperty (streamInfo, CACHE_INFO_FINAL_KEY,
  335.    (VXIValue *) VXIStringCreate(key.c_str( ))) !=
  336. VXIvalue_RESULT_SUCCESS )) {
  337.     Error (log, 100, NULL);
  338.     (*stream)->Close (true);
  339.     *stream = NULL;
  340.     rc = VXIcache_RESULT_OUT_OF_MEMORY;
  341.   }
  342.   if (( rc == VXIcache_RESULT_SUCCESS ) &&
  343.       ( mode == CACHE_MODE_READ_CREATE ) && ( finalMode == CACHE_MODE_WRITE ))
  344.     rc = VXIcache_RESULT_ENTRY_CREATED;
  345.   // Maybe do cleanup, ignore all but fatal errors
  346.   VXIcacheResult rc2 = Cleanup (false, key);
  347.   if ( rc2 < VXIcache_RESULT_SUCCESS ) {
  348.     (*stream)->Close (true);
  349.     *stream = NULL;
  350.     rc = rc2;
  351.   }
  352.   Diag (log, SBCACHE_MGR_TAGID, L"Open", L"%s: rc = %d", key.c_str( ), rc);
  353.   return rc;
  354. }
  355. // Notification of data writes
  356. VXIcacheResult
  357. SBcacheManager::WriteNotification (VXIlogInterface     *log,
  358.    const SBcacheString &moduleName,
  359.    VXIulong             nwritten,
  360.                                    const SBcacheKey    &key)
  361. {
  362.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  363.   // moduleName is reserved for future use, may want to allow
  364.   // configuring the cache with specific cache allocations on a
  365.   // per-module basis
  366.   // Note that _curSizeBytes is a thread-safe object, intentionally
  367.   // ignore cleanup errors unless fatal
  368.   if ( _curSizeBytes.IncrementTest (nwritten, _maxSizeBytes) > 0 ) {
  369.     VXIcacheResult rc2 = Cleanup (true, key);
  370.     if ( rc2 < VXIcache_RESULT_SUCCESS )
  371.       rc = rc2;
  372.   }
  373.   return rc;
  374. }
  375. // Unlock an entry
  376. VXIcacheResult SBcacheManager::Unlock(VXIlogInterface   *log,
  377.       const SBcacheKey  &key)
  378. {
  379.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  380.   if ( _entryTableMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) {
  381.     Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
  382.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  383.   } else {
  384.     // Find the entry and unlock it, only need read permission
  385.     SBcacheEntryTable::iterator vi = _entryTable.find (key);
  386.     if ( vi != _entryTable.end( ) ) {
  387.       rc = (*vi).second.Unlock (log);
  388.     } else {
  389.       rc = VXIcache_RESULT_NOT_FOUND;
  390.     }
  391.     if ( _entryTableMutex.EndRead( ) != VXItrd_RESULT_SUCCESS ) {
  392.       Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
  393.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  394.     }
  395.   }
  396.   Diag (log, SBCACHE_MGR_TAGID, L"Unlock", L"%s: rc = %d", key.c_str( ), rc);
  397.   return rc;
  398. }
  399. // Delete an entry
  400. VXIcacheResult SBcacheManager::Delete(VXIlogInterface   *log,
  401.       const SBcacheKey  &key,
  402.       bool               haveEntryOpen)
  403. {
  404.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  405.   // Find the entry and delete it, only need read permission. Note
  406.   // that we need to hold a reference to the entry in order to make
  407.   // sure it only gets deleted after we release our lock here (that
  408.   // may be a costly operation). The extra braces ensure the actual
  409.   // deletion is done prior to logging our exit.
  410.   {
  411.     SBcacheEntry entry;
  412.     if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  413.       Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
  414.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  415.     } else {
  416.       SBcacheEntryTable::iterator vi = _entryTable.find (key);
  417.       if ( vi != _entryTable.end( ) ) {
  418. entry = (*vi).second;
  419.         RemoveEntry(entry);
  420.       } else {
  421. rc = VXIcache_RESULT_NOT_FOUND;
  422.       }
  423.       if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  424. Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
  425. rc = VXIcache_RESULT_SYSTEM_ERROR;
  426.       }
  427.     }
  428.     // Note that even getting the size can take time since we
  429.     // may lock on a write mutex until some write is done, and note that
  430.     // erasing the entries may take time since that involves deleting
  431.     // on-disk files in the usual case where there are no active streams
  432.     // for the entry.
  433.     if ( rc == VXIcache_RESULT_SUCCESS )
  434.       _curSizeBytes.Decrement (entry.GetSizeBytes (haveEntryOpen));
  435.   }
  436.   Diag (log, SBCACHE_MGR_TAGID, L"Delete", L"%s: rc = %d", key.c_str( ), rc);
  437.   return rc;
  438. }
  439. // Write out the index file, used to handle abnormal termination
  440. VXIcacheResult SBcacheManager::WriteIndex( )
  441. {
  442.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  443.   Diag (SBCACHE_MGR_TAGID, L"WriteIndex", L"entering");
  444.   // TBD write the index from the entry table, schedule periodically?
  445.   Diag (SBCACHE_MGR_TAGID, L"WriteIndex", L"exiting: rc = %d", rc);
  446.   return rc;
  447. }
  448. // Read the index file, used at startup
  449. VXIcacheResult SBcacheManager::ReadIndex(const SBcacheNString  &cacheDir)
  450. {
  451.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  452.   Diag (SBCACHE_MGR_TAGID, L"ReadIndex", L"entering: %S", cacheDir.c_str( ));
  453.   // TBD, read the index to create the entry table
  454.   // TBD, purge files with our extension that aren't in the index but
  455.   // are in the cache, warn about those without our extension
  456.   Diag (SBCACHE_MGR_TAGID, L"ReadIndex", L"exiting: rc = %d", rc);
  457.   return rc;
  458. }
  459. // Get a new path for an entry
  460. SBcachePath SBcacheManager::GetNewEntryPath(const SBcacheString &moduleName,
  461.     const SBcacheKey    &key)
  462. {
  463.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  464.   // Get the index number, note that _pathSeqNum is a thread-safe object
  465.   VXIulong index = _pathSeqNum.IncrementSeqNum( );
  466.   // Construct the path, return an empty string on failure. The path
  467.   // is a directory tree where there is a subdirectory for each module
  468.   // name, then subdirectories underneath each module to limit each
  469.   // subdirectory to no more then 256 entries in order to avoid OS
  470.   // limitations on files per directory for some older OSes
  471. #if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2)
  472.   std::ostrstream pathStream;
  473. #else
  474.   std::basic_ostringstream<char> pathStream;
  475. #endif
  476.   const wchar_t *ptr = moduleName.c_str( );
  477.   if (( ptr ) && ( *ptr )) {
  478.     while (*ptr != L'') {
  479.       if ((( *ptr >= L'0' ) && ( *ptr <= L'9' )) ||
  480.   (( *ptr >= L'A' ) && ( *ptr <= L'Z' )) ||
  481.   (( *ptr >= L'a' ) && ( *ptr <= L'z' )) ||
  482.   ( *ptr == L'.' ))
  483. pathStream << static_cast<char>(*ptr);
  484.       else
  485. pathStream << '_';
  486.       ptr++;
  487.     }
  488.   } else {
  489.     pathStream << "unknown_module";
  490.   }
  491.   pathStream << SBcachePath::PATH_SEPARATOR
  492.      << index / CACHE_MAX_DIR_ENTRIES << SBcachePath::PATH_SEPARATOR
  493.      << index % CACHE_MAX_DIR_ENTRIES << CACHE_ENTRY_FILE_EXTENSION;
  494. #if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2) 
  495.   pathStream << ends; 
  496. #endif 
  497.   SBcachePath path (_cacheDir, pathStream.str( ));
  498. #if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2)
  499.   // str() freezes the stream, we unfreeze it here to allow pathStream to
  500.   // cleanup after itself.
  501.   pathStream.freeze(false);
  502. #else
  503.   // Not required in earlier GCC or windows?
  504. #endif
  505.   return path;
  506. }
  507. // Clean up the cache to eliminate expired entries and if neccessary
  508. // delete other entries to remain within the allocated size
  509. VXIcacheResult SBcacheManager::Cleanup (bool forcedCleanup, 
  510.     const SBcacheKey& writingKey)
  511. {
  512.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  513.   if (_curSizeBytes.Get() <= _maxSizeBytes)
  514.     return rc;
  515.   // Log to Mgr and Cleanup logs, and emit an warning the first time
  516.   // cleanup is entered so integrations know if they're filling it too
  517.   // rapidly.
  518.   Diag (SBCACHE_MGR_TAGID, L"Cleanup",
  519. L"cleanup starting: %lu bytes in cache, %lu allocation",
  520. _curSizeBytes.Get( ), _maxSizeBytes);
  521.   Diag (SBCACHE_CLEANUP_TAGID, L"Cleanup",
  522. L"cleanup starting: %lu bytes in cache, %lu allocation",
  523. _curSizeBytes.Get( ), _maxSizeBytes);
  524.   { static int once = 0;
  525.     if (once == 0) { 
  526.       once = 1;
  527.       Error(302, L"%s%s", L"Cleanup", L"One-time notification: Disk cache "
  528.           L"filled to maximum for first time, performing cleanup.");
  529.     } 
  530.   }
  531.   int bytesToExpire = _curSizeBytes.Get() - _lowWaterBytes;
  532.   time_t now = time(0);
  533.   SBcacheEntryTable::iterator vi;
  534.   SBcacheEntryList::iterator li;
  535.   SBcacheEntryList expiredEntries;
  536.   VXIulong totalBytesFreed = 0;
  537.   time_t oldestAccessed = now;
  538.   int entriesFreed = 0;
  539.   // Lock cache and transfer enough entries from the cache to our temporary
  540.   // list to get us below the cache low water mark.
  541.   // 
  542.   if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  543.     Error (110, L"%s%s", L"mutex", L"entry table mutex");
  544.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  545.   } else {
  546.     // Copy entries to our temporary list
  547.     for (li = _entryLRUList.begin(); li != _entryLRUList.end(); ++li) {
  548.       if (bytesToExpire <= 0) break;
  549.       int entrySize = (*li).GetSizeBytes(true);
  550.       if ((*li).GetKey() != writingKey && 
  551.           0 < entrySize &&
  552.           (*li).IsExpired(now, &oldestAccessed)) {
  553.         expiredEntries.push_back(*li);
  554.         totalBytesFreed += entrySize;
  555.         bytesToExpire -= entrySize;
  556.         entriesFreed++;
  557.       }
  558.     }
  559.     // Remove them from cache
  560.     for (li = expiredEntries.begin(); li != expiredEntries.end(); ++li)
  561.       RemoveEntry(*li);
  562.     if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  563.       Error (111, L"%s%s", L"mutex", L"entry table mutex");
  564.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  565.     }
  566.   }
  567.   // Now that we're outside the cache lock, actually remove all the
  568.   // entries by removing the last reference to them in our list.
  569.   expiredEntries.erase(expiredEntries.begin(), expiredEntries.end());
  570.   _curSizeBytes.Decrement(totalBytesFreed);
  571.   // Log prior to setting the next cleanup time to ensure we log our
  572.   // completion prior to another cleanup starting
  573.   Diag (SBCACHE_MGR_TAGID, L"Cleanup",
  574.       L"exiting: rc = %d, released %u entries, %lu bytes, %lu bytes in cache",
  575. rc, entriesFreed, totalBytesFreed, _curSizeBytes.Get( ));
  576.   Diag (SBCACHE_CLEANUP_TAGID, L"Cleanup",
  577.       L"exiting: rc = %d, released %u entries, %lu bytes, %lu bytes in cache",
  578. rc, entriesFreed, totalBytesFreed, _curSizeBytes.Get( ));
  579.   return rc;
  580. }