/// <summary>
/// Creates sessions concurrently and stores a random binary blob in each session. This
/// method then waits for all the sessions to expire and verifies that each session has in
/// fact been removed from the provider and the provider's memory cache. It also takes a
/// snapshot of the memory usage pre session creation, post session creation and post
/// session expiration. This method will fail is any session still exists in the provider
/// or there was excessive memory usage.
/// </summary>
/// <param name="provider">The MongoDB provider to use for the test.</param>
/// <param name="numberOfSessions">The number of sessions to create concurrently.</param>
/// <param name="sessionSizeInMegabytes">The number of MB of buffer to create and store in each session.</param>
private void CreateConcurrentSessionObjects(MongoDBSessionStateProvider provider, int numberOfSessions, byte sessionSizeInMegabytes)
{
var sessions = new System.Collections.Generic.SynchronizedCollection<string>();
double initialWorkingSet, postSessionCreationWorkingSet, postSessionExpirationWorkingSet;
var currentProcess = System.Diagnostics.Process.GetCurrentProcess();
initialWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);
int sessionSize = (sessionSizeInMegabytes * 1024 * 1024);
var result = Parallel.For(0, numberOfSessions, idx =>
{
System.Threading.Thread.Sleep(50); // Give a little wiggle room
HttpRequest request = null;
HttpResponse response = null;
HttpContext context = GetContext(out request, out response);
string sessionId = _SessionIdManager.CreateSessionID(context);
sessions.Add(sessionId);
byte[] dummyData = new byte[sessionSize];
(new Random()).NextBytes(dummyData);
var dataStore = provider.CreateNewStoreData(context, (_TimeoutInSeconds / 60));
dataStore.Items["Data"] = dummyData;
provider.SetAndReleaseItemExclusive(context, sessionId, dataStore, null, true);
TestContext.WriteLine("Created session {0} with dummy data", sessionId);
});
while (!result.IsCompleted)
{
System.Threading.Thread.Sleep(1000);
}
GC.Collect();
currentProcess.Refresh();
postSessionCreationWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);
var counter = _TimeoutInSeconds + 60;
TestContext.WriteLine("Waiting {0} seconds for session expiration...", counter);
while (counter > 0)
{
System.Threading.Thread.Sleep(1000);
counter--;
}
TestContext.WriteLine("Checking Sessions in store and cache...");
var sessionIds = sessions.ToArray();
result = Parallel.ForEach<string>(sessionIds, sessionId =>
{
HttpRequest request = null;
HttpResponse response = null;
HttpContext context = GetContext(out request, out response);
bool locked;
TimeSpan lockAge;
object lockId;
System.Web.SessionState.SessionStateActions actions;
var storeData = provider.GetItem(context, sessionId, out locked, out lockAge, out lockId, out actions);
Assert.IsNull(storeData);
// Now check the cache!
ISessionStateData sessionStateData;
bool existsInCache = CheckSessionExistsInCache(provider, sessionId, out sessionStateData);
if (existsInCache || sessionStateData != null)
{
TestContext.WriteLine("Session {0} still exists in cache!", sessionId);
}
else
{
sessions.Remove(sessionId);
}
});
while (!result.IsCompleted)
{
System.Threading.Thread.Sleep(1000);
}
GC.Collect();
GC.WaitForPendingFinalizers();
currentProcess.Refresh();
postSessionExpirationWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);
TestContext.WriteLine("Memory Usage: Initial = {0}MB, PostSessionCreation = {1}MB, PostSessionExpiration = {2}MB", initialWorkingSet, postSessionCreationWorkingSet, postSessionExpirationWorkingSet);
TestContext.WriteLine("After expiration, session count = {0}", sessions.Count);
currentProcess.Dispose();
double memoryDifference = postSessionExpirationWorkingSet - initialWorkingSet;
TestContext.WriteLine("Memory Difference -> {0}MB", memoryDifference);
bool isMemoryExhausted = (memoryDifference > 20); // This should be based on the buffer size and number of sessions
if (sessions.Count != 0)
{
Assert.Fail("{0} Sessions still exist in memory. The memory has grown from {1}MB to {2}MB", sessions.Count, initialWorkingSet, postSessionExpirationWorkingSet);
}
if (isMemoryExhausted)
{
Assert.Fail("Excessive Memory Consumption. Memory has grown by {0}MB", memoryDifference);
}
}