📄 sbcacheentry.cpp
字号:
/****************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 "SBcacheEntry.hpp" // For this class #include "SBcacheMisc.hpp" // For SBcacheReaderWriterMutex, // SBcacheRefCount base class #include "VXItrd.h" // For VXItrcSleep() #include <cstdio> // For FILE, fopen( ), etc #include <cerrno> // For errno to report fopen( ) errors #include <string.h> // For strerror( ) #ifndef _win32_ #include <unistd.h> #endif // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8 // SBcacheEntryMutex, a RW mutex implemented over a single exclusive lock // mutex. We do this to save handles for the rw mutex. // We cannot use a pool here, because we rely on // cache entry locks being held in conflict with each other... a pool has // a good chance of deadlocking. // class SBcacheEntryMutex { public: SBcacheEntryMutex(SBcacheMutex* m) : _mutex(m), _nreaders(0), _writer(0), _writers_waiting(0) { } ~SBcacheEntryMutex() { } VXItrdResult Create(const wchar_t* n) { return VXItrd_RESULT_SUCCESS; } VXItrdResult Lock() const { VXItrdResult rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; ++_writers_waiting; while (_nreaders || _writer) { rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; VXItrdThreadYield(); rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; } --_writers_waiting; ++_writer; rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; return VXItrd_RESULT_SUCCESS; } VXItrdResult Unlock() const { VXItrdResult rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; --_writer; rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; return VXItrd_RESULT_SUCCESS; } VXItrdResult StartRead() const { VXItrdResult rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; // i.e. while a writer holds the lock _or_ is waiting for it while (_writer || _writers_waiting) { rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; VXItrdThreadYield(); rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; } ++_nreaders; rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; return VXItrd_RESULT_SUCCESS; } VXItrdResult EndRead() const { VXItrdResult rc = _mutex->Lock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; --_nreaders; rc = _mutex->Unlock(); if (rc != VXItrd_RESULT_SUCCESS) return rc; return VXItrd_RESULT_SUCCESS; } private: SBcacheMutex* _mutex; mutable short _nreaders; mutable short _writer; mutable short _writers_waiting; }; // SBcacheStream, implementation of VXIcacheStream class SBcacheStream : public VXIcacheStream { public: // Constructor and destructor SBcacheStream(VXIlogInterface *log, VXIunsigned diagTagBase, const SBcacheString &moduleName, const SBcacheKey &key, SBcacheEntry &entry, VXIcacheOpenMode mode, bool blockingIO, VXIulong maxSizeBytes, FILE *filePtr) : VXIcacheStream(log, diagTagBase, moduleName, key), _entry(entry), _mode(mode), _blockingIO(blockingIO), _maxSizeBytes(maxSizeBytes), _filePtr(filePtr), _sizeBytes(0) { } virtual ~SBcacheStream( ) { if ( _filePtr ) Close(false); } // Read and write virtual VXIcacheResult Read(VXIbyte *buffer, VXIulong buflen, VXIulong *nread); virtual VXIcacheResult Write(const VXIbyte *buffer, VXIulong buflen, VXIulong *nwritten); // Close virtual VXIcacheResult Close(bool invalidate); private: SBcacheStream(const SBcacheStream &s); const SBcacheStream &operator=(const SBcacheStream &s); private: SBcacheEntry _entry; VXIcacheOpenMode _mode; bool _blockingIO; VXIulong _maxSizeBytes; FILE *_filePtr; VXIunsigned _sizeBytes; }; // Read from the stream VXIcacheResult SBcacheStream::Read(VXIbyte *buffer, VXIulong buflen, VXIulong *nread) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; *nread = 0; if ( _mode != CACHE_MODE_READ ) { Error (206, NULL); rc = VXIcache_RESULT_IO_ERROR; } else if ( ! _filePtr ) { Error (207, NULL); rc = VXIcache_RESULT_FATAL_ERROR; } // Read, for blocking I/O read in a loop. Note this is a lame // implementation of non-blocking I/O, without doing a fctl( ) or // open( ) this will almost always block, but it is very OS // dependant and tricky to do real non-blocking I/O. if ( rc == VXIcache_RESULT_SUCCESS ) { size_t read; do { read = fread (&buffer[*nread], 1, (size_t) (buflen - *nread), _filePtr); if ( read > 0 ) *nread += read; } while (( _blockingIO ) && ( *nread < buflen ) && (( read > 0 ) || ( ! feof (_filePtr) ))); if ( *nread == 0 ) { if ( ferror (_filePtr) ) { _entry.LogIOError (208); rc = VXIcache_RESULT_IO_ERROR; } else if ( feof (_filePtr) ) { rc = VXIcache_RESULT_END_OF_STREAM; } else { rc = VXIcache_RESULT_WOULD_BLOCK; } } } Diag (SBCACHE_STREAM_TAGID, L"Read", L"%s, %S: %lu bytes, %lu requested, rc = %d", _entry.GetKey( ).c_str( ), _entry.GetPath( ).c_str( ), buflen, *nread, rc); return rc; } // Write to the stream VXIcacheResult SBcacheStream::Write(const VXIbyte *buffer, VXIulong buflen, VXIulong *nwritten) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; *nwritten = 0; if ( _mode != CACHE_MODE_WRITE ) { Error (209, NULL); rc = VXIcache_RESULT_IO_ERROR; } else if ( ! _filePtr ) { Error (210, NULL); rc = VXIcache_RESULT_FATAL_ERROR; } else if ( _sizeBytes + buflen > _maxSizeBytes ) { rc = VXIcache_RESULT_EXCEED_MAXSIZE; } // Write, for blocking I/O write in a loop. Note this is a lame // implementation of non-blocking I/O, without doing a fctl( ) or // open( ) this will almost always block, but it is very OS // dependant and tricky to do real non-blocking I/O. if ( rc == VXIcache_RESULT_SUCCESS ) { size_t written; do { written = fwrite (&buffer[*nwritten], 1, (size_t) (buflen - *nwritten), _filePtr); if ( written > 0 ) { *nwritten += written; _sizeBytes += written; } } while (( _blockingIO ) && ( *nwritten < buflen ) && (( written > 0 ) || ( ! ferror (_filePtr) ))); if ( *nwritten == 0 ) { if ( ferror (_filePtr) ) { _entry.LogIOError (212); rc = VXIcache_RESULT_IO_ERROR; } else { rc = VXIcache_RESULT_WOULD_BLOCK; } } } Diag (SBCACHE_STREAM_TAGID, L"Write", L"%s, %S: %lu bytes, %lu requested, rc = %d", _entry.GetKey( ).c_str( ), _entry.GetPath( ).c_str( ), buflen, *nwritten, rc); return rc; } // Close the stream VXIcacheResult SBcacheStream::Close(bool invalidate) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; // Close the file if ( fclose (_filePtr) != 0 ) { _entry.LogIOError (300); rc = VXIcache_RESULT_IO_ERROR; } _filePtr = NULL; // Close the cache entry, do this after logging to ensure the entry // isn't deleted on us after the close VXIcacheResult rc2 = _entry.Close (GetLog( ), _mode, _sizeBytes, invalidate); if ( rc2 != VXIcache_RESULT_SUCCESS ) rc = rc2; return rc; } // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8 // SBcacheEntryDetails, real reference counted cache entry class SBcacheEntryDetails : public SBcacheRefCount, public SBinetLogger { public: // Constructor and destructor SBcacheEntryDetails(VXIlogInterface *log, VXIunsigned diagTagBase, SBcacheMutex *refCountMutex) : SBcacheRefCount(refCountMutex), SBinetLogger(MODULE_SBCACHE, log, diagTagBase), _rwMutex(refCountMutex), _creationCost(CACHE_CREATION_COST_DEFAULT), _lastModified(0), _lastAccessed(0), _flags(CACHE_FLAG_NULL), _key(), _path(), _sizeBytes(0), _fileExists(false), _invalidated(false) { } virtual ~SBcacheEntryDetails( ); // Release the cache entry static VXItrdResult Release (SBcacheEntryDetails **rc) { return SBcacheRefCount::Release (reinterpret_cast<SBcacheRefCount **>(rc)); } // Create the entry VXIcacheResult Create( ); // Open the entry VXIcacheResult Open(VXIlogInterface *log, const SBcacheString &moduleName, const SBcacheKey &key, const SBcachePath &path, VXIcacheOpenMode mode, VXIint32 flags, VXIulong maxSizeBytes, const VXIMap *properties, VXIMap *streamInfo, VXIcacheStream **stream); // Unlock the entry VXIcacheResult Unlock(VXIlogInterface *log); // Accessors bool IsLocked( ) const { return ((_flags & (CACHE_FLAG_LOCK | CACHE_FLAG_LOCK_MEMORY)) != 0); } bool IsExpired (time_t cutoffTime, time_t *lastAccessed) const { bool expired = (( ! IsLocked( ) ) && ( _lastAccessed < cutoffTime )); Diag (SBCACHE_ENTRY_TAGID, L"IsExpired", L"%s, %S, %s (%d %lu %lu)", _key.c_str( ), _path.c_str( ), (expired ? L"true" : L"false"), (int) IsLocked( ), (unsigned long) _lastAccessed, (unsigned long) cutoffTime); *lastAccessed = _lastAccessed; return expired; } const SBcacheKey &GetKey( ) const { return _key; } const SBcachePath &GetPath( ) const { return _path; } VXIulong GetSizeBytes (bool haveEntryOpen) const { VXIulong size = 0; if (( haveEntryOpen ) || ( _rwMutex.StartRead( ) == VXItrd_RESULT_SUCCESS )) { size = _sizeBytes; if ( ! haveEntryOpen ) _rwMutex.EndRead( ); } return size; } // Error logging VXIlogResult LogIOError (VXIunsigned errorID) const { return Error (errorID, L"%s%S%s%S%s%d", L"path", _path.c_str( ), L"errnoStr", strerror(errno), L"errno", errno); } VXIlogResult LogIOError (VXIlogInterface *log, VXIunsigned errorID, const SBcachePath &path) const { return Error (log, errorID, L"%s%S%s%S%s%d", L"path", path.c_str( ), L"errnoStr", strerror(errno), L"errno", errno); } // Comparison operators, smaller is defined as a preference for // deleting this entry first, equality is having equal preference bool operator< (const SBcacheEntryDetails &entry) const { return ((( (! IsLocked( )) && (entry.IsLocked( )) ) || ( _creationCost < entry._creationCost ) || ( _lastAccessed < entry._lastAccessed ) || ( _sizeBytes < entry._sizeBytes )) ? true : false); } bool operator> (const SBcacheEntryDetails &entry) const { return ((( (IsLocked( )) && (! entry.IsLocked( )) ) || ( _creationCost > entry._creationCost ) || ( _lastAccessed > entry._lastAccessed ) || ( _sizeBytes > entry._sizeBytes )) ? true : false); } bool operator== (const SBcacheEntryDetails &entry) const { return ((( IsLocked( ) == entry.IsLocked( ) ) && ( _creationCost == entry._creationCost ) && ( _lastAccessed == entry._lastAccessed ) && ( _sizeBytes == entry._sizeBytes )) ? true : false); } bool operator!= (const SBcacheEntryDetails &entry) const { return ((( IsLocked( ) != entry.IsLocked( ) ) || ( _creationCost != entry._creationCost ) || ( _lastAccessed != entry._lastAccessed ) || ( _sizeBytes != entry._sizeBytes )) ? true : false); } public: // Only for SBcacheStream use // Close VXIcacheResult Close (VXIlogInterface *log, VXIcacheOpenMode mode, VXIunsigned sizeBytes, bool invalidate); private: // Delete the on-disk entry, internal routine, no mutex held VXIcacheResult DeleteFile( ); // Disable the copy constructor and assignment operator SBcacheEntryDetails(const SBcacheEntryDetails &entry); const SBcacheEntryDetails &operator=(const SBcacheEntryDetails &entry); private: // Est base bytes: 76 + (wcslen(modname) + wcslen(key) + wcslen(path)) * 2 // 76 + (10 + 32 + 40) * 2 = 76 + 164 = 240 // Linux: 76 + (*4)328 = 404 // 404 + 8(refcnt) + (4 + 4 + (12 * 10) (logger)) = 540 SBcacheEntryMutex _rwMutex; // (12) VXIcacheCreationCost _creationCost; // (4) time_t _lastModified; // (4) time_t _lastAccessed; // (4) VXIint32 _flags; // (4) SBcacheKey _key; // (12 + wcslen(key) * 2) SBcachePath _path; // (12 + strlen(path)) VXIunsigned _sizeBytes; // (4) bool _fileExists; // (2?) bool _invalidated; // (2?) }; // Destructor SBcacheEntryDetails::~SBcacheEntryDetails( ) { // Delete the on-disk file if appropriate // TBD make this conditional by removing the #if 0 once // persistant caching across process restarts (saving/loading // the index file) is implemented #if 0 if ( _invalidated ) #endif DeleteFile( ); } // Create the entry VXIcacheResult SBcacheEntryDetails::Create( )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -