⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbcachemanager.cpp

📁 sloedgy open sip stack source code
💻 CPP
📖 第 1 页 / 共 2 页
字号:

 /****************License************************************************
  *
  * Copyright 2000-2003.  ScanSoft, Inc.    
  *
  * Use of this software is subject to notices and obligations set forth 
  * in the SpeechWorks Public License - Software Version 1.2 which is 
  * included with this software. 
  *
  * ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech, 
  * SpeechWorks and the SpeechWorks logo are registered trademarks or 
  * trademarks of SpeechWorks International, Inc. in the United States 
  * and other countries.
  *
  ***********************************************************************/
 

 // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
 
#include <vxibuildopts.h>
#if P_VXI

 #include "SBcacheInternal.h"
 
 #include "SBcacheManager.hpp"    // for this class
 
 #include <list>                  // for STL list template class
 #include <vector>                  // for STL list template class
 #include <algorithm>
 #include <limits.h>              // for ULONG_MAX
 
 #if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ < 2)
 #include <strstream>
 #else
 #include <sstream>               // for basic_ostringstream( )
 #endif
 
 static const int CACHE_REF_COUNT_MUTEX_POOL_SIZE = 256;
 static const int CACHE_MAX_DIR_ENTRIES = 256;
 static const char CACHE_ENTRY_FILE_EXTENSION[] = ".sbc";
 
 // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
 
 
 // Shut down the manager
 SBcacheManager::~SBcacheManager( )
 {
   if ( _cacheDir.length( ) > 0 ) {
     // Lock to be paranoid, makes sure everyone else is done
     if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
       Error (110, L"%s%s", L"mutex", L"entry table mutex");
     } else {
       // Write out the index file
       WriteIndex( );
 
       // Clear the cache entries
       _entryTable.erase (_entryTable.begin( ), _entryTable.end( ));
       _entryLRUList.erase(_entryLRUList.begin(), _entryLRUList.end());
       _curSizeBytes.Reset (0);
 
       // Clear the directory name
       _cacheDir = "";
 
       if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS )
 	Error (111, L"%s%s", L"mutex", L"entry table mutex");
     }
   }
 }
 
 
 // Create the manager
 VXIcacheResult SBcacheManager::Create(const SBcacheNString &cacheDir,
 				      VXIulong              cacheMaxSizeBytes,
 				      VXIulong              entryMaxSizeBytes,
 				      VXIulong              entryExpTimeSec,
 				      VXIbool               unlockEntries,
                                       VXIulong              cacheLowWaterBytes)
 {
   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
 
   // Avoid double initialization
   if ( _cacheDir.length( ) > 0 ) {
     Error (112, NULL);
     rc = VXIcache_RESULT_FATAL_ERROR;
   }
 
   // Create the path sequence number
   if (( rc == VXIcache_RESULT_SUCCESS ) &&
       ( _pathSeqNum.Create( ) != VXItrd_RESULT_SUCCESS )) {
     Error (109, L"%s%s", L"mutex", L"path seq num");
     rc = VXIcache_RESULT_SYSTEM_ERROR;
   }
 
   // Create the entry table mutex
   if (( rc == VXIcache_RESULT_SUCCESS ) &&
       ( _entryTableMutex.Create(L"SBcacheManager entry table mutex") !=
 	VXItrd_RESULT_SUCCESS )) {
     Error (109, L"%s%s", L"mutex", L"entry table mutex");
     rc = VXIcache_RESULT_SYSTEM_ERROR;
   }
 
   // Create the mutex pool
   if (( rc == VXIcache_RESULT_SUCCESS ) &&
       ( _refCntMutexPool.Create(L"SBcacheManager refCnt mutex pool",
 				CACHE_REF_COUNT_MUTEX_POOL_SIZE) )) {
     Error (109, L"%s%s", L"mutex", L"entry table mutex");
     rc = VXIcache_RESULT_SYSTEM_ERROR;
   }
 
   // Create the cache size
   if (( rc == VXIcache_RESULT_SUCCESS ) &&
       ( _curSizeBytes.Create( ) != VXItrd_RESULT_SUCCESS )) {
     Error (109, L"%s%s", L"mutex", L"cache size mutex");
     rc = VXIcache_RESULT_SYSTEM_ERROR;
   }
 
   // Create the cache directory if required
   if ( rc == VXIcache_RESULT_SUCCESS ) {
     SBcacheStatInfo statInfo;
     if ( SBcacheStat (cacheDir.c_str( ), &statInfo) ) {
       // Exists, make sure it is a file
       if ( ! SBcacheIsDir(statInfo) ) {
 	Error (113, L"%s%S", L"cacheDirectory", cacheDir.c_str( ));
 	rc = VXIcache_RESULT_FATAL_ERROR;
       } else {
 	// Load the cache index file
 	rc = ReadIndex (cacheDir);
       }
     } else if ( ! SBcacheMkdir (cacheDir.c_str( )) ) {
       Error (114, L"%s%S", L"cacheDirectory", cacheDir.c_str( ));
       rc = VXIcache_RESULT_FATAL_ERROR;
     }
   }
 
   // Update data members
   if ( rc == VXIcache_RESULT_SUCCESS ) {
     _cacheDir = cacheDir;
     _maxSizeBytes = cacheMaxSizeBytes;
     _entryMaxSizeBytes = entryMaxSizeBytes;
     _lowWaterBytes = cacheLowWaterBytes;
   }
 
   _entryReserve = 0;
   ReserveEntries(0); // Disable, for now.
 
   Diag (SBCACHE_MGR_TAGID, L"Create", L"rc = %d", rc);
   return rc;
 }
 
 // NOTE: This is disabled, see above, until SPR is fixed or NPFed.
 //
 // Interesting trick, we want to reserve a certain amount of memory for N
 // entries, but we only have an estimate as to the size of an entry, and we
 // can't make all the code use a special allocator.  
 // Solution: Make an estimate(E) of how much an entry will take up, and
 // grab N * E bytes from the general allocator.  Whenever we add an entry,
 // we give back E bytes (if we can), whenver we remove an entry we take E
 // bytes (unless we hit the maximum preallocation).  
 //
 void SBcacheManager::ReserveEntries(int nentries)
 {
   for (int i = 0; i < nentries; ++i) {
     SBcacheEntryEstimate* es = new SBcacheEntryEstimate();
     es->next = _entryReserve;
     _entryReserve = es;
   }
   _entriesReserved = nentries;
   _maxEntriesReserved = nentries;
 }
 
 void SBcacheManager::EntryAdded()
 {
   if (_entriesReserved > 0) {
     SBcacheEntryEstimate* es = _entryReserve;
     _entryReserve = es->next;
     delete es;
     _entriesReserved--;
   } else {
     static int once = 1;
     if (once) {
       once = 0;
     }
   }
 }
 
 void SBcacheManager::EntryRemoved()
 {
   if (_maxEntriesReserved > _entriesReserved) {
     SBcacheEntryEstimate* es = new SBcacheEntryEstimate();
     es->next = _entryReserve;
     _entryReserve = es;
     _entriesReserved++;
   }
 }
 
 // Synchronized table and LRU list
 //
 bool SBcacheManager::InsertEntry(SBcacheEntry& entry)
 {
   SBcacheEntryTable::value_type tableEntry (entry.GetKey(), entry);
   if ( ! _entryTable.insert (tableEntry).second )
     return false;
   _entryLRUList.push_back(entry);
   EntryAdded();
   return true;
 }
 
 void SBcacheManager::RemoveEntry(const SBcacheEntry& entry)
 {
   SBcacheEntryTable::iterator te = _entryTable.find(entry.GetKey());
   _entryTable.erase(te);
   SBcacheEntryList::iterator vi = _entryLRUList.begin();
   for (; vi != _entryLRUList.end(); ++vi)
     if (entry.Equivalent(*vi)) {
       _entryLRUList.erase(vi);
       break;
     }
   EntryRemoved();
 }
 
 void SBcacheManager::TouchEntry(const SBcacheEntry& entry)
 {
   SBcacheEntryList::iterator vi = _entryLRUList.begin();
   for (; vi != _entryLRUList.end(); ++vi)
     if (entry.Equivalent(*vi)) {
       _entryLRUList.erase(vi);
       _entryLRUList.push_back(entry);
       break;
     }
 }
 
 
 //#######################################################################
 // Note about locking protocol.  THere are three locks in this code:
 //   A. The entrytable lock (_entryTableMutex)
 //   B. a lock per entry  (GetSizeBytes, Open, Close)
 //   C. a lock of _curSizeBytes (atomic operations)
 // Currently, both locks A & C are held inside of lock B because an open
 // obtains a lock and holds it until the entry is closed.  Therefore,
 // a B lock must never be obtained while an A or C lock is held!
 //#######################################################################
 
 // Open an entry
 VXIcacheResult SBcacheManager::Open(VXIlogInterface       *log,
 				    const SBcacheString   &moduleName,
 				    const SBcacheKey      &key,
 				    VXIcacheOpenMode       mode,
 				    VXIint32               flags,
 				    const VXIMap          *properties,
 				    VXIMap                *streamInfo,
 				    VXIcacheStream       **stream)
 {
   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
 
   // Big loop where we attempt to open and re-open the cache entry for
   // as long as we get recoverable errors
   VXIcacheOpenMode finalMode;
   do {
     finalMode = mode;
     rc = VXIcache_RESULT_SUCCESS;
 
     if ( _entryTableMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) {
       Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
       return VXIcache_RESULT_SYSTEM_ERROR;
     }
 
     // Find the entry and open it, only need read permission
     bool entryOpened = false;
     SBcacheEntry entry;
     SBcacheEntryTable::iterator vi = _entryTable.find (key);
     if ( vi == _entryTable.end( ) ) {
       rc = VXIcache_RESULT_NOT_FOUND;
     } else {
       entry = (*vi).second;
       finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode);
     }
 
     if ( _entryTableMutex.EndRead( ) != VXItrd_RESULT_SUCCESS ) {
       Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
       rc = VXIcache_RESULT_SYSTEM_ERROR;
     }
 
 
     // For write and read/create mode, create the entry if not found
     if (( rc == VXIcache_RESULT_NOT_FOUND ) && ( mode != CACHE_MODE_READ )) {
       rc = VXIcache_RESULT_SUCCESS;
 
       // Get write permission
       if ( _entryTableMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
 	Error (log, 110, L"%s%s", L"mutex", L"entry table mutex");
 	rc = VXIcache_RESULT_SYSTEM_ERROR;
       } else {
 	// Try to find the entry again, it may have been created by now
 	vi = _entryTable.find (key);
 	if ( vi != _entryTable.end( ) ) {
 	  // Found it this time
 	  entry = (*vi).second;
 	  finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_READ : mode);
 	} else {
 	  // Create and open the entry for write
 	  rc = entry.Create (GetLog( ), GetDiagBase( ),
 			     _refCntMutexPool.GetMutex( ));
 
 	  if ( rc == VXIcache_RESULT_SUCCESS ) {
 	    finalMode = (mode == CACHE_MODE_READ_CREATE ? CACHE_MODE_WRITE :
 			 mode);
 
             // Note entry lock obtained while entrytable lock is held! We
             // can get away with this, because the lock isn't visible to
             // anyone else yet.
 	    rc = entry.Open (log, moduleName, key,
 			     GetNewEntryPath (moduleName, key),
 			     finalMode, flags, _entryMaxSizeBytes, properties,
 			     streamInfo, stream);
 	  }
 
 	  // Insert the entry
 	  if ( rc == VXIcache_RESULT_SUCCESS ) {
 	    entryOpened = true;
 
 	    SBcacheEntryTable::value_type tableEntry (key, entry);
 	    if ( !InsertEntry(entry)) {
 	      Error (log, 100, NULL);
 	      (*stream)->Close (true);
 	      *stream = NULL;
 	      rc = VXIcache_RESULT_OUT_OF_MEMORY;
 	    } 
 	  }
 	}
 
 	if ( _entryTableMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
 	  Error (log, 111, L"%s%s", L"mutex", L"entry table mutex");
 	  rc = VXIcache_RESULT_SYSTEM_ERROR;
 	}
       }
     }
 
 
     // Open pre-existing entry. Note that this may return
     // VXIcache_RESULT_FAILURE in some cases where we then need to
     // retry the entire process of opening the entry -- that occurs
     // when a writer opens the entry, we attempt to open for read
     // access here before the writer finishes writing the entry, then

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -