/// <inheritdoc /> public override Task CreateUninitializedItemAsync( HttpContextBase context, string id, int timeout, CancellationToken cancellationToken) { if (id == null) { throw new ArgumentNullException("id"); } if (id.Length > SessionIDManager.SessionIDMaxLength) { throw new ArgumentException(SR.Session_id_too_long); } var state = new InProcSessionState( null, null, timeout, false, DateTime.MinValue, NewLockCookie, (int)SessionStateItemFlags.Uninitialized); InsertToCache(id, state); return(Task.CompletedTask); }
private void InsertToCache(string key, InProcSessionState value) { var cachePolicy = new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0, value.Timeout, 0), RemovedCallback = _callback, Priority = CacheItemPriority.NotRemovable }; s_store.Set(key, value, cachePolicy); }
private SessionStateStoreData DoGet(HttpContextBase context, String id, bool exclusive, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { // Set default return values locked = false; lockId = null; lockAge = TimeSpan.Zero; actionFlags = 0; InProcSessionState state = (InProcSessionState)s_store.Get(id); if (state != null) { bool lockedByOther; // True if the state is locked by another session int initialFlags; initialFlags = state.Flags; if ((initialFlags & (int)SessionStateItemFlags.Uninitialized) != 0) { // It is an uninitialized item. We have to remove that flag. // We only allow one request to do that. // If initialFlags != return value of CompareExchange, it means another request has // removed the flag. if (initialFlags == Interlocked.CompareExchange( ref state.Flags, initialFlags & (~((int)SessionStateItemFlags.Uninitialized)), initialFlags)) { actionFlags = SessionStateActions.InitializeItem; } } if (exclusive) { lockedByOther = true; // If unlocked, use a spinlock to test and lock the state. if (!state.Locked) { var lockTaken = false; try { state.SpinLock.Enter(ref lockTaken); if (!state.Locked) { lockedByOther = false; state.Locked = true; state.LockDate = DateTime.UtcNow; state.LockCookie++; } lockId = state.LockCookie; } finally { if (lockTaken) { state.SpinLock.Exit(); } } } else { // It's already locked by another request. Return the lockCookie to caller. lockId = state.LockCookie; } } else { var lockTaken = false; state.SpinLock.Enter(ref lockTaken); try { lockedByOther = state.Locked; lockId = state.LockCookie; } finally { if (lockTaken) { state.SpinLock.Exit(); } } } if (lockedByOther) { // Item found, but locked locked = true; lockAge = DateTime.UtcNow - state.LockDate; return(null); } else { return(CreateLegitStoreData(context, state.SessionItems, state.StaticObjects, state.Timeout)); } } // Not found return(null); }
/// <inheritdoc /> public override Task SetAndReleaseItemExclusiveAsync( HttpContextBase context, string id, SessionStateStoreData item, object lockId, bool newItem, CancellationToken cancellationToken) { if (id == null) { throw new ArgumentNullException("id"); } if (id.Length > SessionIDManager.SessionIDMaxLength) { throw new ArgumentException(SR.Session_id_too_long); } Debug.Assert(item != null, "item != null"); Debug.Assert(item.StaticObjects != null, "item.StaticObjects != null"); ISessionStateItemCollection items = null; HttpStaticObjectsCollection staticObjects = null; var doInsert = true; var lockCookieForInsert = NewLockCookie; if (item.Items.Count > 0) { items = item.Items; } if (!item.StaticObjects.NeverAccessed) { staticObjects = item.StaticObjects; } if (!newItem) { var currentState = (InProcSessionState)s_store.Get(id); var lockCookie = (int)lockId; if (currentState == null) { return(Task.CompletedTask); } var lockTaken = false; try { currentState.SpinLock.Enter(ref lockTaken); // we can change the state in place if the timeout hasn't changed if (currentState.Timeout == item.Timeout) { currentState.Copy(items, staticObjects, item.Timeout, false, DateTime.MinValue, lockCookie, currentState.Flags); doInsert = false; } else { /* We are going to insert a new item to replace the current one in Cache * because the expiry time has changed. * * Pleas note that an insert will cause the Session_End to be incorrectly raised. * * Please note that the item itself should not expire between now and * where we do MemoryCache.Insert below because MemoryCache.Get above have just * updated its expiry time. */ currentState.Flags |= (int)SessionStateItemFlags.IgnoreCacheItemRemoved; lockCookieForInsert = lockCookie; } } finally { if (lockTaken) { currentState.SpinLock.Exit(); } } } if (doInsert) { var newState = new InProcSessionState( items, staticObjects, item.Timeout, false, DateTime.MinValue, lockCookieForInsert, 0); InsertToCache(id, newState); } return(Task.CompletedTask); }