LogUpdatedSession() 개인적인 메소드

private LogUpdatedSession ( string key, ISessionObject Session ) : void
key string
Session ISessionObject
리턴 void
예제 #1
0
        /// <summary>
        /// Updates or inserts a session in the dictionary
        /// </summary>
        /// <param name="Key">Session Key</param>
        /// <param name="Session">Session object</param>
        /// <param name="InsertOnly">Indicates that session should only be inserted if it does not already exist</param>
        /// <param name="UpdateIfNotFound">Indicates whether session should be updated if the session was not found. If set to flase, this gives the caller a chance to query the network before trying again </param>
        /// <param name="LockedSessionInfo">Locked session information if session is locked</param>
        /// <returns>Result of Action</returns>
        private SessionActionResult UpSert(string Key, ISessionObject Session, bool InsertOnly, bool UpdateIfNotFound, out SessionResponseInfo LockedSessionInfo)
        {
            // Look for the session using a reader lock.
            // If session is not found, switch to a writer lock and insert item.
            // If session is found:
            // Perform an atomic compare exchange on the variable 'InUse'
            // If session is in Use, try Upsert again from the start.
            // If session is not in Use, Perform UpSert and reset InUse
            // Also update Sorted session list

            if (Key == null)
            {
                throw new ArgumentNullException("Key");
            }
            if (Session == null)
            {
                throw new ArgumentNullException("Session");
            }

            LockedSessionInfo = null;
            bool tryAgain;

            Diags.ResetDeadLockCounter();
            do
            {
                tryAgain = false;
                AcquireReadLock();
                ISessionObject entry;
                try
                {
                    dict.TryGetValue(Key, out entry);
                }
                finally
                {
                    ReleaseReadLock();
                }

                if (entry == null)
                {
                    if (!UpdateIfNotFound)
                    {
                        return(SessionActionResult.NotFound);
                    }

                    //Session not found -- insert brand new session object
                    AcquireWriteLock();
                    try
                    {
                        //Check again to be sure now that the write-lock has been obtained
                        dict.TryGetValue(Key, out entry);
                        if (entry != null)
                        {
                            //ooops -- another thread inserted a seesion with this key while this thread was trying to obtain the write-lock
                            //so try again
                            tryAgain = true;
                            continue;
                        }

                        Session.LockCookie = 1; //For some reason Lockcookie starts counting from 2 -- so set it to 1 now so that it increments to 2 when sought
                        dict[Key]          = Session;
                        expiryList.Add(DateTime.UtcNow.Add(new TimeSpan(0, Session.TimeOut, 0)), Key, Key);
                        Diags.LogNewSession(Key, Session);
                    }
                    finally
                    {
                        ReleaseWriteLock();
                    }
                }
                else
                {
                    //Session Found

                    if (InsertOnly)
                    {
                        Diags.LogSessionAlreadyExists(Key);
                        return(SessionActionResult.AlreadyExists); //Do not perform an update if InsertOnly is requested
                    }

                    //There is no need to acquire a write lock here since the dictionary is not been modified.
                    //Only the dictionary entry itself is been updated and such updates are guaranteed to be atomic
                    //if the atomic InUse property is set.

                    if (entry.CompareExchangeIsInUse(true, false) == false)
                    {
                        //the InUse flag is set, so this code section has exclusive access to this session object
                        try
                        {
                            if (entry.IsLocked)
                            {
                                if (!entry.UnLock(Session.LockCookie))
                                {
                                    //Lockcookie did not match
                                    LockedSessionInfo = (SessionResponseInfo)entry.CreateResponseInfo();
                                    Diags.LogSessionIsLocked(Key);
                                    return(SessionActionResult.Locked);
                                }
                            }

                            Session.LockCookie = entry.LockCookie;                                              //Overwrite the incoming session's lock-cookie with the internal one's so as not to let external input change the lockcookie
                            Session.ExtraFlags = -1;                                                            //disable extra flags since an update is being performed

                            entry.CopyFrom(Session);                                                            //Copy all information from Session to entry
                            expiryList.Add(DateTime.UtcNow.Add(new TimeSpan(0, Session.TimeOut, 0)), Key, Key); //reset expiry timeout
                            Diags.LogUpdatedSession(Key, Session);
                        }
                        finally
                        {
                            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);
        }