Ejemplo n.º 1
0
        //The item is expired, call the "Refresh" action of this item to get a refresh value
        //1. If there's not enough worker threads, the dispatching thread will wait until the below 2 conditions happend:
        //(1). There is worker threads available
        //(2). There is user event comming (Add/Remove etc.)
        //2. If there's at least one worker thread, the dispatching thread will schedule the "Refresh" action in one worker thread
        //after the worker thread end to refresh the cache item, it will release the worker thread resource, and notify the
        //dispatching thread, so that other expired cache items wait for refresh worker thread can do their refresh job
        private bool RefreshExpiredCache(SchedulerKey sk, CacheItem ci)
        {
            //Refresh the expired item now, but firstly we should get a token
            if (Interlocked.Decrement(ref m_availRefreshThreadCount) < 0)
            {
                //Got an invalid token, return it
                Interlocked.Increment(ref m_availRefreshThreadCount);

                //No available refresh thread now, wait for one
                LogManager.Info("CacheManager:ProcessTimerEvents", string.Format("Begin to wait for refreshing thread token with key [{0}]", sk.Key));

                m_waitHandle.WaitOne();

                //Either there's an user event comming or a refresh thread token is available
                LogManager.Info("CacheManager:ProcessTimerEvents", string.Format("End to wait for refreshing thread token with key [{0}]", sk.Key));

                //No need to wait again, start a new loop
                return false;
            }

            //Save the last expiration time
            ci.LastExpirationInfo.LastExpiration = ci.NextExpirationTime;
            //Update the next expiration time for next schedule
            ci.NextExpirationTime = ci.Expiration.NextExpiration(ci.LastExpirationInfo);

            //Validation
            TimeSpan ts = ci.NextExpirationTime - ci.LastExpirationInfo.LastExpiration;
            if (ts.TotalMilliseconds < MIN_WAIT_TIME)
            {
                LogManager.Warn("CacheManager:ProcessTimerEvents", "Too short time interval, ts=" + ts.TotalMilliseconds);

                //wait 3s
                ci.NextExpirationTime = ci.LastExpirationInfo.LastExpiration.AddMilliseconds(3000);
            }

            //Re-schedule again
            m_heap.Remove(sk);
            m_heap.Add(new SchedulerKey(ci.NextExpirationTime, sk.Key), DUMMY);

            //Fire the refresh action
            Task.Factory.StartNew(() =>
            {
                try
                {
                    ci.RefreshAsync();

                    //Release the token
                    Interlocked.Increment(ref m_availRefreshThreadCount);

                    //And notify the listeners
                    m_waitHandle.Set();
                }
                catch (Exception ex)
                {
                    LogManager.Error(string.Format("Task for key [{0}] exception", ci.Key), ex);
                }
            });

            return true;
        }