Index Source Files Annotated Class List Alphabetical Class List Class Hierarchy Graphical Class Hierarchy

# FileStore.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002 ** Copyright (c) quickfixengine.org  All rights reserved.
    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 #include "CallStack.h"
    00026
    00027 #include "FileStore.h"
    00028 #include "SessionID.h"
    00029 #include "Parser.h"
    00030 #include "Utility.h"
    00031 #include <fstream>
    00032
    00033 namespace FIX
    00034 {
    00035 FileStore::FileStore( std::string path, const SessionID& s )
    00036 : m_msgFile( 0 ), m_headerFile( 0 ), m_seqNumsFile( 0 ), m_sessionFile( 0 )
    00037 {
    00038   file_mkdir( path.c_str() );
    00039
    00040   if ( path.empty() ) path = ".";
    00041   const std::string& begin =
    00042     s.getBeginString().getString();
    00043   const std::string& sender =
    00044     s.getSenderCompID().getString();
    00045   const std::string& target =
    00046     s.getTargetCompID().getString();
    00047   const std::string& qualifier =
    00048     s.getSessionQualifier();
    00049
    00050   std::string sessionid = begin + "-" + sender + "-" + target;
    00051   if( qualifier.size() )
    00052     sessionid += "-" + qualifier;
    00053
    00054   std::string prefix
    00055     = file_appendpath(path, sessionid + ".");
    00056
    00057   m_msgFileName = prefix + "body";
    00058   m_headerFileName = prefix + "header";
    00059   m_seqNumsFileName = prefix + "seqnums";
    00060   m_sessionFileName = prefix + "session";
    00061
    00062   try
    00063   {
    00064     open( false );
    00065   }
    00066   catch ( IOException & e )
    00067   {
    00068     throw ConfigError( e.what() );
    00069   }
    00070 }
    00071
    00072 FileStore::~FileStore()
    00073 {
    00074   if( m_msgFile ) fclose( m_msgFile );
    00075   if( m_headerFile ) fclose( m_headerFile );
    00076   if( m_seqNumsFile ) fclose( m_seqNumsFile );
    00077   if( m_sessionFile ) fclose( m_sessionFile );
    00078 }
    00079
    00080 void FileStore::open( bool deleteFile )
    00081 { QF_STACK_PUSH(FileStore::open)
    00082
    00083   if ( m_msgFile ) fclose( m_msgFile );
    00084   if ( m_headerFile ) fclose( m_headerFile );
    00085   if ( m_seqNumsFile ) fclose( m_seqNumsFile );
    00086   if ( m_sessionFile ) fclose( m_sessionFile );
    00087
    00088   m_msgFile = 0;
    00089   m_headerFile = 0;
    00090   m_seqNumsFile = 0;
    00091   m_sessionFile = 0;
    00092
    00093   if ( deleteFile )
    00094   {
    00095     file_unlink( m_msgFileName.c_str() );
    00096     file_unlink( m_headerFileName.c_str() );
    00097     file_unlink( m_seqNumsFileName.c_str() );
    00098     file_unlink( m_sessionFileName.c_str() );
    00099   }
    00100
    00101   populateCache();
    00102   m_msgFile = file_fopen( m_msgFileName.c_str(), "r+" );
    00103   if ( !m_msgFile ) m_msgFile = file_fopen( m_msgFileName.c_str(), "w+" );
    00104   if ( !m_msgFile ) throw ConfigError( "Could not open body file: " + m_msgFileName );
    00105
    00106   m_headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
    00107   if ( !m_headerFile ) m_headerFile = file_fopen( m_headerFileName.c_str(), "w+" );
    00108   if ( !m_headerFile ) throw ConfigError( "Could not open header file: " + m_headerFileName );
    00109
    00110   m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
    00111   if ( !m_seqNumsFile ) m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "w+" );
    00112   if ( !m_seqNumsFile ) throw ConfigError( "Could not open seqnums file: " + m_seqNumsFileName );
    00113
    00114   bool setCreationTime = false;
    00115   m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r" );
    00116   if ( !m_sessionFile ) setCreationTime = true;
    00117   else fclose( m_sessionFile );
    00118
    00119   m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
    00120   if ( !m_sessionFile ) m_sessionFile = file_fopen( m_sessionFileName.c_str(), "w+" );
    00121   if ( !m_sessionFile ) throw ConfigError( "Could not open session file" );
    00122   if ( setCreationTime ) setSession();
    00123
    00124   setNextSenderMsgSeqNum( getNextSenderMsgSeqNum() );
    00125   setNextTargetMsgSeqNum( getNextTargetMsgSeqNum() );
    00126
    00127   QF_STACK_POP
    00128 }
    00129
    00130 void FileStore::populateCache()
    00131 { QF_STACK_PUSH(FileStore::populateCache)
    00132
    00133   std::string msg;
    00134   Message message;
    00135
    00136   FILE* headerFile;
    00137   headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
    00138   if ( headerFile )
    00139   {
    00140     int num, offset, size;
    00141     while ( FILE_FSCANF( headerFile, "%d,%d,%d ", &num, &offset, &size ) == 3 )
    00142       m_offsets[ num ] = std::make_pair( offset, size );
    00143     fclose( headerFile );
    00144   }
    00145
    00146   FILE* seqNumsFile;
    00147   seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
    00148   if ( seqNumsFile )
    00149   {
    00150     int sender, target;
    00151     if ( FILE_FSCANF( seqNumsFile, "%d : %d", &sender, &target ) == 2 )
    00152     {
    00153       m_cache.setNextSenderMsgSeqNum( sender );
    00154       m_cache.setNextTargetMsgSeqNum( target );
    00155     }
    00156     fclose( seqNumsFile );
    00157   }
    00158
    00159   FILE* sessionFile;
    00160   sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
    00161   if ( sessionFile )
    00162   {
    00163     char time[ 22 ];
    00164 #ifdef HAVE_FSCANF_S
    00165     int result = FILE_FSCANF( sessionFile, "%s", time, 22 );
    00166 #else
    00167     int result = FILE_FSCANF( sessionFile, "%s", time );
    00168 #endif
    00169     if( result == 1 )
    00170     {
    00171       m_cache.setCreationTime( UtcTimeStampConvertor::convert( time, true ) );
    00172     }
    00173     fclose( sessionFile );
    00174   }
    00175
    00176   QF_STACK_POP
    00177 }
    00178
    00179 MessageStore* FileStoreFactory::create( const SessionID& s )
    00180 { QF_STACK_PUSH(FileStoreFactory::create)
    00181
    00182   if ( m_path.size() ) return new FileStore( m_path, s );
    00183
    00184   std::string path;
    00185   Dictionary settings = m_settings.get( s );
    00186   path = settings.getString( FILE_STORE_PATH );
    00187   return new FileStore( path, s );
    00188
    00189   QF_STACK_POP
    00190 }
    00191
    00192 void FileStoreFactory::destroy( MessageStore* pStore )
    00193 { QF_STACK_PUSH(FileStoreFactory::destroy)
    00194   delete pStore;
    00195   QF_STACK_POP
    00196 }
    00197
    00198 bool FileStore::set( int msgSeqNum, const std::string& msg )
    00199 throw ( IOException )
    00200 { QF_STACK_PUSH(FileStore::set)
    00201
    00202   if ( fseek( m_msgFile, 0, SEEK_END ) )
    00203     throw IOException( "Cannot seek to end of " + m_msgFileName );
    00204   if ( fseek( m_headerFile, 0, SEEK_END ) )
    00205     throw IOException( "Cannot seek to end of " + m_headerFileName );
    00206
    00207   int offset = ftell( m_msgFile );
    00208   if ( offset < 0 )
    00209     throw IOException( "Unable to get file pointer position from " + m_msgFileName );
    00210   int size = msg.size();
    00211
    00212   if ( fprintf( m_headerFile, "%d,%d,%d ", msgSeqNum, offset, size ) < 0 )
    00213     throw IOException( "Unable to write to file " + m_headerFileName );
    00214   m_offsets[ msgSeqNum ] = std::make_pair( offset, size );
    00215   fwrite( msg.c_str(), sizeof( char ), msg.size(), m_msgFile );
    00216   if ( ferror( m_msgFile ) )
    00217     throw IOException( "Unable to write to file " + m_msgFileName );
    00218   if ( fflush( m_msgFile ) == EOF )
    00219     throw IOException( "Unable to flush file " + m_msgFileName );
    00220   if ( fflush( m_headerFile ) == EOF )
    00221     throw IOException( "Unable to flush file " + m_headerFileName );
    00222   return true;
    00223
    00224   QF_STACK_POP
    00225 }
    00226
    00227 void FileStore::get( int begin, int end,
    00228                      std::vector < std::string > & result ) const
    00229 throw ( IOException )
    00230 { QF_STACK_PUSH(FileStore::get)
    00231
    00232   result.clear();
    00233   std::string msg;
    00234   for ( int i = begin; i <= end; ++i )
    00235   {
    00236     if ( get( i, msg ) )
    00237       result.push_back( msg );
    00238   }
    00239
    00240   QF_STACK_POP
    00241 }
    00242
    00243 int FileStore::getNextSenderMsgSeqNum() const throw ( IOException )
    00244 { QF_STACK_PUSH(FileStore::getNextSenderMsgSeqNum)
    00245   return m_cache.getNextSenderMsgSeqNum();
    00246   QF_STACK_POP
    00247 }
    00248
    00249 int FileStore::getNextTargetMsgSeqNum() const throw ( IOException )
    00250 { QF_STACK_PUSH(FileStore::getNextTargetMsgSeqNum)
    00251   return m_cache.getNextTargetMsgSeqNum();
    00252   QF_STACK_POP
    00253 }
    00254
    00255 void FileStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
    00256 { QF_STACK_PUSH(FileStore::setNextSenderMsgSeqNum)
    00257   m_cache.setNextSenderMsgSeqNum( value );
    00258   setSeqNum();
    00259   QF_STACK_POP
    00260 }
    00261
    00262 void FileStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
    00263 { QF_STACK_PUSH(FileStore::setNextTargetMsgSeqNum)
    00264   m_cache.setNextTargetMsgSeqNum( value );
    00265   setSeqNum();
    00266   QF_STACK_POP
    00267 }
    00268
    00269 void FileStore::incrNextSenderMsgSeqNum() throw ( IOException )
    00270 { QF_STACK_PUSH(FileStore::incrNextSenderMsgSeqNum)
    00271   m_cache.incrNextSenderMsgSeqNum();
    00272   setSeqNum();
    00273   QF_STACK_POP
    00274 }
    00275
    00276 void FileStore::incrNextTargetMsgSeqNum() throw ( IOException )
    00277 { QF_STACK_PUSH(FileStore::incrNextTargetMsgSeqNum)
    00278   m_cache.incrNextTargetMsgSeqNum();
    00279   setSeqNum();
    00280   QF_STACK_POP
    00281 }
    00282
    00283 UtcTimeStamp FileStore::getCreationTime() const throw ( IOException )
    00284 { QF_STACK_PUSH(FileStore::getCreationTime)
    00285   return m_cache.getCreationTime();
    00286   QF_STACK_POP
    00287 }
    00288
    00289 void FileStore::reset() throw ( IOException )
    00290 { QF_STACK_PUSH(FileStore::reset)
    00291
    00292   m_cache.reset();
    00293   open( true );
    00294   setSession();
    00295
    00296   QF_STACK_POP
    00297 }
    00298
    00299 void FileStore::refresh() throw ( IOException )
    00300 { QF_STACK_PUSH(FileStore::refresh)
    00301
    00302   m_cache.reset();
    00303   open( false );
    00304
    00305   QF_STACK_POP
    00306 }
    00307
    00308 void FileStore::setSeqNum()
    00309 { QF_STACK_PUSH(FileStore::setSeqNum)
    00310
    00311   rewind( m_seqNumsFile );
    00312   fprintf( m_seqNumsFile, "%10.10d : %10.10d",
    00313            getNextSenderMsgSeqNum(), getNextTargetMsgSeqNum() );
    00314   if ( ferror( m_seqNumsFile ) )
    00315     throw IOException( "Unable to write to file " + m_seqNumsFileName );
    00316   if ( fflush( m_seqNumsFile ) )
    00317     throw IOException( "Unable to flush file " + m_seqNumsFileName );
    00318
    00319   QF_STACK_POP
    00320 }
    00321
    00322 void FileStore::setSession()
    00323 { QF_STACK_PUSH(FileStore::setSession)
    00324
    00325   rewind( m_sessionFile );
    00326   fprintf( m_sessionFile, "%s",
    00327            UtcTimeStampConvertor::convert( m_cache.getCreationTime() ).c_str() );
    00328   if ( ferror( m_sessionFile ) )
    00329     throw IOException( "Unable to write to file " + m_sessionFileName );
    00330   if ( fflush( m_sessionFile ) )
    00331     throw IOException( "Unable to flush file " + m_sessionFileName );
    00332
    00333   QF_STACK_POP
    00334 }
    00335
    00336 bool FileStore::get( int msgSeqNum, std::string& msg ) const
    00337 throw ( IOException )
    00338 { QF_STACK_PUSH(FileStore::get)
    00339
    00340   NumToOffset::const_iterator find = m_offsets.find( msgSeqNum );
    00341   if ( find == m_offsets.end() ) return false;
    00342   const OffsetSize& offset = find->second;
    00343   if ( fseek( m_msgFile, offset.first, SEEK_SET ) )
    00344     throw IOException( "Unable to seek in file " + m_msgFileName );
    00345   char* buffer = new char[ offset.second + 1 ];
    00346   fread( buffer, sizeof( char ), offset.second, m_msgFile );
    00347   if ( ferror( m_msgFile ) )
    00348     throw IOException( "Unable to read from file " + m_msgFileName );
    00349   buffer[ offset.second ] = 0;
    00350   msg = buffer;
    00351   delete [] buffer;
    00352   return true;
    00353
    00354   QF_STACK_POP
    00355 }
    00356
    00357 } //namespace FIX