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

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 "SBcacheEntry.hpp"   // For this class
  24. #include "SBcacheMisc.hpp"    // For SBcacheReaderWriterMutex,
  25.                               // SBcacheRefCount base class
  26. #include "VXItrd.h"          // For VXItrcSleep()
  27. #include <cstdio>            // For FILE, fopen( ), etc
  28. #include <cerrno>            // For errno to report fopen( ) errors
  29. #include <string.h>          // For strerror( )
  30. #ifndef _win32_
  31. #include <unistd.h>
  32. #endif
  33. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  34. // SBcacheEntryMutex, a RW mutex implemented over a single exclusive lock
  35. // mutex.  We do this to save handles for the rw mutex.
  36. // We cannot use a pool here, because we rely on
  37. // cache entry locks being held in conflict with each other... a pool has
  38. // a good chance of deadlocking.
  39. //
  40. class SBcacheEntryMutex {
  41. public:
  42.   SBcacheEntryMutex(SBcacheMutex* m) :
  43.     _mutex(m), _nreaders(0), _writer(0), _writers_waiting(0) { }
  44.   ~SBcacheEntryMutex() { }
  45.   VXItrdResult Create(const wchar_t* n) { return VXItrd_RESULT_SUCCESS; }
  46.   VXItrdResult Lock() const {
  47.     VXItrdResult rc = _mutex->Lock();
  48.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  49.     ++_writers_waiting;
  50.     while (_nreaders || _writer) {
  51.       rc = _mutex->Unlock();
  52.       if (rc != VXItrd_RESULT_SUCCESS) return rc;
  53.       VXItrdThreadYield();
  54.       rc = _mutex->Lock();
  55.       if (rc != VXItrd_RESULT_SUCCESS) return rc;
  56.     }
  57.     --_writers_waiting;
  58.     ++_writer;
  59.     rc = _mutex->Unlock();
  60.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  61.     return VXItrd_RESULT_SUCCESS;
  62.   }
  63.   VXItrdResult Unlock() const {
  64.     VXItrdResult rc = _mutex->Lock();
  65.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  66.     --_writer;
  67.     rc = _mutex->Unlock();
  68.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  69.     return VXItrd_RESULT_SUCCESS;
  70.   }
  71.   VXItrdResult StartRead() const {
  72.     VXItrdResult rc = _mutex->Lock();
  73.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  74.     // i.e. while a writer holds the lock _or_ is waiting for it
  75.     while (_writer || _writers_waiting) {
  76.       rc = _mutex->Unlock();
  77.       if (rc != VXItrd_RESULT_SUCCESS) return rc;
  78.       VXItrdThreadYield();
  79.       rc = _mutex->Lock();
  80.       if (rc != VXItrd_RESULT_SUCCESS) return rc;
  81.     }
  82.     ++_nreaders;
  83.     rc = _mutex->Unlock();
  84.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  85.     return VXItrd_RESULT_SUCCESS;
  86.   }
  87.   VXItrdResult EndRead() const {
  88.     VXItrdResult rc = _mutex->Lock();
  89.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  90.     --_nreaders;
  91.     rc = _mutex->Unlock();
  92.     if (rc != VXItrd_RESULT_SUCCESS) return rc;
  93.     return VXItrd_RESULT_SUCCESS;
  94.   }
  95. private:
  96.   SBcacheMutex*  _mutex;
  97.   mutable short  _nreaders;
  98.   mutable short  _writer;
  99.   mutable short  _writers_waiting;
  100. };
  101. // SBcacheStream, implementation of VXIcacheStream
  102. class SBcacheStream : public VXIcacheStream {
  103. public:
  104.   // Constructor and destructor
  105.   SBcacheStream(VXIlogInterface *log, VXIunsigned diagTagBase,
  106. const SBcacheString &moduleName, const SBcacheKey &key,
  107. SBcacheEntry &entry, VXIcacheOpenMode mode, bool blockingIO,
  108. VXIulong maxSizeBytes, FILE *filePtr) :
  109.     VXIcacheStream(log, diagTagBase, moduleName, key), _entry(entry),
  110.     _mode(mode), _blockingIO(blockingIO), _maxSizeBytes(maxSizeBytes),
  111.     _filePtr(filePtr), _sizeBytes(0) { }
  112.   virtual ~SBcacheStream( ) { if ( _filePtr ) Close(false); }
  113.   // Read and write
  114.   virtual VXIcacheResult Read(VXIbyte          *buffer,
  115.       VXIulong          buflen,
  116.       VXIulong         *nread);
  117.   virtual VXIcacheResult Write(const VXIbyte   *buffer,
  118.        VXIulong         buflen,
  119.        VXIulong        *nwritten);
  120.   // Close
  121.   virtual VXIcacheResult Close(bool invalidate);
  122. private:
  123.   SBcacheStream(const SBcacheStream &s);
  124.   const SBcacheStream &operator=(const SBcacheStream &s);
  125. private:
  126.   SBcacheEntry      _entry;
  127.   VXIcacheOpenMode  _mode;
  128.   bool              _blockingIO;
  129.   VXIulong          _maxSizeBytes;
  130.   FILE             *_filePtr;
  131.   VXIunsigned       _sizeBytes;
  132. };
  133. // Read from the stream
  134. VXIcacheResult SBcacheStream::Read(VXIbyte          *buffer,
  135.    VXIulong          buflen,
  136.    VXIulong         *nread)
  137. {
  138.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  139.   *nread = 0;
  140.   if ( _mode != CACHE_MODE_READ ) {
  141.     Error (206, NULL);
  142.     rc = VXIcache_RESULT_IO_ERROR;
  143.   } else if ( ! _filePtr ) {
  144.     Error (207, NULL);
  145.     rc = VXIcache_RESULT_FATAL_ERROR;
  146.   }
  147.   // Read, for blocking I/O read in a loop. Note this is a lame
  148.   // implementation of non-blocking I/O, without doing a fctl( ) or
  149.   // open( ) this will almost always block, but it is very OS
  150.   // dependant and tricky to do real non-blocking I/O.
  151.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  152.     size_t read;
  153.     do {
  154.       read = fread (&buffer[*nread], 1, (size_t) (buflen - *nread), _filePtr);
  155.       if ( read > 0 )
  156. *nread += read;
  157.     } while (( _blockingIO ) && ( *nread < buflen ) &&
  158.      (( read > 0 ) || ( ! feof (_filePtr) )));
  159.     if ( *nread == 0 ) {
  160.       if ( ferror (_filePtr) ) {
  161. _entry.LogIOError (208);
  162. rc = VXIcache_RESULT_IO_ERROR;
  163.       } else if ( feof (_filePtr) ) {
  164. rc = VXIcache_RESULT_END_OF_STREAM;
  165.       } else {
  166. rc = VXIcache_RESULT_WOULD_BLOCK;
  167.       }
  168.     }
  169.   }
  170.   Diag (SBCACHE_STREAM_TAGID, L"Read",
  171. L"%s, %S: %lu bytes, %lu requested, rc = %d",
  172. _entry.GetKey( ).c_str( ), _entry.GetPath( ).c_str( ), buflen,
  173. *nread, rc);
  174.   return rc;
  175. }
  176. // Write to the stream
  177. VXIcacheResult SBcacheStream::Write(const VXIbyte   *buffer,
  178.     VXIulong         buflen,
  179.     VXIulong        *nwritten)
  180. {
  181.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  182.   *nwritten = 0;
  183.   if ( _mode != CACHE_MODE_WRITE ) {
  184.     Error (209, NULL);
  185.     rc = VXIcache_RESULT_IO_ERROR;
  186.   } else if ( ! _filePtr ) {
  187.     Error (210, NULL);
  188.     rc = VXIcache_RESULT_FATAL_ERROR;
  189.   } else if ( _sizeBytes + buflen > _maxSizeBytes ) {
  190.     rc = VXIcache_RESULT_EXCEED_MAXSIZE;
  191.   }
  192.   // Write, for blocking I/O write in a loop. Note this is a lame
  193.   // implementation of non-blocking I/O, without doing a fctl( ) or
  194.   // open( ) this will almost always block, but it is very OS
  195.   // dependant and tricky to do real non-blocking I/O.
  196.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  197.     size_t written;
  198.     do {
  199.       written = fwrite (&buffer[*nwritten], 1, (size_t) (buflen - *nwritten),
  200. _filePtr);
  201.       if ( written > 0 ) {
  202. *nwritten += written;
  203. _sizeBytes += written;
  204.       }
  205.     } while (( _blockingIO ) && ( *nwritten < buflen ) &&
  206.      (( written > 0 ) || ( ! ferror (_filePtr) )));
  207.     if ( *nwritten == 0 ) {
  208.       if ( ferror (_filePtr) ) {
  209. _entry.LogIOError (212);
  210. rc = VXIcache_RESULT_IO_ERROR;
  211.       } else {
  212. rc = VXIcache_RESULT_WOULD_BLOCK;
  213.       }
  214.     }
  215.   }
  216.   Diag (SBCACHE_STREAM_TAGID, L"Write",
  217. L"%s, %S: %lu bytes, %lu requested, rc = %d",
  218. _entry.GetKey( ).c_str( ), _entry.GetPath( ).c_str( ), buflen,
  219. *nwritten, rc);
  220.   return rc;
  221. }
  222. // Close the stream
  223. VXIcacheResult SBcacheStream::Close(bool invalidate)
  224. {
  225.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  226.   // Close the file
  227.   if ( fclose (_filePtr) != 0 ) {
  228.     _entry.LogIOError (300);
  229.     rc = VXIcache_RESULT_IO_ERROR;
  230.   }
  231.   _filePtr = NULL;
  232.   // Close the cache entry, do this after logging to ensure the entry
  233.   // isn't deleted on us after the close
  234.   VXIcacheResult rc2 = _entry.Close (GetLog( ), _mode, _sizeBytes, invalidate);
  235.   if ( rc2 != VXIcache_RESULT_SUCCESS )
  236.     rc = rc2;
  237.   return rc;
  238. }
  239. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  240. // SBcacheEntryDetails, real reference counted cache entry
  241. class SBcacheEntryDetails : public SBcacheRefCount, public SBinetLogger {
  242. public:
  243.   // Constructor and destructor
  244.   SBcacheEntryDetails(VXIlogInterface *log, VXIunsigned diagTagBase,
  245.       SBcacheMutex *refCountMutex) :
  246.     SBcacheRefCount(refCountMutex),
  247.     SBinetLogger(MODULE_SBCACHE, log, diagTagBase),
  248.     _rwMutex(refCountMutex),
  249.     _creationCost(CACHE_CREATION_COST_DEFAULT), _lastModified(0),
  250.     _lastAccessed(0), _flags(CACHE_FLAG_NULL), _key(), _path(), _sizeBytes(0),
  251.     _fileExists(false), _invalidated(false) { }
  252.   virtual ~SBcacheEntryDetails( );
  253.   // Release the cache entry
  254.   static VXItrdResult Release (SBcacheEntryDetails **rc) {
  255.     return SBcacheRefCount::Release (reinterpret_cast<SBcacheRefCount **>(rc)); }
  256.   // Create the entry
  257.   VXIcacheResult Create( );
  258.   // Open the entry
  259.   VXIcacheResult Open(VXIlogInterface       *log,
  260.       const SBcacheString   &moduleName,
  261.       const SBcacheKey      &key,
  262.       const SBcachePath     &path,
  263.       VXIcacheOpenMode       mode,
  264.       VXIint32               flags,
  265.       VXIulong               maxSizeBytes,
  266.       const VXIMap          *properties,
  267.       VXIMap                *streamInfo,
  268.       VXIcacheStream       **stream);
  269.   // Unlock the entry
  270.   VXIcacheResult Unlock(VXIlogInterface  *log);
  271.   // Accessors
  272.   bool IsLocked( ) const {
  273.     return ((_flags & (CACHE_FLAG_LOCK | CACHE_FLAG_LOCK_MEMORY)) != 0); }
  274.   bool IsExpired (time_t cutoffTime, time_t *lastAccessed) const {
  275.     bool expired = (( ! IsLocked( ) ) && ( _lastAccessed < cutoffTime ));
  276.     Diag (SBCACHE_ENTRY_TAGID, L"IsExpired", L"%s, %S, %s (%d %lu %lu)",
  277.           _key.c_str( ), _path.c_str( ), (expired ? L"true" : L"false"),
  278.   (int) IsLocked( ), (unsigned long) _lastAccessed,
  279.        (unsigned long) cutoffTime);
  280.     *lastAccessed = _lastAccessed;
  281.     return expired;
  282.   }
  283.   const SBcacheKey &GetKey( ) const { return _key; }
  284.   const SBcachePath &GetPath( ) const { return _path; }
  285.   VXIulong GetSizeBytes (bool haveEntryOpen) const {
  286.     VXIulong size = 0;
  287.     if (( haveEntryOpen ) ||
  288. ( _rwMutex.StartRead( ) == VXItrd_RESULT_SUCCESS )) {
  289.       size = _sizeBytes;
  290.       if ( ! haveEntryOpen )
  291. _rwMutex.EndRead( );
  292.     }
  293.     return size;
  294.   }
  295.   // Error logging
  296.   VXIlogResult LogIOError (VXIunsigned errorID) const {
  297.     return Error (errorID, L"%s%S%s%S%s%d", L"path", _path.c_str( ),
  298.   L"errnoStr", strerror(errno), L"errno", errno);
  299.   }
  300.   VXIlogResult LogIOError (VXIlogInterface *log,
  301.    VXIunsigned errorID,
  302.    const SBcachePath &path) const {
  303.     return Error (log, errorID, L"%s%S%s%S%s%d", L"path", path.c_str( ),
  304.   L"errnoStr", strerror(errno), L"errno", errno);
  305.   }
  306.   // Comparison operators, smaller is defined as a preference for
  307.   // deleting this entry first, equality is having equal preference
  308.   bool operator< (const SBcacheEntryDetails &entry) const {
  309.     return ((( (! IsLocked( )) && (entry.IsLocked( )) ) ||
  310.      ( _creationCost < entry._creationCost ) ||
  311.      ( _lastAccessed < entry._lastAccessed ) ||
  312.      ( _sizeBytes < entry._sizeBytes )) ? true : false);
  313.   }
  314.   bool operator> (const SBcacheEntryDetails &entry) const {
  315.     return ((( (IsLocked( )) && (! entry.IsLocked( )) ) ||
  316.      ( _creationCost > entry._creationCost ) ||
  317.      ( _lastAccessed > entry._lastAccessed ) ||
  318.      ( _sizeBytes > entry._sizeBytes )) ? true : false);
  319.   }
  320.   bool operator== (const SBcacheEntryDetails &entry) const {
  321.     return ((( IsLocked( ) == entry.IsLocked( ) ) &&
  322.      ( _creationCost == entry._creationCost ) &&
  323.      ( _lastAccessed == entry._lastAccessed ) &&
  324.      ( _sizeBytes == entry._sizeBytes )) ? true : false);
  325.   }
  326.   bool operator!= (const SBcacheEntryDetails &entry) const {
  327.     return ((( IsLocked( ) != entry.IsLocked( ) ) ||
  328.      ( _creationCost != entry._creationCost ) ||
  329.      ( _lastAccessed != entry._lastAccessed ) ||
  330.      ( _sizeBytes != entry._sizeBytes )) ? true : false);
  331.   }
  332. public:
  333.   // Only for SBcacheStream use
  334.   // Close
  335.   VXIcacheResult Close (VXIlogInterface  *log,
  336. VXIcacheOpenMode  mode,
  337. VXIunsigned       sizeBytes,
  338. bool              invalidate);
  339. private:
  340.   // Delete the on-disk entry, internal routine, no mutex held
  341.   VXIcacheResult DeleteFile( );
  342.   // Disable the copy constructor and assignment operator
  343.   SBcacheEntryDetails(const SBcacheEntryDetails &entry);
  344.   const SBcacheEntryDetails &operator=(const SBcacheEntryDetails &entry);
  345. private:
  346.   // Est base bytes: 76 + (wcslen(modname) + wcslen(key) + wcslen(path)) * 2
  347.   //                 76 + (10 + 32 + 40) * 2 = 76 + 164 = 240
  348.   //                 Linux: 76 + (*4)328 = 404
  349.   //                 404 + 8(refcnt) + (4 + 4 + (12 * 10) (logger)) = 540
  350.   SBcacheEntryMutex        _rwMutex;         // (12)
  351.   VXIcacheCreationCost     _creationCost;    // (4)
  352.   time_t                   _lastModified;    // (4)
  353.   time_t                   _lastAccessed;    // (4)
  354.   VXIint32                 _flags;           // (4)
  355.   SBcacheKey               _key;             // (12 + wcslen(key) * 2)
  356.   SBcachePath              _path;            // (12 + strlen(path))
  357.   VXIunsigned              _sizeBytes;       // (4)
  358.   bool                     _fileExists;      // (2?)
  359.   bool                     _invalidated;     // (2?)
  360. };
  361. // Destructor
  362. SBcacheEntryDetails::~SBcacheEntryDetails( )
  363. {
  364.   // Delete the on-disk file if appropriate
  365.   // TBD make this conditional by removing the #if 0 once
  366.   // persistant caching across process restarts (saving/loading
  367.   // the index file) is implemented
  368. #if 0
  369.   if ( _invalidated )
  370. #endif
  371.     DeleteFile( );
  372. }
  373. // Create the entry
  374. VXIcacheResult SBcacheEntryDetails::Create( )
  375. {
  376.   // Create the mutex
  377.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  378.   if ( _rwMutex.Create(L"SBcacheEntry rw mutex") != VXItrd_RESULT_SUCCESS ) {
  379.     Error (109, L"%s%s", L"mutex", L"cache entry rw mutex");
  380.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  381.   }
  382.   return rc;
  383. }
  384. // Open the entry
  385. VXIcacheResult SBcacheEntryDetails::Open(VXIlogInterface       *log,
  386.  const SBcacheString   &moduleName,
  387.  const SBcacheKey      &key,
  388.  const SBcachePath     &path,
  389.  VXIcacheOpenMode       mode,
  390.  VXIint32               flags,
  391.  VXIulong               maxSizeBytes,
  392.  const VXIMap          *properties,
  393.  VXIMap                *streamInfo,
  394.  VXIcacheStream       **stream)
  395. {
  396.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  397.   FILE *filePtr = NULL;
  398.   // Lock and copy input data
  399.   switch ( mode ) {
  400.   case CACHE_MODE_WRITE:
  401.     if ( _rwMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  402.       Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, writer");
  403.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  404.     } else {
  405.       // If the open fails due to directory not existing, call
  406.       // path.CreateDirectories( ) to create the dir tree then open
  407.       // again
  408.       if ( ! _invalidated ) {
  409. filePtr = fopen (path.c_str( ), "wb");
  410.         int retries = 10; // work around possible race condition w/ rmdir
  411. while ((retries-- > 0) &&
  412.             ( ! filePtr ) &&
  413.             ( path.CreateDirectories( ) == VXIcache_RESULT_SUCCESS ))
  414.   filePtr = fopen (path.c_str( ), "wb");
  415.       }
  416.       if ( ! filePtr ) {
  417. if ( _invalidated ) {
  418.   // Invalidated or another thread attempted an open for write
  419.   // and failed, we only got here due to a race condition
  420.   // where we were waiting on the mutex to start our write
  421.   // before the failure/invalidation happened by the previous
  422.   // writer
  423.   rc = VXIcache_RESULT_FAILURE;
  424. } else {
  425.   // File open error
  426.   LogIOError (log, 213, path);
  427.   rc = VXIcache_RESULT_IO_ERROR;
  428. }
  429. _fileExists = false;
  430. _rwMutex.Unlock( );
  431.       } else {
  432. _fileExists = true;
  433. _creationCost = CACHE_CREATION_COST_DEFAULT;
  434. _flags = flags;
  435. _sizeBytes = 0;
  436.         // Only set the path and key if they differ
  437.         if (path != _path || key != _key) {
  438.           _path = path;
  439.           _key = key;
  440.         }
  441. // Load properties
  442. if ( properties ) {
  443.   const VXIValue *value =
  444.     VXIMapGetProperty (properties, CACHE_CREATION_COST);
  445.   if ( value ) {
  446.     if ( VXIValueGetType(value) == VALUE_INTEGER )
  447.       _creationCost = (VXIcacheCreationCost)
  448. VXIIntegerValue ((const VXIInteger *) value);
  449.     else
  450.       Error (log, 301, L"%s%d", L"VXIValueType",
  451.      VXIValueGetType(value));
  452.   }
  453. }
  454.       }
  455.     }
  456.     break;
  457.   case CACHE_MODE_READ:
  458.     if ( _rwMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) {
  459.       Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, reader");
  460.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  461.     } else {
  462.       if (( _fileExists ) && ( ! _invalidated )) {
  463. filePtr = fopen (_path.c_str( ), "rb");
  464. if ( ! filePtr ) {
  465.   _fileExists = false;
  466.   LogIOError (log, 214, _path);
  467.   _rwMutex.EndRead( );
  468.   rc = VXIcache_RESULT_IO_ERROR;
  469. }
  470.       } else {
  471. // Invalidated or another thread attempted an open for write
  472. // and failed, we only got here due to a race condition where
  473. // we were waiting on the mutex to start our read before the
  474. // failure/invalidation happened by the writer
  475. _rwMutex.EndRead( );
  476. rc = VXIcache_RESULT_FAILURE;
  477.       }
  478.     }
  479.     break;
  480.   default:
  481.     Error (log, 215, L"%s%d", L"mode", mode);
  482.     rc = VXIcache_RESULT_UNSUPPORTED;
  483.   }
  484.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  485.     // Update the accessed time
  486.     _lastAccessed = time(0);
  487.     if (mode == CACHE_MODE_WRITE)
  488.       _lastModified = _lastAccessed;
  489.     // Return stream information
  490.     if ( streamInfo ) {
  491.       if (( VXIMapSetProperty (streamInfo, CACHE_INFO_LAST_MODIFIED,
  492.        (VXIValue *) VXIIntegerCreate(_lastModified)) !=
  493.     VXIvalue_RESULT_SUCCESS ) ||
  494.   ( VXIMapSetProperty (streamInfo, CACHE_INFO_SIZE_BYTES,
  495.        (VXIValue *) VXIIntegerCreate (_sizeBytes)) !=
  496.     VXIvalue_RESULT_SUCCESS )) {
  497. Error (log, 100, NULL);
  498. rc = VXIcache_RESULT_OUT_OF_MEMORY;
  499.       }
  500.     }
  501.   }
  502.   // Return the stream
  503.   if ( rc == VXIcache_RESULT_SUCCESS ) {
  504.     SBcacheEntry entry(this);
  505.     *stream = new SBcacheStream (log, GetDiagBase( ), moduleName, key,
  506.  entry, mode,
  507.  ((flags & CACHE_FLAG_NONBLOCKING_IO) == 0),
  508.  maxSizeBytes, filePtr);
  509.     if ( ! *stream ) {
  510.       Error (log, 100, NULL);
  511.       fclose (filePtr);
  512.       Close (log, mode, 0, true);
  513.       rc = VXIcache_RESULT_OUT_OF_MEMORY;
  514.     }
  515.   }
  516.   Diag (log, SBCACHE_ENTRY_TAGID, L"Open", L"%s, %S, 0x%x, 0x%x: rc = %d",
  517. key.c_str( ), path.c_str( ), mode, flags, rc);
  518.   return rc;
  519. }
  520. // Close the entry
  521. VXIcacheResult SBcacheEntryDetails::Close(VXIlogInterface   *log,
  522.   VXIcacheOpenMode   mode,
  523.   VXIunsigned        sizeBytes,
  524.   bool               invalidate)
  525. {
  526.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  527.   Diag (log, SBCACHE_ENTRY_TAGID, L"Close", L"entering: %s, %S, 0x%x, %u, %d",
  528. _key.c_str( ), _path.c_str( ), mode, sizeBytes, invalidate);
  529.   // Invalidate the entry if requested to do so, we just set a flag so
  530.   // when the entry is deleted we remove the on-disk copy. Can't just
  531.   // do "_invalidated = invalidate" as there may be multiple readers
  532.   // at once, if one reader thinks we're good (don't invalidate) and
  533.   // another thinks we're bad (invalidate) don't want us to have race
  534.   // conditions where we ignore the invalidate request.
  535.   if ( invalidate )
  536.     _invalidated = true;
  537.   // Unlock the entry, note that we should avoid doing anything after
  538.   // the unlock (including logging ) because this object may get
  539.   // deleted as soon as we do so
  540.   switch ( mode ) {
  541.   case CACHE_MODE_WRITE:
  542.     _sizeBytes = sizeBytes;
  543.     if ( _rwMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  544.       Error (log, 111, L"%s%s", L"mutex", L"cache entry rw mutex, writer");
  545.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  546.     }
  547.     break;
  548.   case CACHE_MODE_READ:
  549.     if ( _rwMutex.EndRead( ) != VXItrd_RESULT_SUCCESS ) {
  550.       Error (log, 111, L"%s%s", L"mutex", L"cache entry rw mutex, reader");
  551.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  552.     }
  553.     break;
  554.   default:
  555.     Error (log, 211, L"%s%d", L"mode", mode);
  556.     rc = VXIcache_RESULT_FATAL_ERROR;
  557.   }
  558.   Diag (log, SBCACHE_ENTRY_TAGID, L"Close", L"exiting: rc = %d", rc);
  559.   return rc;
  560. }
  561. // Unlock the entry
  562. VXIcacheResult SBcacheEntryDetails::Unlock(VXIlogInterface       *log)
  563. {
  564.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  565.   if ( _rwMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  566.     Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, writer");
  567.     rc = VXIcache_RESULT_SYSTEM_ERROR;
  568.   } else {
  569.     if ( _flags & CACHE_FLAG_LOCK )
  570.       _flags = (_flags ^ CACHE_FLAG_LOCK);
  571.     if ( _flags & CACHE_FLAG_LOCK_MEMORY )
  572.       _flags = (_flags ^ CACHE_FLAG_LOCK_MEMORY);
  573.     if ( _rwMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  574.       Error (log, 111, L"%s%s", L"mutex", L"cache entry rw mutex, writer");
  575.       rc = VXIcache_RESULT_SYSTEM_ERROR;
  576.     }
  577.   }
  578.   Diag (log, SBCACHE_ENTRY_TAGID, L"Unlock", L"%s, %S: rc = %d",
  579.    _key.c_str( ), _path.c_str( ), rc);
  580.   return rc;
  581. }
  582. // Delete the on-disk entry, internal routine, no mutex held
  583. VXIcacheResult SBcacheEntryDetails::DeleteFile( )
  584. {
  585.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  586.   // Delete the file
  587.   if  ( _fileExists ) {
  588.     if ( remove (_path.c_str( )) != 0 )
  589.       LogIOError (216);
  590.     // Remove directory
  591.     SBcacheNString head(_path.c_str());
  592.     SBcacheNString::size_type pos = head.find_last_of("/\");
  593.     if (pos != SBcacheNString::npos) {
  594.       head = head.substr(0, pos);
  595.       if (!head.empty()) {
  596. #ifdef _win32_
  597.         RemoveDirectory(head.c_str());
  598. #else
  599.         rmdir(head.c_str());
  600. #endif
  601.       }
  602.     }
  603.     _fileExists = false;
  604.   }
  605.   Diag (SBCACHE_ENTRY_TAGID, L"DeleteFile", L"%s, %S: rc = %d",
  606. _key.c_str( ), _path.c_str( ), rc);
  607.   return rc;
  608. }
  609. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  610. // Construct a SBcacheEntry from details
  611. SBcacheEntry::SBcacheEntry (SBcacheEntryDetails *details) : _details(details)
  612. {
  613.   if ( SBcacheEntryDetails::AddRef (_details) != VXItrd_RESULT_SUCCESS )
  614.     _details = NULL;
  615. }
  616. // Destructor
  617. SBcacheEntry::~SBcacheEntry( )
  618. {
  619.   if ( _details )
  620.     SBcacheEntryDetails::Release (&_details);
  621. }
  622. // Create the entry
  623. VXIcacheResult SBcacheEntry::Create(VXIlogInterface *log,
  624.     VXIunsigned diagTagBase,
  625.     SBcacheMutex *refCountMutex)
  626. {
  627.   if ( _details )
  628.     return VXIcache_RESULT_FATAL_ERROR;
  629.   VXIcacheResult rc;
  630.   _details = new SBcacheEntryDetails (log, diagTagBase, refCountMutex);
  631.   if ( ! _details ) {
  632.     SBinetLogger::Error (log, MODULE_SBCACHE, 100, NULL);
  633.     rc = VXIcache_RESULT_OUT_OF_MEMORY;
  634.   } else {
  635.     rc = _details->Create( );
  636.   }
  637.   return rc;
  638. }
  639. // Open the entry
  640. VXIcacheResult SBcacheEntry::Open(VXIlogInterface       *log,
  641.   const SBcacheString   &moduleName,
  642.   const SBcacheKey      &key,
  643.   const SBcachePath     &path,
  644.   VXIcacheOpenMode       mode,
  645.   VXIint32               flags,
  646.   VXIulong               maxSizeBytes,
  647.   const VXIMap          *properties,
  648.   VXIMap                *streamInfo,
  649.   VXIcacheStream       **stream)
  650. {
  651.   return (_details == NULL ? VXIcache_RESULT_FATAL_ERROR :
  652.   _details->Open (log, moduleName, key, path, mode, flags,
  653.   maxSizeBytes, properties, streamInfo, stream));
  654. }
  655. // Close the entry
  656. VXIcacheResult SBcacheEntry::Close(VXIlogInterface  *log,
  657.    VXIcacheOpenMode  mode,
  658.    VXIunsigned       sizeBytes,
  659.    bool              invalidate)
  660. {
  661.   return (_details == NULL ? VXIcache_RESULT_FATAL_ERROR :
  662.   _details->Close (log, mode, sizeBytes, invalidate));
  663. }
  664. // Unlock the entry
  665. VXIcacheResult SBcacheEntry::Unlock(VXIlogInterface       *log)
  666. {
  667.   return (_details == NULL ? VXIcache_RESULT_FATAL_ERROR :
  668.   _details->Unlock (log));
  669. }
  670. // Accessors
  671. bool SBcacheEntry::IsLocked( ) const
  672. {
  673.   return _details->IsLocked( );
  674. }
  675. bool SBcacheEntry::IsExpired (time_t  cutoffTime,
  676.       time_t *lastAccessed) const
  677. {
  678.   return _details->IsExpired (cutoffTime, lastAccessed);
  679. }
  680. const SBcacheKey & SBcacheEntry::GetKey( ) const
  681. {
  682.   return _details->GetKey( );
  683. }
  684. const SBcachePath & SBcacheEntry::GetPath( ) const
  685. {
  686.   return _details->GetPath( );
  687. }
  688. VXIulong SBcacheEntry::GetSizeBytes (bool haveEntryOpen) const
  689. {
  690.   return _details->GetSizeBytes (haveEntryOpen);
  691. }
  692. // Error logging
  693. VXIlogResult SBcacheEntry::LogIOError (VXIunsigned errorID) const
  694. {
  695.   return _details->LogIOError (errorID);
  696. }
  697. // Copy constructor and assignment operator that implement reference
  698. // counting of the held SBcacheEntryData
  699. SBcacheEntry::SBcacheEntry (const SBcacheEntry & e) : _details(e._details)
  700. {
  701.   if ( SBcacheEntryDetails::AddRef (_details) != VXItrd_RESULT_SUCCESS )
  702.     _details = NULL;
  703. }
  704. SBcacheEntry & SBcacheEntry::operator= (const SBcacheEntry & e)
  705. {
  706.   if ( &e != this ) {
  707.     SBcacheEntryDetails::Release (&_details);
  708.     if ( SBcacheEntryDetails::AddRef (e._details) == VXItrd_RESULT_SUCCESS )
  709.       _details = e._details;
  710.   }
  711.   return *this;
  712. }
  713. // Comparison operators, smaller is defined as a preference for
  714. // deleting this entry first, equality is having equal preference
  715. bool SBcacheEntry::operator< (const SBcacheEntry &entry) const
  716. {
  717.   return _details->operator< (*(entry._details));
  718. }
  719. bool SBcacheEntry::operator> (const SBcacheEntry &entry) const
  720. {
  721.   return _details->operator> (*(entry._details));
  722. }
  723. bool SBcacheEntry::operator== (const SBcacheEntry &entry) const
  724. {
  725.   return _details->operator== (*(entry._details));
  726. }
  727. bool SBcacheEntry::operator!= (const SBcacheEntry &entry) const
  728. {
  729.   return _details->operator!= (*(entry._details));
  730. }