bdb_blobcache.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:37k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: bdb_blobcache.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 18:37:14  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.54
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: bdb_blobcache.cpp,v 1000.5 2004/06/01 18:37:14 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Anatoliy Kuznetsov
  35.  *
  36.  * File Description:  BDB libarary BLOB cache implementation.
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbitime.hpp>
  41. #include <corelib/ncbifile.hpp>
  42. #include <corelib/ncbi_process.hpp>
  43. #include <corelib/plugin_manager_impl.hpp>
  44. #include <bdb/bdb_blobcache.hpp>
  45. #include <bdb/bdb_cursor.hpp>
  46. #include <bdb/bdb_trans.hpp>
  47. #include <corelib/ncbimtx.hpp>
  48. #include <corelib/ncbitime.hpp>
  49. BEGIN_NCBI_SCOPE
  50. // Mutex to sync cache requests coming from different threads
  51. // All requests are protected with one mutex
  52. DEFINE_STATIC_FAST_MUTEX(x_BDB_BLOB_CacheMutex);
  53. // Mutex to sync int cache requests coming from different threads
  54. // All requests are protected with one mutex
  55. /*
  56. DEFINE_STATIC_FAST_MUTEX(x_BDB_IntCacheMutex);
  57. */
  58. static const unsigned int s_WriterBufferSize = 256 * 1024;
  59. /*
  60. static void s_MakeOverflowFileName(string& buf,
  61.                                    const string& path, 
  62.                                    const string& blob_key,
  63.                                    int           version)
  64. {
  65.     buf = path + blob_key + '_' + NStr::IntToString(version) + ".ov_";
  66. }
  67. */
  68. static void s_MakeOverflowFileName(string& buf,
  69.                                    const string& path, 
  70.                                    const string& key,
  71.                                    int           version,
  72.                                    const string& subkey)
  73. {
  74.     buf = path + key + '_'
  75.                + NStr::IntToString(version) + '_' + subkey + ".ov_";
  76. }
  77. struct SCacheDescr
  78. {
  79.     string    key;
  80.     int       version;
  81.     string    subkey;
  82.     int       overflow;
  83.     SCacheDescr(string x_key,
  84.                 int    x_version,
  85.                 string x_subkey,
  86.                 int    x_overflow)
  87.     : key(x_key),
  88.       version(x_version),
  89.       subkey(x_subkey),
  90.       overflow(x_overflow)
  91.     {}
  92.     SCacheDescr() {}
  93. };
  94. class CBDB_CacheIReader : public IReader
  95. {
  96. public:
  97.     CBDB_CacheIReader(CBDB_BLobStream* blob_stream)
  98.     : m_BlobStream(blob_stream),
  99.       m_OverflowFile(0),
  100.       m_Buffer(0)
  101.     {}
  102.     CBDB_CacheIReader(CNcbiIfstream* overflow_file)
  103.     : m_BlobStream(0),
  104.       m_OverflowFile(overflow_file),
  105.       m_Buffer(0)
  106.     {}
  107.     CBDB_CacheIReader(unsigned char* buf, size_t buf_size)
  108.     : m_BlobStream(0),
  109.       m_OverflowFile(0),
  110.       m_Buffer(buf),
  111.       m_BufferPtr(buf),
  112.       m_BufferSize(buf_size)
  113.     {
  114.     }
  115.     virtual ~CBDB_CacheIReader()
  116.     {
  117.         delete m_BlobStream;
  118.         delete m_OverflowFile;
  119.         delete[] m_Buffer;
  120.     }
  121.     virtual ERW_Result Read(void*   buf, 
  122.                             size_t  count,
  123.                             size_t* bytes_read)
  124.     {
  125.         if (count == 0)
  126.             return eRW_Success;
  127.         // Check if BLOB is memory based...
  128.         if (m_Buffer) {
  129.             if (m_BufferSize == 0) {
  130.                 *bytes_read = 0;
  131.                 return eRW_Eof;
  132.             }
  133.             *bytes_read = min(count, m_BufferSize);
  134.             ::memcpy(buf, m_BufferPtr, *bytes_read);
  135.             m_BufferPtr += *bytes_read;
  136.             m_BufferSize -= *bytes_read;
  137.             return eRW_Success;
  138.         }
  139.         // Check if BLOB is file based...
  140.         if (m_OverflowFile) {
  141.             CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  142.             m_OverflowFile->read((char*)buf, count);
  143.             *bytes_read = m_OverflowFile->gcount();
  144.             if (*bytes_read == 0) {
  145.                 return eRW_Eof;
  146.             }
  147.             return eRW_Success;
  148.         }
  149.         
  150.         // Reading from the BDB stream
  151.         size_t br;
  152.         {{
  153.         CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  154.         m_BlobStream->Read(buf, count, &br);
  155.         }}
  156.         if (bytes_read)
  157.             *bytes_read = br;
  158.         
  159.         if (br == 0) 
  160.             return eRW_Eof;
  161.         return eRW_Success;
  162.     }
  163.     virtual ERW_Result PendingCount(size_t* count)
  164.     {
  165.         if ( m_Buffer ) {
  166.             *count = m_BufferSize;
  167.             return eRW_Success;
  168.         }
  169.         else if ( m_OverflowFile ) {
  170.             *count = m_OverflowFile->good()? 1: 0;
  171.             return eRW_Success;
  172.         }
  173.         else if (m_BlobStream) {
  174.             *count = m_BlobStream->PendingCount();
  175.             return eRW_Success;
  176.         }
  177.         *count = 0;
  178.         return eRW_Error;
  179.     }
  180. private:
  181.     CBDB_CacheIReader(const CBDB_CacheIReader&);
  182.     CBDB_CacheIReader& operator=(const CBDB_CacheIReader&);
  183. private:
  184.     CBDB_BLobStream* m_BlobStream;
  185.     CNcbiIfstream*   m_OverflowFile;
  186.     unsigned char*   m_Buffer;
  187.     unsigned char*   m_BufferPtr;
  188.     size_t           m_BufferSize;
  189. };
  190. class CBDB_CacheIWriter : public IWriter
  191. {
  192. public:
  193.     CBDB_CacheIWriter(const char*         path,
  194.                       const string&       blob_key,
  195.                       int                 version,
  196.                       const string&       subkey,
  197.                       CBDB_BLobStream*    blob_stream,
  198.                       SCacheDB&           blob_db,
  199.                       SCache_AttrDB&      attr_db,
  200.                       int                 stamp_subkey)
  201.     : m_Path(path),
  202.       m_BlobKey(blob_key),
  203.       m_Version(version),
  204.       m_SubKey(subkey),
  205.       m_BlobStream(blob_stream),
  206.       m_BlobDB(blob_db),
  207.       m_AttrDB(attr_db),
  208.       m_Buffer(0),
  209.       m_BytesInBuffer(0),
  210.       m_OverflowFile(0),
  211.       m_StampSubKey(stamp_subkey)
  212.     {
  213.         m_Buffer = new unsigned char[s_WriterBufferSize];
  214.     }
  215.     virtual ~CBDB_CacheIWriter()
  216.     {
  217.         // Dumping the buffer
  218.         CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  219.         CBDB_Transaction trans(*m_AttrDB.GetEnv());
  220.         m_AttrDB.SetTransaction(&trans);
  221.         m_BlobDB.SetTransaction(&trans);
  222.         if (m_Buffer) {
  223.             _TRACE("LC: Dumping BDB BLOB size=" << m_BytesInBuffer);
  224.             m_BlobStream->SetTransaction(&trans);
  225.             m_BlobStream->Write(m_Buffer, m_BytesInBuffer);
  226.             m_BlobDB.Sync();
  227.             delete[] m_Buffer;
  228.         }
  229.         delete m_BlobStream;
  230.         m_AttrDB.key = m_BlobKey.c_str();
  231.         m_AttrDB.version = m_Version;
  232.         m_AttrDB.subkey = m_StampSubKey ? m_SubKey : "";
  233.         m_AttrDB.overflow = 0;
  234.         CTime time_stamp(CTime::eCurrent);
  235.         m_AttrDB.time_stamp = (unsigned)time_stamp.GetTimeT();
  236.         if (m_OverflowFile) {
  237.             m_AttrDB.overflow = 1;
  238.             delete m_OverflowFile;
  239.         }
  240.         m_AttrDB.UpdateInsert();
  241.         m_AttrDB.Sync();
  242.         trans.Commit();
  243.         m_AttrDB.GetEnv()->TransactionCheckpoint();
  244.     }
  245.     virtual ERW_Result Write(const void* buf, size_t count,
  246.                              size_t* bytes_written = 0)
  247.     {
  248.         *bytes_written = 0;
  249.         if (count == 0)
  250.             return eRW_Success;
  251.         CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  252.         unsigned int new_buf_length = m_BytesInBuffer + count;
  253.         if (m_Buffer) {
  254.             // Filling the buffer while we can
  255.             if (new_buf_length <= s_WriterBufferSize) {
  256.                 ::memcpy(m_Buffer + m_BytesInBuffer, buf, count);
  257.                 m_BytesInBuffer = new_buf_length;
  258.                 *bytes_written = count;
  259.                 return eRW_Success;
  260.             } else {
  261.                 // Buffer overflow. Writing to file.
  262.                 OpenOverflowFile();
  263.                 if (m_OverflowFile) {
  264.                     if (m_BytesInBuffer) {
  265.                         m_OverflowFile->write((char*)m_Buffer, 
  266.                                               m_BytesInBuffer);
  267.                     }
  268.                     delete[] m_Buffer;
  269.                     m_Buffer = 0;
  270.                     m_BytesInBuffer = 0;
  271.                 }
  272.             }
  273.         }
  274.         if (m_OverflowFile) {
  275.             m_OverflowFile->write((char*)buf, count);
  276.             if ( m_OverflowFile->good() ) {
  277.                 *bytes_written = count;
  278.                 return eRW_Success;
  279.             }
  280.         }
  281.         return eRW_Error;
  282.     }
  283.     /// Flush pending data (if any) down to output device.
  284.     virtual ERW_Result Flush(void)
  285.     {
  286.         // Dumping the buffer
  287.         CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  288.         CBDB_Transaction trans(*m_AttrDB.GetEnv());
  289.         m_AttrDB.SetTransaction(&trans);
  290.         m_BlobDB.SetTransaction(&trans);
  291.         if (m_Buffer) {
  292.             _TRACE("LC: Dumping BDB BLOB size=" << m_BytesInBuffer);
  293.             m_BlobStream->SetTransaction(&trans);
  294.             m_BlobStream->Write(m_Buffer, m_BytesInBuffer);
  295.             delete[] m_Buffer;
  296.             m_Buffer = 0;
  297.             m_BytesInBuffer = 0;
  298.         }
  299.         m_BlobDB.Sync();
  300.         if ( m_OverflowFile ) {
  301.             m_OverflowFile->flush();
  302.             if ( m_OverflowFile->bad() ) {
  303.                 return eRW_Error;
  304.             }
  305.         }
  306.         trans.Commit();
  307.         m_AttrDB.GetEnv()->TransactionCheckpoint();
  308.         return eRW_Success;
  309.     }
  310. private:
  311.     void OpenOverflowFile()
  312.     {
  313.         string path;
  314.         s_MakeOverflowFileName(path, m_Path, m_BlobKey, m_Version, m_SubKey);
  315.         _TRACE("LC: Making overflow file " << path);
  316.         m_OverflowFile =
  317.             new CNcbiOfstream(path.c_str(), 
  318.                               IOS_BASE::out | 
  319.                               IOS_BASE::trunc | 
  320.                               IOS_BASE::binary);
  321.         if (!m_OverflowFile->is_open()) {
  322.             ERR_POST("LC Error:Cannot create overflow file " << path);
  323.             delete m_OverflowFile;
  324.             m_OverflowFile = 0;
  325.         }
  326.     }
  327. private:
  328.     CBDB_CacheIWriter(const CBDB_CacheIWriter&);
  329.     CBDB_CacheIWriter& operator=(const CBDB_CacheIWriter&);
  330. private:
  331.     const char*           m_Path;
  332.     string                m_BlobKey;
  333.     int                   m_Version;
  334.     string                m_SubKey;
  335.     CBDB_BLobStream*      m_BlobStream;
  336.     SCacheDB&             m_BlobDB;
  337.     SCache_AttrDB&        m_AttrDB;
  338.     unsigned char*        m_Buffer;
  339.     unsigned int          m_BytesInBuffer;
  340.     CNcbiOfstream*        m_OverflowFile;
  341.     int                   m_StampSubKey;
  342. };
  343. CBDB_Cache::CBDB_Cache()
  344. : m_PidGuard(0),
  345.   m_Env(0),
  346.   m_CacheDB(0),
  347.   m_CacheAttrDB(0),
  348.   m_VersionFlag(eDropOlder)
  349. {
  350.     m_TimeStampFlag = fTimeStampOnRead | 
  351.                       fExpireLeastFrequentlyUsed |
  352.                       fPurgeOnStartup;
  353. }
  354. CBDB_Cache::~CBDB_Cache()
  355. {
  356.     Close();
  357. }
  358. void CBDB_Cache::Open(const char* cache_path, 
  359.                       const char* cache_name,
  360.                       ELockMode lm, 
  361.                       unsigned int cache_ram_size)
  362. {
  363.     {{
  364.     
  365.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  366.     Close();
  367.     m_Path = CDirEntry::AddTrailingPathSeparator(cache_path);
  368.     // Make sure our directory exists
  369.     {{
  370.         CDir dir(m_Path);
  371.         if ( !dir.Exists() ) {
  372.             dir.Create();
  373.         }
  374.     }}
  375.     string lock_file = string("lcs_") + string(cache_name) + string(".pid");
  376.     string lock_file_path = m_Path + lock_file;
  377.     switch (lm)
  378.     {
  379.     case ePidLock:
  380.         m_PidGuard = new CPIDGuard(lock_file_path, m_Path);
  381.         break;
  382.     case eNoLock:
  383.         break;
  384.     default:
  385.         break;
  386.     }
  387.     m_Env = new CBDB_Env();
  388.     // Check if bdb env. files are in place and try to join
  389.     CDir dir(m_Path);
  390.     CDir::TEntries fl = dir.GetEntries("__db.*", CDir::eIgnoreRecursive);
  391.     if (fl.empty()) {
  392.         if (cache_ram_size) {
  393.             m_Env->SetCacheSize(cache_ram_size);
  394.         }
  395.         m_Env->OpenWithTrans(cache_path);
  396.     } else {
  397.         if (cache_ram_size) {
  398.             m_Env->SetCacheSize(cache_ram_size);
  399.         }
  400.         try {
  401.             m_Env->JoinEnv(cache_path, CBDB_Env::eThreaded);
  402.             if (!m_Env->IsTransactional()) {
  403.                 LOG_POST(Warning << 
  404.                          "LC: Warning: Joined non-transactional environment ");
  405.             }
  406.         } 
  407.         catch (CBDB_Exception&)
  408.         {
  409.             m_Env->OpenWithTrans(cache_path);
  410.         }
  411.     }
  412.     m_Env->SetDirectDB(true);
  413.     m_Env->SetDirectLog(true);
  414.     m_CacheDB = new SCacheDB();
  415.     m_CacheAttrDB = new SCache_AttrDB();
  416.     m_CacheDB->SetEnv(*m_Env);
  417.     m_CacheAttrDB->SetEnv(*m_Env);
  418.     m_CacheDB->SetPageSize(32 * 1024);
  419.     string cache_db_name = 
  420.        string("lcs_") + string(cache_name) + string(".db");
  421.     string attr_db_name = 
  422.        string("lcs_") + string(cache_name) + string("_attr") + string(".db");
  423.     m_CacheDB->Open(cache_db_name.c_str(),    CBDB_RawFile::eReadWriteCreate);
  424.     m_CacheAttrDB->Open(attr_db_name.c_str(), CBDB_RawFile::eReadWriteCreate);
  425.     
  426.     }}
  427.     if (m_TimeStampFlag & fPurgeOnStartup) {
  428.         Purge(GetTimeout());
  429.     }
  430.     m_Env->TransactionCheckpoint();
  431. }
  432. void CBDB_Cache::Close()
  433. {
  434.     delete m_PidGuard;    m_PidGuard = 0;
  435.     delete m_CacheDB;     m_CacheDB = 0;
  436.     delete m_CacheAttrDB; m_CacheAttrDB = 0;
  437.     delete m_Env;         m_Env = 0;
  438. }
  439. void CBDB_Cache::SetTimeStampPolicy(TTimeStampFlags policy, 
  440.                                     int             timeout)
  441. {
  442.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  443.     m_TimeStampFlag = policy;
  444.     m_Timeout = timeout;
  445. }
  446. CBDB_Cache::TTimeStampFlags CBDB_Cache::GetTimeStampPolicy() const
  447. {
  448.     return m_TimeStampFlag;
  449. }
  450. int CBDB_Cache::GetTimeout()
  451. {
  452.     return m_Timeout;
  453. }
  454. void CBDB_Cache::SetVersionRetention(EKeepVersions policy)
  455. {
  456.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  457.     m_VersionFlag = policy;
  458. }
  459. CBDB_Cache::EKeepVersions CBDB_Cache::GetVersionRetention() const
  460. {
  461.     return m_VersionFlag;
  462. }
  463. void CBDB_Cache::Store(const string&  key,
  464.                        int            version,
  465.                        const string&  subkey,
  466.                        const void*    data,
  467.                        size_t         size)
  468. {
  469.     if (m_VersionFlag == eDropAll || m_VersionFlag == eDropOlder) {
  470.         Purge(key, subkey, 0, m_VersionFlag);
  471.     }
  472.     CBDB_Transaction trans(*m_Env);
  473.     m_CacheDB->SetTransaction(&trans);
  474.     m_CacheAttrDB->SetTransaction(&trans);
  475.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  476.     unsigned overflow = 0;
  477.     if (size < s_WriterBufferSize) {  // inline BLOB
  478.         m_CacheDB->key = key;
  479.         m_CacheDB->version = version;
  480.         m_CacheDB->subkey = subkey;
  481.         m_CacheDB->Insert(data, size);
  482.         overflow = 0;
  483.     } else { // overflow BLOB
  484.         string path;
  485.         s_MakeOverflowFileName(path, m_Path, key, version, subkey);
  486.         _TRACE("LC: Making overflow file " << path);
  487.         CNcbiOfstream oveflow_file(path.c_str(), 
  488.                                    IOS_BASE::out | 
  489.                                    IOS_BASE::trunc | 
  490.                                    IOS_BASE::binary);
  491.         if (!oveflow_file.is_open()) {
  492.             ERR_POST("LC Error:Cannot create overflow file " << path);
  493.             return;
  494.         }
  495.         oveflow_file.write((char*)data, size);
  496.         overflow = 1;
  497.     }
  498.     //
  499.     // Update cache element's attributes
  500.     //
  501.     CTime time_stamp(CTime::eCurrent);
  502.     m_CacheAttrDB->key = key;
  503.     m_CacheAttrDB->version = version;
  504.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  505.     m_CacheAttrDB->time_stamp = (unsigned)time_stamp.GetTimeT();
  506.     m_CacheAttrDB->overflow = overflow;
  507.     m_CacheAttrDB->UpdateInsert();
  508.     trans.Commit();
  509.     m_CacheAttrDB->GetEnv()->TransactionCheckpoint();
  510. }
  511. size_t CBDB_Cache::GetSize(const string&  key,
  512.                            int            version,
  513.                            const string&  subkey)
  514. {
  515.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  516.     m_CacheAttrDB->key = key;
  517.     m_CacheAttrDB->version = version;
  518.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  519.     EBDB_ErrCode ret = m_CacheAttrDB->Fetch();
  520.     if (ret != eBDB_Ok) {
  521.         return 0;
  522.     }
  523.     // check expiration here
  524.     if (m_TimeStampFlag & fCheckExpirationAlways) {
  525.         if (x_CheckTimestampExpired()) {
  526.             return 0;
  527.         }
  528.     }
  529.     int overflow = m_CacheAttrDB->overflow;
  530.     if (overflow) {
  531.         string path;
  532.         s_MakeOverflowFileName(path, m_Path, key, version, subkey);
  533.         CFile entry(path);
  534.         if (entry.Exists()) {
  535.             return (size_t) entry.GetLength();
  536.         }
  537.     }
  538.     // Regular inline BLOB
  539.     m_CacheDB->key = key;
  540.     m_CacheDB->version = version;
  541.     m_CacheDB->subkey = subkey;
  542.     ret = m_CacheDB->Fetch();
  543.     if (ret != eBDB_Ok) {
  544.         return 0;
  545.     }
  546.     return m_CacheDB->LobSize();
  547. }
  548. bool CBDB_Cache::Read(const string& key, 
  549.                       int           version, 
  550.                       const string& subkey,
  551.                       void*         buf, 
  552.                       size_t        buf_size)
  553. {
  554.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  555.     m_CacheAttrDB->key = key;
  556.     m_CacheAttrDB->version = version;
  557.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  558.     EBDB_ErrCode ret = m_CacheAttrDB->Fetch();
  559.     if (ret != eBDB_Ok) {
  560.         return false;
  561.     }
  562.     // check expiration
  563.     if (m_TimeStampFlag & fCheckExpirationAlways) {
  564.         if (x_CheckTimestampExpired()) {
  565.             return false;
  566.         }
  567.     }
  568.     int overflow = m_CacheAttrDB->overflow;
  569.     if (overflow) {
  570.         string path;
  571.         s_MakeOverflowFileName(path, m_Path, key, version, subkey);
  572.         auto_ptr<CNcbiIfstream>
  573.             overflow_file(new CNcbiIfstream(path.c_str(),
  574.                                             IOS_BASE::in | IOS_BASE::binary));
  575.         if (!overflow_file->is_open()) {
  576.             return false;
  577.         }
  578.         overflow_file->read((char*)buf, buf_size);
  579.         if (!*overflow_file) {
  580.             return false;
  581.         }
  582.     }
  583.     else {
  584.         m_CacheDB->key = key;
  585.         m_CacheDB->version = version;
  586.         m_CacheDB->subkey = subkey;
  587.         ret = m_CacheDB->Fetch();
  588.         if (ret != eBDB_Ok) {
  589.             return false;
  590.         }
  591.         ret = m_CacheDB->GetData(buf, buf_size);
  592.         if (ret != eBDB_Ok) {
  593.             return false;
  594.         }
  595.     }
  596.     if ( m_TimeStampFlag & fTimeStampOnRead ) {
  597.         x_UpdateAccessTime(key, version, subkey);
  598.     }
  599.     return true;
  600. }
  601. IReader* CBDB_Cache::GetReadStream(const string&  key, 
  602.                                    int            version,
  603.                                    const string&  subkey)
  604. {
  605.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  606.     m_CacheAttrDB->key = key;
  607.     m_CacheAttrDB->version = version;
  608.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  609.     EBDB_ErrCode ret = m_CacheAttrDB->Fetch();
  610.     if (ret != eBDB_Ok) {
  611.         return 0;
  612.     }
  613.     // check expiration
  614.     if (m_TimeStampFlag & fCheckExpirationAlways) {
  615.         if (x_CheckTimestampExpired()) {
  616.             return 0;
  617.         }
  618.     }
  619.     int overflow = m_CacheAttrDB->overflow;
  620.     // Check if it's an overflow BLOB (external file)
  621.     if (overflow) {
  622.         string path;
  623.         s_MakeOverflowFileName(path, m_Path, key, version, subkey);
  624.         auto_ptr<CNcbiIfstream> 
  625.             overflow_file(new CNcbiIfstream(path.c_str(),
  626.                                             IOS_BASE::in | IOS_BASE::binary));
  627.         if (!overflow_file->is_open()) {
  628.             return 0;
  629.         }
  630.         if ( m_TimeStampFlag & fTimeStampOnRead ) {
  631.             x_UpdateAccessTime(key, version, subkey);
  632.         }
  633.         return new CBDB_CacheIReader(overflow_file.release());
  634.     }
  635.     // Inline BLOB, reading from BDB storage
  636.     m_CacheDB->key = key;
  637.     m_CacheDB->version = version;
  638.     m_CacheDB->subkey = subkey;
  639.     
  640.     ret = m_CacheDB->Fetch();
  641.     if (ret != eBDB_Ok) {
  642.         return 0;
  643.     }
  644.     size_t bsize = m_CacheDB->LobSize();
  645.     unsigned char* buf = new unsigned char[bsize+1];
  646.     ret = m_CacheDB->GetData(buf, bsize);
  647.     if (ret != eBDB_Ok) {
  648.         return 0;
  649.     }
  650.     if ( m_TimeStampFlag & fTimeStampOnRead ) {
  651.         x_UpdateAccessTime(key, version, subkey);
  652.     }
  653.     return new CBDB_CacheIReader(buf, bsize);
  654. /*
  655.     CBDB_BLobStream* bstream = m_BlobDB.CreateStream();
  656.     return new CBDB_BLOB_CacheIReader(bstream);
  657. */
  658. }
  659. IWriter* CBDB_Cache::GetWriteStream(const string&    key,
  660.                                     int              version,
  661.                                     const string&    subkey)
  662. {
  663.     if (m_VersionFlag == eDropAll || m_VersionFlag == eDropOlder) {
  664.         Purge(key, subkey, 0, m_VersionFlag);
  665.     }
  666.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  667.     {
  668.         CBDB_Transaction trans(*m_Env);
  669.         m_CacheDB->SetTransaction(&trans);
  670.         m_CacheAttrDB->SetTransaction(&trans);
  671.         x_DropBlob(key.c_str(), version, subkey.c_str(), 1);
  672.         trans.Commit();
  673.     }
  674.     m_CacheDB->key = key;
  675.     m_CacheDB->version = version;
  676.     m_CacheDB->subkey = subkey;
  677.     CBDB_BLobStream* bstream = m_CacheDB->CreateStream();
  678.     return 
  679.         new CBDB_CacheIWriter(m_Path.c_str(), 
  680.                               key, 
  681.                               version,
  682.                               subkey,
  683.                               bstream, 
  684.                               *m_CacheDB,
  685.                               *m_CacheAttrDB,
  686.                               m_TimeStampFlag & fTrackSubKey);
  687. }
  688. void CBDB_Cache::Remove(const string& key)
  689. {
  690.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  691.     vector<SCacheDescr>  cache_elements;
  692.     // Search the records to delete
  693.     {{
  694.     CBDB_FileCursor cur(*m_CacheAttrDB);
  695.     cur.SetCondition(CBDB_FileCursor::eEQ);
  696.     cur.From << key;
  697.     while (cur.Fetch() == eBDB_Ok) {
  698.         int version = m_CacheAttrDB->version;
  699.         const char* subkey = m_CacheAttrDB->subkey;
  700.         int overflow = m_CacheAttrDB->overflow;
  701.         cache_elements.push_back(SCacheDescr(key, version, subkey, overflow));
  702.     }
  703.     }}
  704.     CBDB_Transaction trans(*m_Env);
  705.     m_CacheDB->SetTransaction(&trans);
  706.     m_CacheAttrDB->SetTransaction(&trans);
  707.     // Now delete all objects
  708.     ITERATE(vector<SCacheDescr>, it, cache_elements) {
  709.         x_DropBlob(it->key.c_str(), 
  710.                    it->version, 
  711.                    it->subkey.c_str(), 
  712.                    it->overflow);
  713.     }
  714. trans.Commit();
  715.     // Second pass scan if for some resons some cache elements are 
  716.     // still in the database
  717.     cache_elements.resize(0);
  718.     {{
  719.     CBDB_FileCursor cur(*m_CacheDB);
  720.     cur.SetCondition(CBDB_FileCursor::eEQ);
  721.     cur.From << key;
  722.     while (cur.Fetch() == eBDB_Ok) {
  723.         int version = m_CacheDB->version;
  724.         const char* subkey = m_CacheDB->subkey;
  725.         cache_elements.push_back(SCacheDescr(key, version, subkey, 0));
  726.     }
  727.     }}
  728.     ITERATE(vector<SCacheDescr>, it, cache_elements) {
  729.         x_DropBlob(it->key.c_str(), 
  730.                    it->version, 
  731.                    it->subkey.c_str(), 
  732.                    it->overflow);
  733.     }
  734.     trans.Commit();
  735.     m_CacheAttrDB->GetEnv()->TransactionCheckpoint();
  736. }
  737. time_t CBDB_Cache::GetAccessTime(const string&  key,
  738.                                  int            version,
  739.                                  const string&  subkey)
  740. {
  741.     _ASSERT(m_CacheAttrDB);
  742.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  743.     m_CacheAttrDB->key = key;
  744.     m_CacheAttrDB->version = version;
  745.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  746.     EBDB_ErrCode ret = m_CacheAttrDB->Fetch();
  747.     if (ret != eBDB_Ok) {
  748.         return 0;
  749.     }
  750.     
  751.     return (int) m_CacheAttrDB->time_stamp;
  752. }
  753. void CBDB_Cache::Purge(time_t           access_timeout,
  754.                        EKeepVersions    keep_last_version)
  755. {
  756.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  757.     if (keep_last_version == eDropAll && access_timeout == 0) {
  758.         x_TruncateDB();
  759.         return;
  760.     }
  761.     // Search the database for obsolete cache entries
  762.     vector<SCacheDescr> cache_entries;
  763.     {{
  764.     CBDB_FileCursor cur(*m_CacheAttrDB);
  765.     cur.SetCondition(CBDB_FileCursor::eFirst);
  766.     CTime time_stamp(CTime::eCurrent);
  767.     time_t curr = (int)time_stamp.GetTimeT();
  768.     int timeout = GetTimeout();
  769.     while (cur.Fetch() == eBDB_Ok) {
  770.         time_t db_time_stamp = m_CacheAttrDB->time_stamp;
  771.         int version = m_CacheAttrDB->version;
  772.         const char* key = m_CacheAttrDB->key;
  773.         int overflow = m_CacheAttrDB->overflow;
  774.         const char* subkey = m_CacheAttrDB->subkey;
  775.         if (curr - timeout > db_time_stamp) {
  776.             cache_entries.push_back(
  777.                             SCacheDescr(key, version, subkey, overflow));
  778.         }
  779.     } // while
  780.     }}
  781.     CBDB_Transaction trans(*m_Env);
  782.     m_CacheDB->SetTransaction(&trans);
  783.     m_CacheAttrDB->SetTransaction(&trans);
  784.     ITERATE(vector<SCacheDescr>, it, cache_entries) {
  785.         x_DropBlob(it->key.c_str(), 
  786.                    it->version, 
  787.                    it->subkey.c_str(), 
  788.                    it->overflow);
  789.     }
  790.     trans.Commit();
  791. }
  792. void CBDB_Cache::Purge(const string&    key,
  793.                        const string&    subkey,
  794.                        time_t           access_timeout,
  795.                        EKeepVersions    keep_last_version)
  796. {
  797.     CFastMutexGuard guard(x_BDB_BLOB_CacheMutex);
  798.     if (key.empty() || 
  799.         (keep_last_version == eDropAll && access_timeout == 0)) {
  800.         x_TruncateDB();
  801.         return;
  802.     }
  803.     // Search the database for obsolete cache entries
  804.     vector<SCacheDescr> cache_entries;
  805.     {{
  806.     CBDB_FileCursor cur(*m_CacheAttrDB);
  807.     cur.SetCondition(CBDB_FileCursor::eEQ);
  808.     cur.From << key;
  809.     CTime time_stamp(CTime::eCurrent);
  810.     time_t curr = (int)time_stamp.GetTimeT();
  811.     int timeout = GetTimeout();
  812.     while (cur.Fetch() == eBDB_Ok) {
  813.         time_t db_time_stamp = m_CacheAttrDB->time_stamp;
  814.         int version = m_CacheAttrDB->version;
  815.         const char* x_key = m_CacheAttrDB->key;
  816.         int overflow = m_CacheAttrDB->overflow;
  817.         string x_subkey = (const char*) m_CacheAttrDB->subkey;
  818.         if (subkey.empty()) {
  819.             
  820.         }
  821.         if ( (curr - timeout > db_time_stamp) ||
  822.             (subkey.empty() || (subkey == x_subkey)) 
  823.            ) {
  824.             cache_entries.push_back(
  825.                             SCacheDescr(x_key, version, x_subkey, overflow));
  826.         }
  827.     } // while
  828.     }}
  829.     CBDB_Transaction trans(*m_Env);
  830.     m_CacheDB->SetTransaction(&trans);
  831.     m_CacheAttrDB->SetTransaction(&trans);
  832.     ITERATE(vector<SCacheDescr>, it, cache_entries) {
  833.         x_DropBlob(it->key.c_str(), 
  834.                    it->version, 
  835.                    it->subkey.c_str(), 
  836.                    it->overflow);
  837.     }
  838.     
  839.     trans.Commit();
  840. }
  841. bool CBDB_Cache::x_CheckTimestampExpired()
  842. {
  843.     int timeout = GetTimeout();
  844.     int db_time_stamp = m_CacheAttrDB->time_stamp;
  845.     if (timeout) {
  846.         CTime time_stamp(CTime::eCurrent);
  847.         time_t curr = (int)time_stamp.GetTimeT();
  848.         if (curr - timeout > db_time_stamp) {
  849.             _TRACE("local cache item expired:" 
  850.                    << db_time_stamp << " curr=" << curr 
  851.                    << " diff=" << curr - db_time_stamp);
  852.             return true;
  853.         }
  854.     }
  855.     return false;
  856. }
  857. void CBDB_Cache::x_UpdateAccessTime(const string&  key,
  858.                                     int            version,
  859.                                     const string&  subkey)
  860. {
  861.     CBDB_Transaction trans(*m_Env);
  862.     m_CacheDB->SetTransaction(&trans);
  863.     m_CacheAttrDB->SetTransaction(&trans);
  864.     m_CacheAttrDB->key = key;
  865.     m_CacheAttrDB->version = version;
  866.     m_CacheAttrDB->subkey = (m_TimeStampFlag & fTrackSubKey) ? subkey : "";
  867.     EBDB_ErrCode ret =m_CacheAttrDB->Fetch();
  868.     if (ret != eBDB_Ok) {
  869.         m_CacheAttrDB->overflow = 0;
  870.     }
  871.     CTime time_stamp(CTime::eCurrent);
  872.     m_CacheAttrDB->time_stamp = (unsigned)time_stamp.GetTimeT();
  873.     m_CacheAttrDB->UpdateInsert();
  874.     trans.Commit();
  875. }
  876. void CBDB_Cache::x_TruncateDB()
  877. {
  878.     LOG_POST(Info << "CBDB_BLOB_Cache:: cache database truncated");
  879.     m_CacheDB->Truncate();
  880.     m_CacheAttrDB->Truncate();
  881.     // Scan the directory, delete overflow BLOBs
  882.     // TODO: remove overflow files only matching cache specific name
  883.     //       signatures. Since several caches may live in the same
  884.     //       directory we may delete some "extra" files
  885.     CDir dir(m_Path);
  886.     string ext;
  887.     string ov_("ov_");
  888.     if (dir.Exists()) {
  889.         CDir::TEntries  content(dir.GetEntries());
  890.         ITERATE(CDir::TEntries, it, content) {
  891.             if (!(*it)->IsFile()) {
  892.                 if (ext == ov_) {
  893.                     (*it)->Remove();
  894.                 }
  895.             }
  896.         }
  897.     }
  898. }
  899. void CBDB_Cache::x_DropBlob(const char*    key,
  900.                             int            version,
  901.                             const char*    subkey,
  902.                             int            overflow)
  903. {
  904.     _ASSERT(key);
  905.     _ASSERT(subkey);
  906.     if (overflow == 1) {
  907.         string path;
  908.         s_MakeOverflowFileName(path, m_Path, key, version, subkey);
  909.         CDirEntry entry(path);
  910.         if (entry.Exists()) {
  911.             entry.Remove();
  912.         }
  913.     }
  914.     m_CacheDB->key = key;
  915.     m_CacheDB->version = version;
  916.     m_CacheDB->subkey = subkey;
  917.     m_CacheDB->Delete(CBDB_RawFile::eIgnoreError);
  918.     m_CacheAttrDB->key = key;
  919.     m_CacheAttrDB->version = version;
  920.     m_CacheAttrDB->subkey = subkey;
  921.     m_CacheAttrDB->Delete(CBDB_RawFile::eIgnoreError);
  922. }
  923. const char* kBDBCacheDriverName = "bdbcache";
  924. /// Class factory for BDB implementation of ICache
  925. ///
  926. /// @internal
  927. ///
  928. class CBDB_CacheReaderCF : 
  929.     public CSimpleClassFactoryImpl<ICache, CBDB_Cache>
  930. {
  931. public:
  932.     typedef 
  933.       CSimpleClassFactoryImpl<ICache, CBDB_Cache> TParent;
  934. public:
  935.     CBDB_CacheReaderCF() : TParent(kBDBCacheDriverName, 0)
  936.     {
  937.     }
  938.     ~CBDB_CacheReaderCF()
  939.     {
  940.     }
  941. };
  942. void NCBI_BDB_ICacheEntryPoint(
  943.      CPluginManager<ICache>::TDriverInfoList&   info_list,
  944.      CPluginManager<ICache>::EEntryPointRequest method)
  945. {
  946.     CHostEntryPointImpl<CBDB_CacheReaderCF>::
  947.        NCBI_EntryPointImpl(info_list, method);
  948. }
  949. CBDB_CacheHolder::CBDB_CacheHolder(ICache* blob_cache, ICache* id_cache) 
  950. : m_BlobCache(blob_cache),
  951.   m_IdCache(id_cache)
  952. {}
  953. CBDB_CacheHolder::~CBDB_CacheHolder()
  954. {
  955.     delete m_BlobCache;
  956.     delete m_IdCache;
  957. }
  958. END_NCBI_SCOPE
  959. /*
  960.  * ===========================================================================
  961.  * $Log: bdb_blobcache.cpp,v $
  962.  * Revision 1000.5  2004/06/01 18:37:14  gouriano
  963.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.54
  964.  *
  965.  * Revision 1.54  2004/05/25 18:43:51  kuznets
  966.  * Fixed bug in setting cache RAM size, added additional protection when joining
  967.  * existing environment.
  968.  *
  969.  * Revision 1.53  2004/05/24 18:03:03  kuznets
  970.  * CBDB_Cache::Open added parameter to specify RAM cache size
  971.  *
  972.  * Revision 1.52  2004/05/17 20:55:11  gorelenk
  973.  * Added include of PCH ncbi_pch.hpp
  974.  *
  975.  * Revision 1.51  2004/04/28 16:58:56  kuznets
  976.  * Fixed deadlock in CBDB_Cache::Remove
  977.  *
  978.  * Revision 1.50  2004/04/28 12:21:32  kuznets
  979.  * Cleaned up dead code
  980.  *
  981.  * Revision 1.49  2004/04/28 12:11:22  kuznets
  982.  * Replaced static string with char* (fix crash on Linux)
  983.  *
  984.  * Revision 1.48  2004/04/27 19:12:01  kuznets
  985.  * Commented old cache implementation
  986.  *
  987.  * Revision 1.47  2004/03/26 14:54:21  kuznets
  988.  * Transaction checkpoint after database creation
  989.  *
  990.  * Revision 1.46  2004/03/26 14:05:39  kuznets
  991.  * Force transaction checkpoints and turn-off buffering
  992.  *
  993.  * Revision 1.45  2004/03/24 13:51:03  friedman
  994.  * Fixed mutex comments
  995.  *
  996.  * Revision 1.44  2004/03/23 19:22:08  friedman
  997.  * Replaced 'static CFastMutex' with DEFINE_STATIC_FAST_MUTEX
  998.  *
  999.  * Revision 1.43  2004/02/27 17:29:50  kuznets
  1000.  * +CBDB_CacheHolder
  1001.  *
  1002.  * Revision 1.42  2004/02/06 16:16:40  vasilche
  1003.  * Fixed delete m_Buffer -> delete[] m_Buffer.
  1004.  *
  1005.  * Revision 1.41  2004/02/02 21:24:29  vasilche
  1006.  * Fixed buffering of overflow file streams - open file in constructor.
  1007.  * Fixed processing of timestamps when fTimeStampOnRead flag is not set.
  1008.  *
  1009.  * Revision 1.40  2004/01/29 20:31:06  vasilche
  1010.  * Removed debug messages.
  1011.  *
  1012.  * Revision 1.39  2004/01/07 18:58:10  vasilche
  1013.  * Make message about joining to non-transactional environment a warning.
  1014.  *
  1015.  * Revision 1.38  2003/12/30 16:29:12  kuznets
  1016.  * Fixed a bug in overflow file naming.
  1017.  *
  1018.  * Revision 1.37  2003/12/29 18:47:20  kuznets
  1019.  * Cache opening changed to use free threaded environment.
  1020.  *
  1021.  * Revision 1.36  2003/12/29 17:08:15  kuznets
  1022.  * CBDB_CacheIWriter - using transactions to save BDB data
  1023.  *
  1024.  * Revision 1.35  2003/12/29 16:53:25  kuznets
  1025.  * Made Flush transactional
  1026.  *
  1027.  * Revision 1.34  2003/12/29 15:39:59  vasilche
  1028.  * Fixed subkey value in GetReadStream/GetWriteStream.
  1029.  *
  1030.  * Revision 1.33  2003/12/29 12:57:15  kuznets
  1031.  * Changes in Purge() method to make cursor loop lock independent
  1032.  * from the record delete function
  1033.  *
  1034.  * Revision 1.32  2003/12/16 13:45:11  kuznets
  1035.  * ICache implementation made transaction protected
  1036.  *
  1037.  * Revision 1.31  2003/12/08 16:13:15  kuznets
  1038.  * Added plugin mananger support
  1039.  *
  1040.  * Revision 1.30  2003/11/28 17:35:05  vasilche
  1041.  * Fixed new[]/delete discrepancy.
  1042.  *
  1043.  * Revision 1.29  2003/11/26 13:09:16  kuznets
  1044.  * Fixed bug in mutex locking
  1045.  *
  1046.  * Revision 1.28  2003/11/25 19:36:35  kuznets
  1047.  * + ICache implementation
  1048.  *
  1049.  * Revision 1.27  2003/11/06 14:20:38  kuznets
  1050.  * Warnings cleaned up
  1051.  *
  1052.  * Revision 1.26  2003/10/24 13:54:03  vasilche
  1053.  * Rolled back incorrect fix of PendingCount().
  1054.  *
  1055.  * Revision 1.25  2003/10/24 13:41:23  kuznets
  1056.  * Completed PendingCount implementaion
  1057.  *
  1058.  * Revision 1.24  2003/10/24 12:37:42  kuznets
  1059.  * Implemented cache locking using PID guard
  1060.  *
  1061.  * Revision 1.23  2003/10/23 13:46:38  vasilche
  1062.  * Implemented PendingCount() method.
  1063.  *
  1064.  * Revision 1.22  2003/10/22 19:08:29  vasilche
  1065.  * Added Flush() implementation.
  1066.  *
  1067.  * Revision 1.21  2003/10/21 12:11:27  kuznets
  1068.  * Fixed non-updated timestamp in Int cache.
  1069.  *
  1070.  * Revision 1.20  2003/10/20 20:44:20  vasilche
  1071.  * Added return true for overflow file read.
  1072.  *
  1073.  * Revision 1.19  2003/10/20 20:41:37  kuznets
  1074.  * Fixed bug in BlobCache::Read
  1075.  *
  1076.  * Revision 1.18  2003/10/20 20:35:33  kuznets
  1077.  * Blob cache Purge improved.
  1078.  *
  1079.  * Revision 1.17  2003/10/20 20:34:03  kuznets
  1080.  * Fixed bug with writing BLOB overflow attribute
  1081.  *
  1082.  * Revision 1.16  2003/10/20 20:15:30  kuznets
  1083.  * Fixed bug with expiration time retrieval
  1084.  *
  1085.  * Revision 1.15  2003/10/20 19:58:26  kuznets
  1086.  * Fixed bug in int cache expiration algorithm
  1087.  *
  1088.  * Revision 1.14  2003/10/20 17:53:03  kuznets
  1089.  * Dismissed blob cache entry overwrite protection.
  1090.  *
  1091.  * Revision 1.13  2003/10/20 16:34:20  kuznets
  1092.  * BLOB cache Store operation reimplemented to use external files.
  1093.  * BDB cache shared between tables by using common environment.
  1094.  * Overflow file limit set to 1M (was 2M)
  1095.  *
  1096.  * Revision 1.12  2003/10/17 14:11:41  kuznets
  1097.  * Implemented cached read from berkeley db BLOBs
  1098.  *
  1099.  * Revision 1.11  2003/10/16 19:29:18  kuznets
  1100.  * Added Int cache (AKA id resolution cache)
  1101.  *
  1102.  * Revision 1.10  2003/10/16 12:08:16  ucko
  1103.  * Address GCC 2.95 errors about missing sprintf declaration, and avoid
  1104.  * possible buffer overflows, by rewriting s_MakeOverflowFileName to use
  1105.  * C++ strings.
  1106.  *
  1107.  * Revision 1.9  2003/10/16 00:30:57  ucko
  1108.  * ios_base -> IOS_BASE (should fix GCC 2.95 build)
  1109.  *
  1110.  * Revision 1.8  2003/10/15 18:39:13  kuznets
  1111.  * Fixed minor incompatibility with the C++ language.
  1112.  *
  1113.  * Revision 1.7  2003/10/15 18:13:16  kuznets
  1114.  * Implemented new cache architecture based on combination of BDB tables
  1115.  * and plain files. Fixes the performance degradation in Berkeley DB
  1116.  * when it has to work with a lot of overflow pages.
  1117.  *
  1118.  * Revision 1.6  2003/10/06 16:24:19  kuznets
  1119.  * Fixed bug in Purge function
  1120.  * (truncated cache files with some parameters combination).
  1121.  *
  1122.  * Revision 1.5  2003/10/02 20:13:25  kuznets
  1123.  * Minor code cleanup
  1124.  *
  1125.  * Revision 1.4  2003/09/29 16:26:34  kuznets
  1126.  * Reflected ERW_Result rename + cleaned up 64-bit compilation
  1127.  *
  1128.  * Revision 1.3  2003/09/29 15:45:17  kuznets
  1129.  * Minor warning fixed
  1130.  *
  1131.  * Revision 1.2  2003/09/24 15:59:45  kuznets
  1132.  * Reflected changes in IReader/IWriter <util/reader_writer.hpp>
  1133.  *
  1134.  * Revision 1.1  2003/09/24 14:30:17  kuznets
  1135.  * Initial revision
  1136.  *
  1137.  *
  1138.  * ===========================================================================
  1139.  */