FileStore.cpp
Go to the documentation of this file.
/****************************************************************************
** Copyright (c) 2001-2014
**
** This file is part of the QuickFIX FIX Engine
**
** This file may be distributed under the terms of the quickfixengine.org
** license as defined by quickfixengine.org and appearing in the file
** LICENSE included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.quickfixengine.org/LICENSE for licensing information.
**
** Contact ask@quickfixengine.org if any conditions of this licensing are
** not clear to you.
**
****************************************************************************/
#ifdef _MSC_VER
#include "stdafx.h"
#else
#include "config.h"
#endif
#include "FileStore.h"
#include "SessionID.h"
#include "Parser.h"
#include "Utility.h"
#include <fstream>
namespace FIX
{
FileStore::FileStore( std::string path, const SessionID& s )
: m_msgFile( 0 ), m_headerFile( 0 ), m_seqNumsFile( 0 ), m_sessionFile( 0 )
{
file_mkdir( path.c_str() );
if ( path.empty() ) path = ".";
const std::string& begin =
s.getBeginString().getString();
const std::string& sender =
s.getSenderCompID().getString();
const std::string& target =
s.getTargetCompID().getString();
const std::string& qualifier =
s.getSessionQualifier();
std::string sessionid = begin + "-" + sender + "-" + target;
if( qualifier.size() )
sessionid += "-" + qualifier;
std::string prefix
= file_appendpath(path, sessionid + ".");
m_msgFileName = prefix + "body";
m_headerFileName = prefix + "header";
m_seqNumsFileName = prefix + "seqnums";
m_sessionFileName = prefix + "session";
try
{
open( false );
}
catch ( IOException & e )
{
throw ConfigError( e.what() );
}
}
FileStore::~FileStore()
{
if( m_msgFile ) fclose( m_msgFile );
if( m_headerFile ) fclose( m_headerFile );
if( m_seqNumsFile ) fclose( m_seqNumsFile );
if( m_sessionFile ) fclose( m_sessionFile );
}
void FileStore::open( bool deleteFile )
{
if ( m_msgFile ) fclose( m_msgFile );
if ( m_headerFile ) fclose( m_headerFile );
if ( m_seqNumsFile ) fclose( m_seqNumsFile );
if ( m_sessionFile ) fclose( m_sessionFile );
m_msgFile = 0;
m_headerFile = 0;
m_seqNumsFile = 0;
m_sessionFile = 0;
if ( deleteFile )
{
file_unlink( m_msgFileName.c_str() );
file_unlink( m_headerFileName.c_str() );
file_unlink( m_seqNumsFileName.c_str() );
file_unlink( m_sessionFileName.c_str() );
}
populateCache();
m_msgFile = file_fopen( m_msgFileName.c_str(), "r+" );
if ( !m_msgFile ) m_msgFile = file_fopen( m_msgFileName.c_str(), "w+" );
if ( !m_msgFile ) throw ConfigError( "Could not open body file: " + m_msgFileName );
m_headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
if ( !m_headerFile ) m_headerFile = file_fopen( m_headerFileName.c_str(), "w+" );
if ( !m_headerFile ) throw ConfigError( "Could not open header file: " + m_headerFileName );
m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
if ( !m_seqNumsFile ) m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "w+" );
if ( !m_seqNumsFile ) throw ConfigError( "Could not open seqnums file: " + m_seqNumsFileName );
bool setCreationTime = false;
m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r" );
if ( !m_sessionFile ) setCreationTime = true;
else fclose( m_sessionFile );
m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
if ( !m_sessionFile ) m_sessionFile = file_fopen( m_sessionFileName.c_str(), "w+" );
if ( !m_sessionFile ) throw ConfigError( "Could not open session file" );
if ( setCreationTime ) setSession();
setNextSenderMsgSeqNum( getNextSenderMsgSeqNum() );
setNextTargetMsgSeqNum( getNextTargetMsgSeqNum() );
}
void FileStore::populateCache()
{
FILE* headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
if ( headerFile )
{
int num;
long offset;
std::size_t size;
while (FILE_FSCANF(headerFile, "%d,%ld,%lu ", &num, &offset, &size) == 3)
{
std::pair<NumToOffset::iterator, bool> it =
m_offsets.insert(NumToOffset::value_type(num, std::make_pair(offset, size)));
//std::cout << it.first->second.first << " --- " << it.first->second.second << '\n';
if (it.second == false)
{
it.first->second = std::make_pair(offset, size);
}
}
fclose( headerFile );
}
FILE* seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
if ( seqNumsFile )
{
int sender, target;
if ( FILE_FSCANF( seqNumsFile, "%d : %d", &sender, &target ) == 2 )
{
m_cache.setNextSenderMsgSeqNum( sender );
m_cache.setNextTargetMsgSeqNum( target );
}
fclose( seqNumsFile );
}
FILE* sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
if ( sessionFile )
{
char time[ 22 ];
#ifdef HAVE_FSCANF_S
int result = FILE_FSCANF( sessionFile, "%s", time, 22 );
#else
int result = FILE_FSCANF( sessionFile, "%s", time );
#endif
if( result == 1 )
{
m_cache.setCreationTime( UtcTimeStampConvertor::convert( time ) );
}
fclose( sessionFile );
}
}
MessageStore* FileStoreFactory::create( const SessionID& s )
{
if ( m_path.size() ) return new FileStore( m_path, s );
std::string path;
Dictionary settings = m_settings.get( s );
path = settings.getString( FILE_STORE_PATH );
return new FileStore( path, s );
}
void FileStoreFactory::destroy( MessageStore* pStore )
{
delete pStore;
}
bool FileStore::set( int msgSeqNum, const std::string& msg )
throw ( IOException )
{
if ( fseek( m_msgFile, 0, SEEK_END ) )
throw IOException( "Cannot seek to end of " + m_msgFileName );
if ( fseek( m_headerFile, 0, SEEK_END ) )
throw IOException( "Cannot seek to end of " + m_headerFileName );
long offset = ftell( m_msgFile );
if ( offset < 0 )
throw IOException( "Unable to get file pointer position from " + m_msgFileName );
std::size_t size = msg.size();
if ( fprintf( m_headerFile, "%d,%ld,%lu ", msgSeqNum, offset, size ) < 0 )
throw IOException( "Unable to write to file " + m_headerFileName );
std::pair<NumToOffset::iterator, bool> it =
m_offsets.insert(NumToOffset::value_type(msgSeqNum, std::make_pair(offset, size)));
if (it.second == false)
{
it.first->second = std::make_pair(offset, size);
}
fwrite( msg.c_str(), sizeof( char ), msg.size(), m_msgFile );
if ( ferror( m_msgFile ) )
throw IOException( "Unable to write to file " + m_msgFileName );
if ( fflush( m_msgFile ) == EOF )
throw IOException( "Unable to flush file " + m_msgFileName );
if ( fflush( m_headerFile ) == EOF )
throw IOException( "Unable to flush file " + m_headerFileName );
return true;
}
void FileStore::get( int begin, int end,
std::vector < std::string > & result ) const
throw ( IOException )
{
result.clear();
std::string msg;
for ( int i = begin; i <= end; ++i )
{
if ( get( i, msg ) )
result.push_back( msg );
}
}
int FileStore::getNextSenderMsgSeqNum() const throw ( IOException )
{
return m_cache.getNextSenderMsgSeqNum();
}
int FileStore::getNextTargetMsgSeqNum() const throw ( IOException )
{
return m_cache.getNextTargetMsgSeqNum();
}
void FileStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
{
m_cache.setNextSenderMsgSeqNum( value );
setSeqNum();
}
void FileStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
{
m_cache.setNextTargetMsgSeqNum( value );
setSeqNum();
}
void FileStore::incrNextSenderMsgSeqNum() throw ( IOException )
{
m_cache.incrNextSenderMsgSeqNum();
setSeqNum();
}
void FileStore::incrNextTargetMsgSeqNum() throw ( IOException )
{
m_cache.incrNextTargetMsgSeqNum();
setSeqNum();
}
UtcTimeStamp FileStore::getCreationTime() const throw ( IOException )
{
return m_cache.getCreationTime();
}
void FileStore::reset() throw ( IOException )
{
try
{
m_cache.reset();
open( true );
setSession();
}
catch( std::exception& e )
{
throw IOException( e.what() );
}
}
void FileStore::refresh() throw ( IOException )
{
try
{
m_cache.reset();
open( false );
}
catch( std::exception& e )
{
throw IOException( e.what() );
}
}
void FileStore::setSeqNum()
{
rewind( m_seqNumsFile );
fprintf( m_seqNumsFile, "%10.10d : %10.10d",
getNextSenderMsgSeqNum(), getNextTargetMsgSeqNum() );
if ( ferror( m_seqNumsFile ) )
throw IOException( "Unable to write to file " + m_seqNumsFileName );
if ( fflush( m_seqNumsFile ) )
throw IOException( "Unable to flush file " + m_seqNumsFileName );
}
void FileStore::setSession()
{
rewind( m_sessionFile );
fprintf( m_sessionFile, "%s",
UtcTimeStampConvertor::convert( m_cache.getCreationTime() ).c_str() );
if ( ferror( m_sessionFile ) )
throw IOException( "Unable to write to file " + m_sessionFileName );
if ( fflush( m_sessionFile ) )
throw IOException( "Unable to flush file " + m_sessionFileName );
}
bool FileStore::get( int msgSeqNum, std::string& msg ) const
throw ( IOException )
{
NumToOffset::const_iterator find = m_offsets.find( msgSeqNum );
if ( find == m_offsets.end() ) return false;
const OffsetSize& offset = find->second;
if ( fseek( m_msgFile, offset.first, SEEK_SET ) )
throw IOException( "Unable to seek in file " + m_msgFileName );
char* buffer = new char[ offset.second + 1 ];
size_t result = fread( buffer, sizeof( char ), offset.second, m_msgFile );
if ( ferror( m_msgFile ) || result != (size_t)offset.second )
{
delete [] buffer;
throw IOException( "Unable to read from file " + m_msgFileName );
}
buffer[ offset.second ] = 0;
msg = buffer;
delete [] buffer;
return true;
}
} //namespace FIX
FileStore.h
Parser.h
SessionID.h
Utility.h
FILE_FSCANF
#define FILE_FSCANF
Definition: Utility.h:215
FIX::Dictionary
For storage and retrieval of key/value pairs.
Definition: Dictionary.h:37
FIX::Dictionary::getString
std::string getString(const std::string &, bool capitalize=false) const
Get a value as a string.
Definition: Dictionary.cpp:32
FIX::FileStoreFactory::create
MessageStore * create(const SessionID &)
Definition: FileStore.cpp:177
FIX::FileStoreFactory::m_settings
SessionSettings m_settings
Definition: FileStore.h:51
FIX::FileStoreFactory::m_path
std::string m_path
Definition: FileStore.h:50
FIX::FileStoreFactory::destroy
void destroy(MessageStore *)
Definition: FileStore.cpp:187
FIX::FileStore
File based implementation of MessageStore.
Definition: FileStore.h:82
FIX::FileStore::refresh
void refresh()
Definition: FileStore.cpp:289
FIX::FileStore::m_headerFile
FILE * m_headerFile
Definition: FileStore.h:127
FIX::FileStore::m_seqNumsFileName
std::string m_seqNumsFileName
Definition: FileStore.h:123
FIX::FileStore::setNextSenderMsgSeqNum
void setNextSenderMsgSeqNum(int value)
Definition: FileStore.cpp:246
FIX::FileStore::getCreationTime
UtcTimeStamp getCreationTime() const
Definition: FileStore.cpp:270
FIX::FileStore::getNextSenderMsgSeqNum
int getNextSenderMsgSeqNum() const
Definition: FileStore.cpp:236
FIX::FileStore::OffsetSize
std::pair< long, std::size_t > OffsetSize
Definition: FileStore.h:106
FIX::FileStore::m_sessionFile
FILE * m_sessionFile
Definition: FileStore.h:129
FIX::FileStore::m_seqNumsFile
FILE * m_seqNumsFile
Definition: FileStore.h:128
FIX::FileStore::incrNextSenderMsgSeqNum
void incrNextSenderMsgSeqNum()
Definition: FileStore.cpp:258
FIX::FileStore::setSession
void setSession()
Definition: FileStore.cpp:313
FIX::FileStore::incrNextTargetMsgSeqNum
void incrNextTargetMsgSeqNum()
Definition: FileStore.cpp:264
FIX::FileStore::m_sessionFileName
std::string m_sessionFileName
Definition: FileStore.h:124
FIX::FileStore::open
void open(bool deleteFile)
Definition: FileStore.cpp:79
FIX::FileStore::populateCache
void populateCache()
Definition: FileStore.cpp:126
FIX::FileStore::m_headerFileName
std::string m_headerFileName
Definition: FileStore.h:122
FIX::FileStore::get
void get(int, int, std::vector< std::string > &) const
Definition: FileStore.cpp:223
FIX::FileStore::~FileStore
virtual ~FileStore()
Definition: FileStore.cpp:71
FIX::FileStore::reset
void reset()
Definition: FileStore.cpp:275
FIX::FileStore::m_cache
MemoryStore m_cache
Definition: FileStore.h:118
FIX::FileStore::setNextTargetMsgSeqNum
void setNextTargetMsgSeqNum(int value)
Definition: FileStore.cpp:252
FIX::FileStore::m_msgFileName
std::string m_msgFileName
Definition: FileStore.h:121
FIX::FileStore::FileStore
FileStore(std::string, const SessionID &s)
Definition: FileStore.cpp:34
FIX::FileStore::setSeqNum
void setSeqNum()
Definition: FileStore.cpp:302
FIX::FileStore::m_msgFile
FILE * m_msgFile
Definition: FileStore.h:126
FIX::FileStore::m_offsets
NumToOffset m_offsets
Definition: FileStore.h:119
FIX::FileStore::set
bool set(int, const std::string &)
Definition: FileStore.cpp:192
FIX::FileStore::getNextTargetMsgSeqNum
int getNextTargetMsgSeqNum() const
Definition: FileStore.cpp:241
FIX::MemoryStore::setCreationTime
void setCreationTime(const UtcTimeStamp &creationTime)
Definition: MessageStore.h:117
FIX::MemoryStore::getNextTargetMsgSeqNum
int getNextTargetMsgSeqNum() const
Definition: MessageStore.h:106
FIX::MemoryStore::incrNextTargetMsgSeqNum
void incrNextTargetMsgSeqNum()
Definition: MessageStore.h:114
FIX::MemoryStore::incrNextSenderMsgSeqNum
void incrNextSenderMsgSeqNum()
Definition: MessageStore.h:112
FIX::MemoryStore::setNextTargetMsgSeqNum
void setNextTargetMsgSeqNum(int value)
Definition: MessageStore.h:110
FIX::MemoryStore::reset
void reset()
Definition: MessageStore.h:122
FIX::MemoryStore::getCreationTime
UtcTimeStamp getCreationTime() const
Definition: MessageStore.h:119
FIX::MemoryStore::setNextSenderMsgSeqNum
void setNextSenderMsgSeqNum(int value)
Definition: MessageStore.h:108
FIX::MemoryStore::getNextSenderMsgSeqNum
int getNextSenderMsgSeqNum() const
Definition: MessageStore.h:104
FIX::MessageStore
This interface must be implemented to store and retrieve messages and sequence numbers.
Definition: MessageStore.h:67
FIX::SessionID
Unique session id consists of BeginString, SenderCompID and TargetCompID.
Definition: SessionID.h:31
FIX::SessionID::getTargetCompID
const TargetCompID & getTargetCompID() const
Definition: SessionID.h:57
FIX::SessionID::getSessionQualifier
const std::string & getSessionQualifier() const
Definition: SessionID.h:59
FIX::SessionID::getBeginString
const BeginString & getBeginString() const
Definition: SessionID.h:53
FIX::SessionID::getSenderCompID
const SenderCompID & getSenderCompID() const
Definition: SessionID.h:55
FIX::SessionSettings::get
const Dictionary & get(const SessionID &) const
Get a dictionary for a session.
Definition: SessionSettings.cpp:127
FIX::UtcTimeStamp
Date and Time represented in UTC.
Definition: FieldTypes.h:583
FIX
Definition: Acceptor.cpp:35
FIX::file_unlink
void file_unlink(const char *path)
Definition: Utility.cpp:537
FIX::file_mkdir
void file_mkdir(const char *path)
Definition: Utility.cpp:489
FIX::FILE_STORE_PATH
const char FILE_STORE_PATH[]
Definition: SessionSettings.h:80
FIX::file_fopen
FILE * file_fopen(const char *path, const char *mode)
Definition: Utility.cpp:509
FIX::file_appendpath
std::string file_appendpath(const std::string &path, const std::string &file)
Definition: Utility.cpp:551
FIX::ConfigError
Application is not configured correctly
Definition: Exceptions.h:88
FIX::IOException
IO Error.
Definition: Exceptions.h:239
FIX::UtcTimeStampConvertor::convert
static std::string convert(const UtcTimeStamp &value, int precision=0)
Definition: FieldConvertors.h:434