//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; }
private bool DoGetOrAdd(OperationEvent operEvent) { CacheItem ci = operEvent.OperObject as CacheItem; if (ci == null) { LogManager.Warn("CacheManager:Assert Failure", "DoGetOrAdd a null item"); return true; } //Cache Item bool added = m_cacheItems.TryAdd(ci.Key, ci); if (added) { //Add the SchedulerKey at the same time SchedulerKey sk = new SchedulerKey(ci.NextExpirationTime, ci.Key); if (m_heap.ContainsKey(sk)) { //This should not happen. If it does, then this is a critial bug! LogManager.Warn("CacheManager:Assert Failure", string.Format("The SchedulerKey key[{0}] is already exising", sk.ToString())); } else { m_heap.Add(sk, DUMMY); } operEvent.OperResult = ci; LogManager.Info("CacheManager:DoGetOrAdd", string.Format("The key [{0}] is added, value=[{1}]", ci.Key, ci.ToString())); } else { CacheItem existingItem = null; if (!m_cacheItems.TryGetValue(ci.Key, out existingItem)) { //This should not happen. If it does, then this is a critial bug! LogManager.Warn("CacheManager:Assert Failure", string.Format("The expected existing key[{0}] doesn't exist", ci.Key)); } else if (existingItem == null) { //This should not happen. If it does, then this is a critial bug! LogManager.Warn("CacheManager:Assert Failure", string.Format("The expected existing key[{0}] is null", ci.Key)); } else { operEvent.OperResult = existingItem; //LogManager.Debug("CacheManager:DoGetOrAdd", string.Format("The key [{0}] is already existing, value=[{1}]", // ci.Key, existingItem.ToString())); } } return true; }
private bool DoRemove(CacheItem ci) { if (ci == null) { LogManager.Warn("CacheManager:Assert Failure", "DoRemove a null item"); return true; } CacheItem value = null; if (!m_cacheItems.TryRemove(ci.Key, out value)) { LogManager.Warn("CacheManager:DoRemove", string.Format("The CacheItem key[{0}] is already removed", ci.Key)); } SchedulerKey sk = new SchedulerKey(ci.NextExpirationTime, ci.Key); if (!m_heap.ContainsKey(sk)) { LogManager.Warn("CacheManager:DoRemove", string.Format("The SchedulerKey key[{0}] is already removed", sk.ToString())); } else { m_heap.Remove(sk); } LogManager.Info("CacheManager:DoRemove", string.Format("The key [{0}] is removed", ci.Key)); return true; }
private bool DoAdd(CacheItem ci) { if (ci == null) { LogManager.Warn("CacheManager:Assert Failure", "DoAdd a null item"); return true; } //Cache Item bool added = m_cacheItems.TryAdd(ci.Key, ci); if (added) { //Add the SchedulerKey at the same time SchedulerKey sk = new SchedulerKey(ci.NextExpirationTime, ci.Key); if (m_heap.ContainsKey(sk)) { //This should not happen. If it does, then this is a critial bug! LogManager.Warn("CacheManager:Assert Failure", string.Format("The SchedulerKey key[{0}] is already exising", sk.ToString())); } else { m_heap.Add(sk, DUMMY); } } if (added) { LogManager.Info("CacheManager:DoAdd", string.Format("The key [{0}] is added, value=[{1}]", ci.Key, ci.ToString())); } else { LogManager.Info("CacheManager:DoAdd", string.Format("The key [{0}] is already existing", ci.Key)); } return true; }