/// <summary> /// Reads a stored session /// </summary> /// <param name="Key">Session Key</param> /// <param name="Reader">Method to call to complete read</param> /// <param name="StateObject">State object</param> /// <param name="isExporting">Indicates if the session is to be exported</param> /// <returns>Result of read action</returns> private SessionActionResult Read(string Key, SessionReadHandler Reader, object StateObject, bool isExporting) { if (Key == null) { throw new ArgumentNullException("Key"); } bool tryAgain; bool sessionIslocked = false; Diags.ResetDeadLockCounter(); //Reset Dead lock counter do { tryAgain = false; AcquireReadLock(); ISessionObject entry; try { dict.TryGetValue(Key, out entry); } finally { ReleaseReadLock(); } if (entry == null) { //Session not found Diags.LogSessionNotFound(Key); return(SessionActionResult.NotFound); } else { //Session Found if (entry.CompareExchangeIsInUse(true, false) == false) { //The InUse flag has been set and now this thread has exclusive access to this session object try { //Set IsExporting flag for this entry if item is to be exported if (isExporting) { entry.IsExporting = true; } //Call Reader Delegate if (Reader != null) { Reader(entry, StateObject); } if (isExporting) { Diags.LogSessionExporting(Key, entry); } else { Diags.LogSessionRead(Key, entry); } sessionIslocked = entry.IsLocked; } finally { if (!isExporting) //Remove inUse property if not exporting { entry.CompareExchangeIsInUse(false, true); } } } else { //Nope, it's still there so check if it's been exported and try again if (entry.IsExporting) { //This session is already been exported so leave Diags.ResetDeadLockCounter(); return(SessionActionResult.Exporting); } Thread.Sleep(1); //pause for 1 ms tryAgain = true; } Diags.DetectDeadLock(Key, DeadLockIterationCount); //Signal a deadlock after 2000 iterations } } while (tryAgain); Diags.ResetDeadLockCounter(); //Signal deadlock was freed if (sessionIslocked && !isExporting) { Diags.LogSessionIsLocked(Key); return(SessionActionResult.Locked); } else { return(SessionActionResult.OK); } }
/// <summary> /// Removes a session from the dictionary /// </summary> /// <param name="Key">Session Key</param> /// <param name="LockCookie">Lock Cookie</param> /// <param name="IsExpiring">Indicates that the item is being removed because it's expiring</param> /// <param name="ExpiryDate">The Item expiry date (for comparison)</param> /// <param name="LockedSessionInfo">Locked session information if session is locked</param> /// <returns>Result of Action</returns> private SessionActionResult Remove(string Key, uint LockCookie, bool IsExpiring, DateTime ExpiryDate, out SessionResponseInfo LockedSessionInfo) { if (Key == null) { throw new ArgumentNullException("Key"); } LockedSessionInfo = null; bool tryAgain; Diags.ResetDeadLockCounter(); do { tryAgain = false; AcquireReadLock(); ISessionObject entry; try { dict.TryGetValue(Key, out entry); } finally { ReleaseReadLock(); } if (entry == null) { //Session not found Diags.LogSessionNotFound(Key); return(SessionActionResult.NotFound); } else { //Session Found if (entry.CompareExchangeIsInUse(true, false) == false) { try { //The InUse flag is set and so this code section has exclusive access to this session object AcquireWriteLock(); try { //Check again to be sure, now that the write-lock has been obtained ISessionObject oldEntry = entry; if (!dict.TryGetValue(Key, out entry)) { //ooops -- another thread deleted the session from the dictionary while this thread //was either trying to do the compareExchange (or if buggy, while obtaining the write-lock) //so try again oldEntry.CompareExchangeIsInUse(false, true); //unlock the previously locked item tryAgain = true; continue; } if (IsExpiring) { DateTime timeStamp; if (expiryList.TryGetTimeStamp(Key, out timeStamp)) { if (timeStamp != ExpiryDate) { //The expiration date on this session was updated, so leave return(SessionActionResult.OK); } } } if (!IsExpiring && entry.IsLocked) //Locked items DO expire. if not expiring, LockCookie has to match session's { if (!entry.UnLock(LockCookie)) { //Lockcookie did not match LockedSessionInfo = (SessionResponseInfo)entry.CreateResponseInfo(); Diags.LogSessionIsLocked(Key); return(SessionActionResult.Locked); } } if (dict.Remove(Key)) { expiryList.Remove(Key); if (IsExpiring) { Diags.LogSessionExpired(Key); } else { Diags.LogSessionDeleted(Key); } } else { //This should never happen Diags.Fail("ASSERTION Failed -- Session dictionary was unable to remove key\r\n"); } } finally { ReleaseWriteLock(); } } finally { if (entry != null) { entry.CompareExchangeIsInUse(false, true); } } } else { //Is this entry being exported? if (entry.IsExporting) { //This session is already been exported so leave Diags.ResetDeadLockCounter(); return(SessionActionResult.Exporting); } //Another thread is using this session and will be done soon so try again Thread.Sleep(1); //pause for 1 ms tryAgain = true; } Diags.DetectDeadLock(Key, DeadLockIterationCount); //Signal a deadlock after 2000 iterations } } while (tryAgain); Diags.ResetDeadLockCounter(); //Signal deadlock was freed return(SessionActionResult.OK); }