private static void ReleaseItemExclusive(sqlTableServiceContext svc, SessionRow session, object lockId) { if ((int)lockId != session.Lock) { // obviously that can happen, but let's see when at least in Debug mode Debug.Assert(false); return; } session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); session.Locked = false; svc.UpdateObject(session); svc.SaveChangesWithRetries(); }
public override void ResetItemTimeout(HttpContext context, string id) { Debug.Assert(context != null); SecUtility.CheckParameter(ref id, true, true, false, Configuration.MaxStringPropertySizeInChars, "id"); _providerRetry(() => { sqlTableServiceContext svc = CreateDataServiceContext(); SessionRow session = GetSession(id, svc); session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); svc.UpdateObject(session); svc.SaveChangesWithRetries(); }); }
// we don't use the retry policy itself in this function because out parameters are not well handled by // retry policies private SessionStateStoreData GetSession(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions, bool exclusive) { Debug.Assert(context != null); SecUtility.CheckParameter(ref id, true, true, false, Configuration.MaxStringPropertySizeInChars, "id"); SessionRow session = null; int curRetry = 0; bool retry = false; // Assign default values to out parameters locked = false; lockId = null; lockAge = TimeSpan.Zero; actions = SessionStateActions.None; do { retry = false; try { sqlTableServiceContext svc = CreateDataServiceContext(); session = GetSession(id, svc); // Assign default values to out parameters locked = false; lockId = null; lockAge = TimeSpan.Zero; actions = SessionStateActions.None; // if the blob does not exist, we return null // ASP.NET will call the corresponding method for creating the session if (session == null) { return(null); } if (session.Initialized == false) { Debug.Assert(session.Locked == false); actions = SessionStateActions.InitializeItem; session.Initialized = true; } session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); if (exclusive) { if (!session.Locked) { if (session.Lock == Int32.MaxValue) { session.Lock = 0; } else { session.Lock++; } session.LockDateUtc = DateTime.UtcNow; } lockId = session.Lock; locked = session.Locked; session.Locked = true; } lockAge = DateTime.UtcNow.Subtract(session.LockDateUtc); lockId = session.Lock; if (locked == true) { return(null); } // let's try to write this back to the data store // in between, someone else could have written something to the store for the same session // we retry a number of times; if all fails, we throw an exception svc.UpdateObject(session); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { // precondition fails indicates problems with the status code if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.PreconditionFailed) { retry = true; } else { throw new ProviderException("Error accessing the data store.", e); } } } while (retry && curRetry++ < NumRetries); // ok, now we have successfully written back our state // we can now read the blob // note that we do not need to care about read/write locking when accessing the // blob because each time we write a new session we create a new blob with a different name SessionStateStoreData result = null; MemoryStream stream = null; StreamReader reader = null; sqlBlobProperties properties; try { try { stream = _blobProvider.GetBlobContent(session.BlobName, out properties); } catch (Exception e) { throw new ProviderException("Couldn't read session blob!", e); } reader = new StreamReader(stream); if (actions == SessionStateActions.InitializeItem) { // Return an empty SessionStateStoreData result = new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), session.Timeout); } else { // Read Items, StaticObjects, and Timeout from the file byte[] items = Convert.FromBase64String(reader.ReadLine()); byte[] statics = Convert.FromBase64String(reader.ReadLine()); int timeout = session.Timeout; // Deserialize the session result = DeserializeSession(items, statics, timeout); } } finally { if (stream != null) { stream.Close(); } if (reader != null) { reader.Close(); } } return(result); }