Skip to content

Commit

Permalink
Merge branch 'master' of github.com:connamara/quickfixn
Browse files Browse the repository at this point in the history
Conflicts:
	NEXT_VERSION.md
  • Loading branch information
gbirchmeier committed Apr 23, 2014
2 parents 4f2c189 + d6c077f commit 4bce90b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 5 deletions.
2 changes: 1 addition & 1 deletion NEXT_VERSION.md
Expand Up @@ -20,5 +20,5 @@ Changes since the last version:

* (minor) #247 - support for CheckLatency/MaxLatency config settings (ruaanviljoen)
* (minor) #256 - bug in 247, defaults override config (akamyshanov)
* (minor) #258 - make SessionState.Store (FileStore) be threadsafe in Get/Set (jacsuper)
* (minor) #258 - threadsafe SessionState.Get/Set to fix garbled message issue (jacsuper)

5 changes: 4 additions & 1 deletion QuickFIXn/SessionState.cs
Expand Up @@ -275,7 +275,10 @@ public ResendRange GetResendRange()

public void Get(int begSeqNo, int endSeqNo, List<string> messages)
{
MessageStore.Get(begSeqNo, endSeqNo, messages);
lock (sync_)
{
MessageStore.Get(begSeqNo, endSeqNo, messages);
}
}

public void SetResendRange(int begin, int end, int chunkEnd=-1)
Expand Down
97 changes: 94 additions & 3 deletions UnitTests/SessionStateTest.cs
@@ -1,5 +1,9 @@
using NUnit.Framework;
using System;
using NUnit.Framework;
using QuickFix;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace UnitTests
{
Expand All @@ -18,8 +22,6 @@ public void TimedOut()
System.DateTime now = System.DateTime.UtcNow;
System.DateTime lastReceivedTime = now;



now = now.AddMilliseconds(heartBtIntMillis);
Assert.False(SessionState.TimedOut(now, heartBtIntMillis, lastReceivedTime));
now = now.AddMilliseconds(heartBtIntMillis);
Expand Down Expand Up @@ -125,5 +127,94 @@ public void WithinHeartbeat()
lastReceivedTime = lastReceivedTime.AddMilliseconds(1);
Assert.True(SessionState.WithinHeartbeat(now, heartBtIntMillis, lastSentTime, lastReceivedTime));
}

[Test]
public void ThreadSafeSetAndGet() {
//Set up store
if (System.IO.Directory.Exists("store")) {
System.IO.Directory.Delete("store", true);
}

SessionID sessionId = new SessionID("FIX.4.2", "SENDERCOMP", "TARGETCOMP");

Dictionary config = new Dictionary();
config.SetString(SessionSettings.CONNECTION_TYPE, "initiator");
config.SetString(SessionSettings.FILE_STORE_PATH, "store");

SessionSettings settings = new SessionSettings();
settings.Set(sessionId, config);
FileStoreFactory factory = new FileStoreFactory(settings);

FileStore store = (FileStore)factory.Create(sessionId);

NullLog log = new NullLog();

//Set up sessionstate
SessionState state = new SessionState(log, 1) {MessageStore = store};

Hashtable errorsTable = Hashtable.Synchronized(new Hashtable());//used in more than 1 thread at a time
Hashtable setTable = new Hashtable(1000);//only used in 1 thread at a time
Hashtable getTable = new Hashtable(1000);//only used in 1 thread at a time

//Synchronously populate 1000 messages
for (int i = 1; i < 1000; i++) {
string msg = "msg" + i;
state.Set(i, msg);
setTable[i] = msg;
}

//Simulate background sending of messages that populate into the store
AutoResetEvent setEvent = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate(object stateObject) {
AutoResetEvent internalSetEvent = (AutoResetEvent)((object[])stateObject)[0];
SessionState internalState = (SessionState)((object[])stateObject)[1];
for (int i = 1001; i < 2000; i++) {
try {
internalState.Set(i, "msg" + i);
}
catch (System.IO.IOException ex) {
errorsTable[ex.Message] = ex;
}
}

internalSetEvent.Set();
}
, new object[] { setEvent, state });

//Simulate background reading of messages from the store - like is done in a resend request answer
AutoResetEvent getEvent = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate(object stateObject){
AutoResetEvent internalGetEvent = (AutoResetEvent)((object[])stateObject)[0];
SessionState internalState = (SessionState)((object[])stateObject)[1];
for (int i = 1; i < 1000; i++) {
try {
List<string> lst = new List<string>(1);
internalState.Get(i, i, lst);
if (lst.Count == 0) {
getTable[i] = "nothing read";
}
else {
getTable[i] = lst[0];
}
}
catch (System.IO.IOException ex) {
errorsTable[ex.Message] = ex;
}
}

internalGetEvent.Set();
}
, new object[]{getEvent, state});

//wait till done and assert results
Assert.True(setEvent.WaitOne(10000), "Get or Set hung/timed out during concurrent usage");
Assert.True(getEvent.WaitOne(10000), "Get or Set hung/timed out during concurrent usage");
Assert.AreEqual(setTable, getTable, "Garbled data read in concurrent set and get (like between resendrequest and send)");
Assert.AreEqual(errorsTable.Count, 0, "IOException occured in concurrent set and get (like between resendrequest and send)");

//Tear down filestore
state.Dispose();
store.Dispose();
}
}
}
1 change: 1 addition & 0 deletions web/views/about/credits.md
Expand Up @@ -42,5 +42,6 @@ Contributors
- Daniel Svensson
- Ruann Viljoen
- Andrey Kamyshanov
- Jac Steyn


0 comments on commit 4bce90b

Please sign in to comment.