📄 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 <vxibuildopts.h>
#if P_VXI
#include "SBcacheEntry.hpp" // For this class
#include "SBcacheMisc.hpp" // For SBcacheReaderWriterMutex,
// SBcacheRefCount base class
#include "vxi/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
#if defined(_MSC_VER)
#pragma warning(disable:4061)
#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( );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -