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, offset, size;
00132     while ( FILE_FSCANF( headerFile, "%d,%d,%d ", &num, &offset, &size ) == 3 )
00133       m_offsets[ num ] = std::make_pair( offset, size );
00134     fclose( headerFile );
00135   }
00136 
00137   FILE* seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
00138   if ( seqNumsFile )
00139   {
00140     int sender, target;
00141     if ( FILE_FSCANF( seqNumsFile, "%d : %d", &sender, &target ) == 2 )
00142     {
00143       m_cache.setNextSenderMsgSeqNum( sender );
00144       m_cache.setNextTargetMsgSeqNum( target );
00145     }
00146     fclose( seqNumsFile );
00147   }
00148 
00149   FILE* sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
00150   if ( sessionFile )
00151   {
00152     char time[ 22 ];
00153 #ifdef HAVE_FSCANF_S
00154     int result = FILE_FSCANF( sessionFile, "%s", time, 22 );
00155 #else
00156     int result = FILE_FSCANF( sessionFile, "%s", time );
00157 #endif
00158     if( result == 1 )
00159     {
00160       m_cache.setCreationTime( UtcTimeStampConvertor::convert( time, true ) );
00161     }
00162     fclose( sessionFile );
00163   }
00164 }
00165 
00166 MessageStore* FileStoreFactory::create( const SessionID& s )
00167 {
00168   if ( m_path.size() ) return new FileStore( m_path, s );
00169 
00170   std::string path;
00171   Dictionary settings = m_settings.get( s );
00172   path = settings.getString( FILE_STORE_PATH );
00173   return new FileStore( path, s );
00174 }
00175 
00176 void FileStoreFactory::destroy( MessageStore* pStore )
00177 {
00178   delete pStore;
00179 }
00180 
00181 bool FileStore::set( int msgSeqNum, const std::string& msg )
00182 throw ( IOException )
00183 {
00184   if ( fseek( m_msgFile, 0, SEEK_END ) ) 
00185     throw IOException( "Cannot seek to end of " + m_msgFileName );
00186   if ( fseek( m_headerFile, 0, SEEK_END ) ) 
00187     throw IOException( "Cannot seek to end of " + m_headerFileName );
00188 
00189   int offset = ftell( m_msgFile );
00190   if ( offset < 0 ) 
00191     throw IOException( "Unable to get file pointer position from " + m_msgFileName );
00192   int size = msg.size();
00193 
00194   if ( fprintf( m_headerFile, "%d,%d,%d ", msgSeqNum, offset, size ) < 0 )
00195     throw IOException( "Unable to write to file " + m_headerFileName );
00196   m_offsets[ msgSeqNum ] = std::make_pair( offset, size );
00197   fwrite( msg.c_str(), sizeof( char ), msg.size(), m_msgFile );
00198   if ( ferror( m_msgFile ) ) 
00199     throw IOException( "Unable to write to file " + m_msgFileName );
00200   if ( fflush( m_msgFile ) == EOF ) 
00201     throw IOException( "Unable to flush file " + m_msgFileName );
00202   if ( fflush( m_headerFile ) == EOF ) 
00203     throw IOException( "Unable to flush file " + m_headerFileName );
00204   return true;
00205 }
00206 
00207 void FileStore::get( int begin, int end,
00208                      std::vector < std::string > & result ) const
00209 throw ( IOException )
00210 {
00211   result.clear();
00212   std::string msg;
00213   for ( int i = begin; i <= end; ++i )
00214   {
00215     if ( get( i, msg ) )
00216       result.push_back( msg );
00217   }
00218 }
00219 
00220 int FileStore::getNextSenderMsgSeqNum() const throw ( IOException )
00221 {
00222   return m_cache.getNextSenderMsgSeqNum();
00223 }
00224 
00225 int FileStore::getNextTargetMsgSeqNum() const throw ( IOException )
00226 {
00227   return m_cache.getNextTargetMsgSeqNum();
00228 }
00229 
00230 void FileStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
00231 {
00232   m_cache.setNextSenderMsgSeqNum( value );
00233   setSeqNum();
00234 }
00235 
00236 void FileStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
00237 {
00238   m_cache.setNextTargetMsgSeqNum( value );
00239   setSeqNum();
00240 }
00241 
00242 void FileStore::incrNextSenderMsgSeqNum() throw ( IOException )
00243 {
00244   m_cache.incrNextSenderMsgSeqNum();
00245   setSeqNum();
00246 }
00247 
00248 void FileStore::incrNextTargetMsgSeqNum() throw ( IOException )
00249 {
00250   m_cache.incrNextTargetMsgSeqNum();
00251   setSeqNum();
00252 }
00253 
00254 UtcTimeStamp FileStore::getCreationTime() const throw ( IOException )
00255 {
00256   return m_cache.getCreationTime();
00257 }
00258 
00259 void FileStore::reset() throw ( IOException )
00260 {
00261   try
00262   {
00263     m_cache.reset();
00264     open( true );
00265     setSession();
00266   }
00267   catch( std::exception& e )
00268   {
00269     throw IOException( e.what() );
00270   }
00271 }
00272 
00273 void FileStore::refresh() throw ( IOException )
00274 {
00275   try
00276   {
00277     m_cache.reset();
00278     open( false );
00279   }
00280   catch( std::exception& e )
00281   {
00282     throw IOException( e.what() );
00283   }
00284 }
00285 
00286 void FileStore::setSeqNum()
00287 {
00288   rewind( m_seqNumsFile );
00289   fprintf( m_seqNumsFile, "%10.10d : %10.10d",
00290            getNextSenderMsgSeqNum(), getNextTargetMsgSeqNum() );
00291   if ( ferror( m_seqNumsFile ) ) 
00292     throw IOException( "Unable to write to file " + m_seqNumsFileName );
00293   if ( fflush( m_seqNumsFile ) ) 
00294     throw IOException( "Unable to flush file " + m_seqNumsFileName );
00295 }
00296 
00297 void FileStore::setSession()
00298 {
00299   rewind( m_sessionFile );
00300   fprintf( m_sessionFile, "%s",
00301            UtcTimeStampConvertor::convert( m_cache.getCreationTime() ).c_str() );
00302   if ( ferror( m_sessionFile ) ) 
00303     throw IOException( "Unable to write to file " + m_sessionFileName );
00304   if ( fflush( m_sessionFile ) ) 
00305     throw IOException( "Unable to flush file " + m_sessionFileName );
00306 }
00307 
00308 bool FileStore::get( int msgSeqNum, std::string& msg ) const
00309 throw ( IOException )
00310 {
00311   NumToOffset::const_iterator find = m_offsets.find( msgSeqNum );
00312   if ( find == m_offsets.end() ) return false;
00313   const OffsetSize& offset = find->second;
00314   if ( fseek( m_msgFile, offset.first, SEEK_SET ) ) 
00315     throw IOException( "Unable to seek in file " + m_msgFileName );
00316   char* buffer = new char[ offset.second + 1 ];
00317   size_t result = fread( buffer, sizeof( char ), offset.second, m_msgFile );
00318   if ( ferror( m_msgFile ) || result != (size_t)offset.second ) 
00319   {
00320     delete [] buffer;
00321     throw IOException( "Unable to read from file " + m_msgFileName );
00322   }
00323   buffer[ offset.second ] = 0;
00324   msg = buffer;
00325   delete [] buffer;
00326   return true;
00327 }
00328 
00329 } //namespace FIX

Generated on Mon Jun 23 2014 23:49:37 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001