FileStore.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (c) 2001-2014
00003 **
00004 ** This file is part of the QuickFIX FIX Engine
00005 **
00006 ** This file may be distributed under the terms of the quickfixengine.org
00007 ** license as defined by quickfixengine.org and appearing in the file
00008 ** LICENSE included in the packaging of this file.
00009 **
00010 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00011 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00012 **
00013 ** See http://www.quickfixengine.org/LICENSE for licensing information.
00014 **
00015 ** Contact ask@quickfixengine.org if any conditions of this licensing are
00016 ** not clear to you.
00017 **
00018 ****************************************************************************/
00019 
00020 #ifdef _MSC_VER
00021 #include "stdafx.h"
00022 #else
00023 #include "config.h"
00024 #endif
00025 
00026 #include "FileStore.h"
00027 #include "SessionID.h"
00028 #include "Parser.h"
00029 #include "Utility.h"
00030 #include <fstream>
00031 
00032 namespace FIX
00033 {
00034 FileStore::FileStore( std::string path, const SessionID& s )
00035 : m_msgFile( 0 ), m_headerFile( 0 ), m_seqNumsFile( 0 ), m_sessionFile( 0 )
00036 {
00037   file_mkdir( path.c_str() );
00038 
00039   if ( path.empty() ) path = ".";
00040   const std::string& begin =
00041     s.getBeginString().getString();
00042   const std::string& sender =
00043     s.getSenderCompID().getString();
00044   const std::string& target =
00045     s.getTargetCompID().getString();
00046   const std::string& qualifier =
00047     s.getSessionQualifier();
00048 
00049   std::string sessionid = begin + "-" + sender + "-" + target;
00050   if( qualifier.size() )
00051     sessionid += "-" + qualifier;
00052 
00053   std::string prefix
00054     = file_appendpath(path, sessionid + ".");
00055 
00056   m_msgFileName = prefix + "body";
00057   m_headerFileName = prefix + "header";
00058   m_seqNumsFileName = prefix + "seqnums";
00059   m_sessionFileName = prefix + "session";
00060 
00061   try
00062   {
00063     open( false );
00064   }
00065   catch ( IOException & e )
00066   {
00067     throw ConfigError( e.what() );
00068   }
00069 }
00070 
00071 FileStore::~FileStore()
00072 {
00073   if( m_msgFile ) fclose( m_msgFile );
00074   if( m_headerFile ) fclose( m_headerFile );
00075   if( m_seqNumsFile ) fclose( m_seqNumsFile );
00076   if( m_sessionFile ) fclose( m_sessionFile );
00077 }
00078 
00079 void FileStore::open( bool deleteFile )
00080 {
00081   if ( m_msgFile ) fclose( m_msgFile );
00082   if ( m_headerFile ) fclose( m_headerFile );
00083   if ( m_seqNumsFile ) fclose( m_seqNumsFile );
00084   if ( m_sessionFile ) fclose( m_sessionFile );
00085 
00086   m_msgFile = 0;
00087   m_headerFile = 0;
00088   m_seqNumsFile = 0;
00089   m_sessionFile = 0;
00090 
00091   if ( deleteFile )
00092   {
00093     file_unlink( m_msgFileName.c_str() );
00094     file_unlink( m_headerFileName.c_str() );
00095     file_unlink( m_seqNumsFileName.c_str() );
00096     file_unlink( m_sessionFileName.c_str() );
00097   }
00098 
00099   populateCache();
00100   m_msgFile = file_fopen( m_msgFileName.c_str(), "r+" );
00101   if ( !m_msgFile ) m_msgFile = file_fopen( m_msgFileName.c_str(), "w+" );
00102   if ( !m_msgFile ) throw ConfigError( "Could not open body file: " + m_msgFileName );
00103 
00104   m_headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
00105   if ( !m_headerFile ) m_headerFile = file_fopen( m_headerFileName.c_str(), "w+" );
00106   if ( !m_headerFile ) throw ConfigError( "Could not open header file: " + m_headerFileName );
00107 
00108   m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
00109   if ( !m_seqNumsFile ) m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "w+" );
00110   if ( !m_seqNumsFile ) throw ConfigError( "Could not open seqnums file: " + m_seqNumsFileName );
00111 
00112   bool setCreationTime = false;
00113   m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r" );
00114   if ( !m_sessionFile ) setCreationTime = true;
00115   else fclose( m_sessionFile );
00116 
00117   m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
00118   if ( !m_sessionFile ) m_sessionFile = file_fopen( m_sessionFileName.c_str(), "w+" );
00119   if ( !m_sessionFile ) throw ConfigError( "Could not open session file" );
00120   if ( setCreationTime ) setSession();
00121 
00122   setNextSenderMsgSeqNum( getNextSenderMsgSeqNum() );
00123   setNextTargetMsgSeqNum( getNextTargetMsgSeqNum() );
00124 }
00125 
00126 void FileStore::populateCache()
00127 {
00128   FILE* headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
00129   if ( headerFile )
00130   {
00131     int num;
00132     long offset;
00133     size_t size;
00134 
00135     while ( FILE_FSCANF( headerFile, "%d,%ld,%lu ", &num, &offset, &size ) == 3 )
00136       m_offsets[ num ] = std::make_pair( offset, size );
00137     fclose( headerFile );
00138   }
00139 
00140   FILE* seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
00141   if ( seqNumsFile )
00142   {
00143     int sender, target;
00144     if ( FILE_FSCANF( seqNumsFile, "%d : %d", &sender, &target ) == 2 )
00145     {
00146       m_cache.setNextSenderMsgSeqNum( sender );
00147       m_cache.setNextTargetMsgSeqNum( target );
00148     }
00149     fclose( seqNumsFile );
00150   }
00151 
00152   FILE* sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
00153   if ( sessionFile )
00154   {
00155     char time[ 22 ];
00156 #ifdef HAVE_FSCANF_S
00157     int result = FILE_FSCANF( sessionFile, "%s", time, 22 );
00158 #else
00159     int result = FILE_FSCANF( sessionFile, "%s", time );
00160 #endif
00161     if( result == 1 )
00162     {
00163       m_cache.setCreationTime( UtcTimeStampConvertor::convert( time, true ) );
00164     }
00165     fclose( sessionFile );
00166   }
00167 }
00168 
00169 MessageStore* FileStoreFactory::create( const SessionID& s )
00170 {
00171   if ( m_path.size() ) return new FileStore( m_path, s );
00172 
00173   std::string path;
00174   Dictionary settings = m_settings.get( s );
00175   path = settings.getString( FILE_STORE_PATH );
00176   return new FileStore( path, s );
00177 }
00178 
00179 void FileStoreFactory::destroy( MessageStore* pStore )
00180 {
00181   delete pStore;
00182 }
00183 
00184 bool FileStore::set( int msgSeqNum, const std::string& msg )
00185 throw ( IOException )
00186 {
00187   if ( fseek( m_msgFile, 0, SEEK_END ) ) 
00188     throw IOException( "Cannot seek to end of " + m_msgFileName );
00189   if ( fseek( m_headerFile, 0, SEEK_END ) ) 
00190     throw IOException( "Cannot seek to end of " + m_headerFileName );
00191 
00192   long offset = ftell( m_msgFile );
00193   if ( offset < 0 ) 
00194     throw IOException( "Unable to get file pointer position from " + m_msgFileName );
00195   size_t size = msg.size();
00196 
00197   if ( fprintf( m_headerFile, "%d,%ld,%lu ", msgSeqNum, offset, size ) < 0 )
00198     throw IOException( "Unable to write to file " + m_headerFileName );
00199   m_offsets[ msgSeqNum ] = std::make_pair( offset, size );
00200   fwrite( msg.c_str(), sizeof( char ), msg.size(), m_msgFile );
00201   if ( ferror( m_msgFile ) ) 
00202     throw IOException( "Unable to write to file " + m_msgFileName );
00203   if ( fflush( m_msgFile ) == EOF ) 
00204     throw IOException( "Unable to flush file " + m_msgFileName );
00205   if ( fflush( m_headerFile ) == EOF ) 
00206     throw IOException( "Unable to flush file " + m_headerFileName );
00207   return true;
00208 }
00209 
00210 void FileStore::get( int begin, int end,
00211                      std::vector < std::string > & result ) const
00212 throw ( IOException )
00213 {
00214   result.clear();
00215   std::string msg;
00216   for ( int i = begin; i <= end; ++i )
00217   {
00218     if ( get( i, msg ) )
00219       result.push_back( msg );
00220   }
00221 }
00222 
00223 int FileStore::getNextSenderMsgSeqNum() const throw ( IOException )
00224 {
00225   return m_cache.getNextSenderMsgSeqNum();
00226 }
00227 
00228 int FileStore::getNextTargetMsgSeqNum() const throw ( IOException )
00229 {
00230   return m_cache.getNextTargetMsgSeqNum();
00231 }
00232 
00233 void FileStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
00234 {
00235   m_cache.setNextSenderMsgSeqNum( value );
00236   setSeqNum();
00237 }
00238 
00239 void FileStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
00240 {
00241   m_cache.setNextTargetMsgSeqNum( value );
00242   setSeqNum();
00243 }
00244 
00245 void FileStore::incrNextSenderMsgSeqNum() throw ( IOException )
00246 {
00247   m_cache.incrNextSenderMsgSeqNum();
00248   setSeqNum();
00249 }
00250 
00251 void FileStore::incrNextTargetMsgSeqNum() throw ( IOException )
00252 {
00253   m_cache.incrNextTargetMsgSeqNum();
00254   setSeqNum();
00255 }
00256 
00257 UtcTimeStamp FileStore::getCreationTime() const throw ( IOException )
00258 {
00259   return m_cache.getCreationTime();
00260 }
00261 
00262 void FileStore::reset() throw ( IOException )
00263 {
00264   try
00265   {
00266     m_cache.reset();
00267     open( true );
00268     setSession();
00269   }
00270   catch( std::exception& e )
00271   {
00272     throw IOException( e.what() );
00273   }
00274 }
00275 
00276 void FileStore::refresh() throw ( IOException )
00277 {
00278   try
00279   {
00280     m_cache.reset();
00281     open( false );
00282   }
00283   catch( std::exception& e )
00284   {
00285     throw IOException( e.what() );
00286   }
00287 }
00288 
00289 void FileStore::setSeqNum()
00290 {
00291   rewind( m_seqNumsFile );
00292   fprintf( m_seqNumsFile, "%10.10d : %10.10d",
00293            getNextSenderMsgSeqNum(), getNextTargetMsgSeqNum() );
00294   if ( ferror( m_seqNumsFile ) ) 
00295     throw IOException( "Unable to write to file " + m_seqNumsFileName );
00296   if ( fflush( m_seqNumsFile ) ) 
00297     throw IOException( "Unable to flush file " + m_seqNumsFileName );
00298 }
00299 
00300 void FileStore::setSession()
00301 {
00302   rewind( m_sessionFile );
00303   fprintf( m_sessionFile, "%s",
00304            UtcTimeStampConvertor::convert( m_cache.getCreationTime() ).c_str() );
00305   if ( ferror( m_sessionFile ) ) 
00306     throw IOException( "Unable to write to file " + m_sessionFileName );
00307   if ( fflush( m_sessionFile ) ) 
00308     throw IOException( "Unable to flush file " + m_sessionFileName );
00309 }
00310 
00311 bool FileStore::get( int msgSeqNum, std::string& msg ) const
00312 throw ( IOException )
00313 {
00314   NumToOffset::const_iterator find = m_offsets.find( msgSeqNum );
00315   if ( find == m_offsets.end() ) return false;
00316   const OffsetSize& offset = find->second;
00317   if ( fseek( m_msgFile, offset.first, SEEK_SET ) ) 
00318     throw IOException( "Unable to seek in file " + m_msgFileName );
00319   char* buffer = new char[ offset.second + 1 ];
00320   size_t result = fread( buffer, sizeof( char ), offset.second, m_msgFile );
00321   if ( ferror( m_msgFile ) || result != (size_t)offset.second ) 
00322   {
00323     delete [] buffer;
00324     throw IOException( "Unable to read from file " + m_msgFileName );
00325   }
00326   buffer[ offset.second ] = 0;
00327   msg = buffer;
00328   delete [] buffer;
00329   return true;
00330 }
00331 
00332 } //namespace FIX

Generated on Mon Sep 15 2014 01:23:54 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001