FileStore.cpp
Go to the documentation of this file.
1/****************************************************************************
2** Copyright (c) 2001-2014
3**
4** This file is part of the QuickFIX FIX Engine
5**
6** This file may be distributed under the terms of the quickfixengine.org
7** license as defined by quickfixengine.org and appearing in the file
8** LICENSE included in the packaging of this file.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12**
13** See http://www.quickfixengine.org/LICENSE for licensing information.
14**
15** Contact ask@quickfixengine.org if any conditions of this licensing are
16** not clear to you.
17**
18****************************************************************************/
19
20#ifdef _MSC_VER
21#include "stdafx.h"
22#else
23#include "config.h"
24#endif
25
26#include "FileStore.h"
27#include "SessionID.h"
28#include "Parser.h"
29#include "Utility.h"
30#include <fstream>
31
32namespace FIX
33{
34FileStore::FileStore( std::string path, const SessionID& s )
36{
37 file_mkdir( path.c_str() );
38
39 if ( path.empty() ) path = ".";
40 const std::string& begin =
41 s.getBeginString().getString();
42 const std::string& sender =
43 s.getSenderCompID().getString();
44 const std::string& target =
45 s.getTargetCompID().getString();
46 const std::string& qualifier =
48
49 std::string sessionid = begin + "-" + sender + "-" + target;
50 if( qualifier.size() )
51 sessionid += "-" + qualifier;
52
53 std::string prefix
54 = file_appendpath(path, sessionid + ".");
55
56 m_msgFileName = prefix + "body";
57 m_headerFileName = prefix + "header";
58 m_seqNumsFileName = prefix + "seqnums";
59 m_sessionFileName = prefix + "session";
60
61 try
62 {
63 open( false );
64 }
65 catch ( IOException & e )
66 {
67 throw ConfigError( e.what() );
68 }
69}
70
72{
73 if( m_msgFile ) fclose( m_msgFile );
74 if( m_headerFile ) fclose( m_headerFile );
75 if( m_seqNumsFile ) fclose( m_seqNumsFile );
76 if( m_sessionFile ) fclose( m_sessionFile );
77}
78
79void FileStore::open( bool deleteFile )
80{
81 if ( m_msgFile ) fclose( m_msgFile );
82 if ( m_headerFile ) fclose( m_headerFile );
83 if ( m_seqNumsFile ) fclose( m_seqNumsFile );
84 if ( m_sessionFile ) fclose( m_sessionFile );
85
86 m_msgFile = 0;
87 m_headerFile = 0;
88 m_seqNumsFile = 0;
89 m_sessionFile = 0;
90
91 if ( deleteFile )
92 {
93 file_unlink( m_msgFileName.c_str() );
97 }
98
100 m_msgFile = file_fopen( m_msgFileName.c_str(), "r+" );
101 if ( !m_msgFile ) m_msgFile = file_fopen( m_msgFileName.c_str(), "w+" );
102 if ( !m_msgFile ) throw ConfigError( "Could not open body file: " + m_msgFileName );
103
104 m_headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
105 if ( !m_headerFile ) m_headerFile = file_fopen( m_headerFileName.c_str(), "w+" );
106 if ( !m_headerFile ) throw ConfigError( "Could not open header file: " + m_headerFileName );
107
108 m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
109 if ( !m_seqNumsFile ) m_seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "w+" );
110 if ( !m_seqNumsFile ) throw ConfigError( "Could not open seqnums file: " + m_seqNumsFileName );
111
112 bool setCreationTime = false;
114 if ( !m_sessionFile ) setCreationTime = true;
115 else fclose( m_sessionFile );
116
117 m_sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
118 if ( !m_sessionFile ) m_sessionFile = file_fopen( m_sessionFileName.c_str(), "w+" );
119 if ( !m_sessionFile ) throw ConfigError( "Could not open session file" );
120 if ( setCreationTime ) setSession();
121
124}
125
127{
128 FILE* headerFile = file_fopen( m_headerFileName.c_str(), "r+" );
129 if ( headerFile )
130 {
131 int num;
132 long offset;
133 std::size_t size;
134
135 while (FILE_FSCANF(headerFile, "%d,%ld,%lu ", &num, &offset, &size) == 3)
136 {
137 std::pair<NumToOffset::iterator, bool> it =
138 m_offsets.insert(NumToOffset::value_type(num, std::make_pair(offset, size)));
139 //std::cout << it.first->second.first << " --- " << it.first->second.second << '\n';
140 if (it.second == false)
141 {
142 it.first->second = std::make_pair(offset, size);
143 }
144 }
145 fclose( headerFile );
146 }
147
148 FILE* seqNumsFile = file_fopen( m_seqNumsFileName.c_str(), "r+" );
149 if ( seqNumsFile )
150 {
151 int sender, target;
152 if ( FILE_FSCANF( seqNumsFile, "%d : %d", &sender, &target ) == 2 )
153 {
154 m_cache.setNextSenderMsgSeqNum( sender );
155 m_cache.setNextTargetMsgSeqNum( target );
156 }
157 fclose( seqNumsFile );
158 }
159
160 FILE* sessionFile = file_fopen( m_sessionFileName.c_str(), "r+" );
161 if ( sessionFile )
162 {
163 char time[ 22 ];
164#ifdef HAVE_FSCANF_S
165 int result = FILE_FSCANF( sessionFile, "%s", time, 22 );
166#else
167 int result = FILE_FSCANF( sessionFile, "%s", time );
168#endif
169 if( result == 1 )
170 {
171 m_cache.setCreationTime( UtcTimeStampConvertor::convert( time ) );
172 }
173 fclose( sessionFile );
174 }
175}
176
178{
179 if ( m_path.size() ) return new FileStore( m_path, s );
180
181 std::string path;
182 Dictionary settings = m_settings.get( s );
183 path = settings.getString( FILE_STORE_PATH );
184 return new FileStore( path, s );
185}
186
188{
189 delete pStore;
190}
191
192bool FileStore::set( int msgSeqNum, const std::string& msg )
193throw ( IOException )
194{
195 if ( fseek( m_msgFile, 0, SEEK_END ) )
196 throw IOException( "Cannot seek to end of " + m_msgFileName );
197 if ( fseek( m_headerFile, 0, SEEK_END ) )
198 throw IOException( "Cannot seek to end of " + m_headerFileName );
199
200 long offset = ftell( m_msgFile );
201 if ( offset < 0 )
202 throw IOException( "Unable to get file pointer position from " + m_msgFileName );
203 std::size_t size = msg.size();
204
205 if ( fprintf( m_headerFile, "%d,%ld,%lu ", msgSeqNum, offset, size ) < 0 )
206 throw IOException( "Unable to write to file " + m_headerFileName );
207 std::pair<NumToOffset::iterator, bool> it =
208 m_offsets.insert(NumToOffset::value_type(msgSeqNum, std::make_pair(offset, size)));
209 if (it.second == false)
210 {
211 it.first->second = std::make_pair(offset, size);
212 }
213 fwrite( msg.c_str(), sizeof( char ), msg.size(), m_msgFile );
214 if ( ferror( m_msgFile ) )
215 throw IOException( "Unable to write to file " + m_msgFileName );
216 if ( fflush( m_msgFile ) == EOF )
217 throw IOException( "Unable to flush file " + m_msgFileName );
218 if ( fflush( m_headerFile ) == EOF )
219 throw IOException( "Unable to flush file " + m_headerFileName );
220 return true;
221}
222
223void FileStore::get( int begin, int end,
224 std::vector < std::string > & result ) const
225throw ( IOException )
226{
227 result.clear();
228 std::string msg;
229 for ( int i = begin; i <= end; ++i )
230 {
231 if ( get( i, msg ) )
232 result.push_back( msg );
233 }
234}
235
237{
238 return m_cache.getNextSenderMsgSeqNum();
239}
240
242{
243 return m_cache.getNextTargetMsgSeqNum();
244}
245
247{
248 m_cache.setNextSenderMsgSeqNum( value );
249 setSeqNum();
250}
251
253{
254 m_cache.setNextTargetMsgSeqNum( value );
255 setSeqNum();
256}
257
259{
260 m_cache.incrNextSenderMsgSeqNum();
261 setSeqNum();
262}
263
265{
266 m_cache.incrNextTargetMsgSeqNum();
267 setSeqNum();
268}
269
271{
272 return m_cache.getCreationTime();
273}
274
276{
277 try
278 {
279 m_cache.reset();
280 open( true );
281 setSession();
282 }
283 catch( std::exception& e )
284 {
285 throw IOException( e.what() );
286 }
287}
288
290{
291 try
292 {
293 m_cache.reset();
294 open( false );
295 }
296 catch( std::exception& e )
297 {
298 throw IOException( e.what() );
299 }
300}
301
303{
304 rewind( m_seqNumsFile );
305 fprintf( m_seqNumsFile, "%10.10d : %10.10d",
307 if ( ferror( m_seqNumsFile ) )
308 throw IOException( "Unable to write to file " + m_seqNumsFileName );
309 if ( fflush( m_seqNumsFile ) )
310 throw IOException( "Unable to flush file " + m_seqNumsFileName );
311}
312
314{
315 rewind( m_sessionFile );
316 fprintf( m_sessionFile, "%s",
317 UtcTimeStampConvertor::convert( m_cache.getCreationTime() ).c_str() );
318 if ( ferror( m_sessionFile ) )
319 throw IOException( "Unable to write to file " + m_sessionFileName );
320 if ( fflush( m_sessionFile ) )
321 throw IOException( "Unable to flush file " + m_sessionFileName );
322}
323
324bool FileStore::get( int msgSeqNum, std::string& msg ) const
325throw ( IOException )
326{
327 NumToOffset::const_iterator find = m_offsets.find( msgSeqNum );
328 if ( find == m_offsets.end() ) return false;
329 const OffsetSize& offset = find->second;
330 if ( fseek( m_msgFile, offset.first, SEEK_SET ) )
331 throw IOException( "Unable to seek in file " + m_msgFileName );
332 char* buffer = new char[ offset.second + 1 ];
333 size_t result = fread( buffer, sizeof( char ), offset.second, m_msgFile );
334 if ( ferror( m_msgFile ) || result != (size_t)offset.second )
335 {
336 delete [] buffer;
337 throw IOException( "Unable to read from file " + m_msgFileName );
338 }
339 buffer[ offset.second ] = 0;
340 msg = buffer;
341 delete [] buffer;
342 return true;
343}
344
345} //namespace FIX
#define FILE_FSCANF
For storage and retrieval of key/value pairs.
Definition Dictionary.h:37
std::string getString(const std::string &, bool capitalize=false) const
Get a value as a string.
MessageStore * create(const SessionID &)
SessionSettings m_settings
Definition FileStore.h:51
std::string m_path
Definition FileStore.h:50
void destroy(MessageStore *)
File based implementation of MessageStore.
Definition FileStore.h:82
FILE * m_headerFile
Definition FileStore.h:127
std::string m_seqNumsFileName
Definition FileStore.h:123
void setNextSenderMsgSeqNum(int value)
UtcTimeStamp getCreationTime() const
int getNextSenderMsgSeqNum() const
std::pair< long, std::size_t > OffsetSize
Definition FileStore.h:106
FILE * m_sessionFile
Definition FileStore.h:129
FILE * m_seqNumsFile
Definition FileStore.h:128
void incrNextSenderMsgSeqNum()
void incrNextTargetMsgSeqNum()
std::string m_sessionFileName
Definition FileStore.h:124
void open(bool deleteFile)
Definition FileStore.cpp:79
void populateCache()
std::string m_headerFileName
Definition FileStore.h:122
void get(int, int, std::vector< std::string > &) const
virtual ~FileStore()
Definition FileStore.cpp:71
MemoryStore m_cache
Definition FileStore.h:118
void setNextTargetMsgSeqNum(int value)
std::string m_msgFileName
Definition FileStore.h:121
FileStore(std::string, const SessionID &s)
Definition FileStore.cpp:34
FILE * m_msgFile
Definition FileStore.h:126
NumToOffset m_offsets
Definition FileStore.h:119
bool set(int, const std::string &)
int getNextTargetMsgSeqNum() const
This interface must be implemented to store and retrieve messages and sequence numbers.
Unique session id consists of BeginString, SenderCompID and TargetCompID.
Definition SessionID.h:31
const SenderCompID & getSenderCompID() const
Definition SessionID.h:55
const std::string & getSessionQualifier() const
Definition SessionID.h:59
const BeginString & getBeginString() const
Definition SessionID.h:53
const TargetCompID & getTargetCompID() const
Definition SessionID.h:57
Date and Time represented in UTC.
Definition FieldTypes.h:583
void file_unlink(const char *path)
Definition Utility.cpp:537
void file_mkdir(const char *path)
Definition Utility.cpp:489
const char FILE_STORE_PATH[]
FILE * file_fopen(const char *path, const char *mode)
Definition Utility.cpp:509
std::string file_appendpath(const std::string &path, const std::string &file)
Definition Utility.cpp:551
Application is not configured correctly
Definition Exceptions.h:88
static std::string convert(const UtcTimeStamp &value, int precision=0)

Generated on for QuickFIX by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2001