예제 #1
0
		private static void Remove(CacheDependency dependency)
		{
			lock (dependencies)
			{
				dependencies.Remove(dependency.fileOrDirectory);
			}
		}
예제 #2
0
		/// <summary>
		/// 使用指定的文件名或目录获取一个依赖项,如果与指定的文件名或目录对应的依赖项不存在,那么新建一个与其关联的依赖项并返回它。
		/// </summary>
		/// <param name="fileOrDirectory">指定的文件名或目录。</param>
		/// <returns>CacheDependency 对象。</returns>
		/// <remarks>
		/// 如果传入的文件名或目录不合法,那么该方法返回 null。
		/// </remarks>
		public static CacheDependency Get(string fileOrDirectory)
		{
			if (!String.IsNullOrEmpty(fileOrDirectory))
			{
				// fileOrDirectory	GetFileName		GetDirectoryName
				// \zhaixd\a\b		> b				\zhaixd\a
				// D:\a\b			> b				D:\a
				// D:\a\b\			> String.Empty	D:\a\b
				// \zhaixd\a\b.txt	> b.txt			\zhaixd\a
				// D:\a\b.txt		> b.txt			D:\a
				// D:\				> String.Empty	null
				// a				> String.Empty	String.Empty
				string directoryName = Path.GetDirectoryName(fileOrDirectory);
				if (!String.IsNullOrEmpty(directoryName))
				{
					string fileName = Path.GetFileName(fileOrDirectory);

					lock (dependencies)
					{
						CacheDependency cacheDependency;
						if (dependencies.ContainsKey(fileOrDirectory))
						{
							cacheDependency = dependencies[fileOrDirectory];
							if (!cacheDependency.hasChanged)
							{
								return cacheDependency;
							}
						}

						cacheDependency = new CacheDependency(fileOrDirectory, directoryName, fileName);
						dependencies.Add(fileOrDirectory, cacheDependency);
						cacheDependency.fsw.EnableRaisingEvents = true;
						return cacheDependency;
					}
				}
			}
			return null;
		}
예제 #3
0
			private void SetItemInternal(string key, object value, CacheDependency dependency, TimeSpan timeToLive, DateTime? nextUpdateTime, params string[] tags)
			{
				if (string.IsNullOrWhiteSpace(key))
				{
					throw new ArgumentNullOrWhiteSpaceException("key");
				}
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}

				CachedItem item = new CachedItem();

				if (tags != null && tags.Length > 0)
				{
					EnsureTags(tags);

					item.Tags = tags;
				}

				item.Key = key;
				item.Value = value;
				item.ExpiredTime = timeToLive.Days > 1000 ? DateTime.Now.AddDays(1000) : DateTime.Now + timeToLive;
				item.NextUpdateTime = nextUpdateTime;

				item.Dependency = dependency;

				// 优化实现: 使用读写锁,减少高并发读取阻塞
				this.lock4Items.EnterWriteLock();
				try
				{
					// 覆盖时处理旧项
					if (this.cachedItems.ContainsKey(key))
					{
						this.RemoveItemInternal(key);
					}

					#region LRU 支持
					if (this.cachedItems.Count >= this.capacity)
					{
						this.RemoveItemInternal(this.linkedList.Last.item.Key);
					}
					#endregion

					this.cachedItems.Add(key, item);

					#region LRU 支持,新添加的设为第一个
					this.linkedList.AddFirst(item);
					item.Node = this.linkedList.First;
					#endregion

					if (tags != null && tags.Length > 0)
					{
						foreach (string tag in tags)
						{
							if (!this.cachedItemKeyByTags.ContainsKey(tag))
							{
								this.cachedItemKeyByTags.Add(tag, new Dictionary<string, KeyValuePair<string, CachedItem>>(StringComparer.InvariantCultureIgnoreCase));
							}
							Dictionary<string, KeyValuePair<string, CachedItem>> keys = this.cachedItemKeyByTags[tag];
							if (!this.cachedItemObjectByTags.ContainsKey(tag))
							{
								this.cachedItemObjectByTags.Add(tag, new List<KeyValuePair<string, CachedItem>>());
							}
							List<KeyValuePair<string, CachedItem>> objects = this.cachedItemObjectByTags[tag];

							KeyValuePair<string, CachedItem> newKvp = new KeyValuePair<string, CachedItem>(key, item);
							int index;
							if (keys.ContainsKey(key) && ((index = objects.IndexOf(keys[key])) >= 0)) // 覆盖时
							{
								objects[index] = newKvp;
							}
							else
							{
								objects.Add(newKvp);
							}
							keys[key] = newKvp;
						}
					}
				}
				finally
				{
					this.lock4Items.ExitWriteLock();
				}
			}
예제 #4
0
			public void SetItem(string key, object value, CacheDependency dependency, TimeSpan timeToLive, params string[] tags)
			{
				this.SetItemInternal(key, value, dependency, timeToLive, null, tags);
			}
예제 #5
0
			public Region(NamedCache owner, string name, int capacity, int asyncUpdateInterval, string fileOrDirectory)
			{
				this.owner = owner;

				this.name = name;

				this.capacity = capacity;
				this.asyncUpdateInterval = asyncUpdateInterval;

				this.cachedItems = new Dictionary<string, CachedItem>(this.capacity, StringComparer.InvariantCultureIgnoreCase);
				this.cachedItemKeyByTags = new Dictionary<string, Dictionary<string, KeyValuePair<string, CachedItem>>>(16, StringComparer.InvariantCultureIgnoreCase);
				this.cachedItemObjectByTags = new Dictionary<string, List<KeyValuePair<string, CachedItem>>>(16, StringComparer.InvariantCultureIgnoreCase);

				this.Dependency = CacheDependency.Get(fileOrDirectory);
			}
예제 #6
0
			public NamedCache(string name, string fileOrDirectory)
			{
				this.name = name;

				this.Dependency = CacheDependency.Get(fileOrDirectory);
			}
예제 #7
0
		private object GetAndSetItem(string cacheName, string regionName, string key, Func<object, object> callback, object callBackState, CacheDependency dependency, params string[] tags)
		{
			if (string.IsNullOrWhiteSpace(cacheName))
			{
				throw new ArgumentNullOrWhiteSpaceException("cacheName");
			}

			if (string.IsNullOrWhiteSpace(regionName))
			{
				throw new ArgumentNullOrWhiteSpaceException("regionName");
			}

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

			return this.GetOrCreateCache(cacheName).GetOrCreateRegion(regionName).GetAndSetItem(key, callback, callBackState, dependency, tags);
		}
예제 #8
0
			public object GetAndSetItem(string regionName, string key, Func<object, object> callback, object callBackState, CacheDependency dependency)
			{
				object result = null;
				try
				{
					result = LocalCacheManager.Instance.GetAndSetItem(CacheName, regionName, key, callback, callBackState, dependency, null);
				}
				catch (ArgumentException are)
				{
					Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, are.GetFriendlyToString()), LogCategory.Cache);
				}
				catch (ConfigurationException confExp)
				{
					if (confExp is IgnoredConfigurationException) // 这种类型的配置错误不做任何处理,以避免产生大量同类型的配置错误日志
					{
					}
					else
					{
						Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, confExp.GetFriendlyToString()), LogCategory.Cache);
					}
				}
				catch (Exception err)
				{
					Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, err.GetFriendlyToString()), LogCategory.Cache);
				}
				return result;
			}
예제 #9
0
		public void SetItem(string cacheName, string regionName, string key, object value, CacheDependency dependency, TimeSpan timeToLive, params string[] tags)
		{
			if (string.IsNullOrWhiteSpace(cacheName))
			{
				throw new ArgumentNullOrWhiteSpaceException("cacheName");
			}

			if (string.IsNullOrWhiteSpace(regionName))
			{
				throw new ArgumentNullOrWhiteSpaceException("regionName");
			}

			this.GetOrCreateCache(cacheName).GetOrCreateRegion(regionName).SetItem(key, value, dependency, timeToLive, tags);
		}
예제 #10
0
			public void SetItem(string key, object value, CacheDependency dependency, int timeToLiveInSeconds, params string[] tags)
			{
				this.SetItemInternal(key, value, dependency, TimeSpan.FromSeconds(timeToLiveInSeconds), null, tags);
			}
예제 #11
0
				public CachedItemCallbackWrapper(CachedItem item, Func<object, object> callback, object callBackState, CacheDependency dependency, TimeSpan timeToLive, params string[] tags)
				{
					this.Item = item;
					
					this.Callback = callback;
					this.CallBackState = callBackState;

					this.Dependency = dependency;

					this.TTL = timeToLive;

					this.Tags = tags;
				}
예제 #12
0
			public Region(NamedCache owner, string name, int capacity, TimeSpan asyncTimeToLive, TimeSpan asyncUpdateInterval, string fileOrDirectory)
			{
				this.owner = owner;

				this.name = name;
                if (this.name == "_CFG_AppSettings")
                    this.isAppsettingRegion = true;

				this.capacity = capacity;
				this.asyncTimeToLive = asyncTimeToLive;
				this.asyncUpdateInterval = asyncUpdateInterval;

				this.cachedItems = new Dictionary<string, CachedItem>(this.capacity, StringComparer.InvariantCultureIgnoreCase);
				this.cachedItemKeyByTags = new Dictionary<string, Dictionary<string, KeyValuePair<string, CachedItem>>>(16, StringComparer.InvariantCultureIgnoreCase);
				this.cachedItemObjectByTags = new Dictionary<string, List<KeyValuePair<string, CachedItem>>>(16, StringComparer.InvariantCultureIgnoreCase);

				this.Dependency = CacheDependency.Get(fileOrDirectory);
			}
예제 #13
0
		public object GetAndSetItem(string regionName, string key, Func<object, object> callback, object callBackState, CacheDependency dependency, params string[] tags)
		{
			object result = null;
			try
			{
				result = LocalCacheManager.Instance.GetAndSetItem(CacheName, regionName, key, callback, callBackState, dependency, tags);
			}
			catch (ArgumentException are)
			{
				Container.LogService.Warn(are.Message, LogCategory.Cache);
			}
			catch (Exception err)
			{
				Container.LogService.Warn(err, LogCategory.Cache);
			}
			return result;
		}
예제 #14
0
		public void SetItemWithNoExpiration(string regionName, string key, object value, CacheDependency dependency, params string[] tags)
		{
			if (value == null)
			{
				return;
			}

			try
			{
				LocalCacheManager.Instance.SetItemWithNoExpiration(CacheName, regionName, key, value, dependency, tags);
			}
			catch (ArgumentException are)
			{
				Container.LogService.Warn(are.Message, LogCategory.Cache);
			}
			catch (Exception err)
			{
				Container.LogService.Warn(err, LogCategory.Cache);
			}
		}
예제 #15
0
		public void SetItem(string regionName, string key, object value, CacheDependency dependency, int timeToLiveInSeconds, params string[] tags)
		{
			try
			{
				LocalCacheManager.Instance.SetItem(CacheName, regionName, key, value, dependency, timeToLiveInSeconds, tags);
			}
			catch (ArgumentException are)
			{
				Container.LogService.Warn(are.Message, LogCategory.Cache);
			}
			catch (Exception err)
			{
				Container.LogService.Warn(err, LogCategory.Cache);
			}
		}
예제 #16
0
				public CachedItemCallbackWrapper(CachedItem item, Func<object, object> callback, object callBackState, CacheDependency dependency, int timeToLiveInSeconds, params string[] tags)
				{
					this.Item = item;
					
					this.Callback = callback;
					this.CallBackState = callBackState;

					this.Dependency = dependency;

					this.TTL = TimeSpan.FromSeconds(timeToLiveInSeconds);

					this.Tags = tags;
				}
예제 #17
0
			public object GetAndSetItem(string key, Func<object, object> callback, object callBackState, CacheDependency dependency, params string[] tags)
			{
				CachedItem cachedItem = this.GetCachedItem(key);
               
				// 缓存项不存在时立即添加新的缓存项并返回
				if (cachedItem == null)
				{
					object cacheItemLock = null;

					lock (cacheItemLocks)
					{
						if (!cacheItemLocks.ContainsKey(key))
						{
							cacheItemLock = new object();

							cacheItemLocks[key] = cacheItemLock;
						}
						else
						{
							cacheItemLock = cacheItemLocks[key];
						}
					}

					object value = null;

					lock (cacheItemLock)
					{
						cachedItem = this.GetCachedItem(key);

						if (cachedItem == null)
						{
							value = callback(callBackState);

							if (value != null)
							{
								// 缓存项在缓存服务器中的生存时间为:异步更新间隔+5分钟,这足够保证缓存项能够及时成功更新
								// 同时,可以避免添加当前缓存项的客户端应用终止时(客户端应用中保存的 cacheItemVersions 失效,其它客户端因为仅读取该缓存项而没有存储其版本,永远不会更新该缓存项)
								// 缓存项将可能在很长时间(由传入的 timeToLive 值决定)内不再更新的问题
								this.SetItemInternal(key, value, dependency, TimeSpan.FromSeconds(this.asyncUpdateInterval + this.asyncUpdateAdditionalLiveTime), DateTime.Now.AddSeconds(this.asyncUpdateInterval), tags);
							}
						}
						else
						{
							value = cachedItem.Value;
						}
					}

					lock (cacheItemLocks)
					{
						cacheItemLocks.Remove(key);
					}

					return value;
				}

				// 首先不是处于更新过程中且时间上判断应更新缓存项,使用双重检查锁定机制并通过任务并行库异步更新缓存项
				if (!cachedItem.IsUpdating && cachedItem.NextUpdateTime < DateTime.Now)
				{
					lock (cachedItem) // 仅锁定当前缓存项,尽可能的避免阻塞对其它缓存项的访问
					{
						if (!cachedItem.IsUpdating && cachedItem.NextUpdateTime < DateTime.Now)
						{
							cachedItem.IsUpdating = true;

							System.Threading.Tasks.Task.Factory.StartNew(this.UpdateCacheItem, new CachedItemCallbackWrapper(cachedItem, callback, callBackState, dependency, this.asyncUpdateInterval + this.asyncUpdateAdditionalLiveTime, tags));
						}
					}
				}

				// 在异步更新缓存项之前立即返回当前缓存项的值。
				return cachedItem.Value;
			}
예제 #18
0
		public void SetItem(string cacheName, string regionName, string key, object value, CacheDependency dependency, int timeToLiveInSeconds, params string[] tags)
		{
			this.SetItem(cacheName, regionName, key, value, dependency, TimeSpan.FromSeconds(timeToLiveInSeconds), tags);
		}
예제 #19
0
		public void SetItemWithNoExpiration(string cacheName, string regionName, string key, object value, CacheDependency dependency, params string[] tags)
		{
			this.SetItem(cacheName, regionName, key, value, dependency, TimeSpan.MaxValue, tags);
		}
예제 #20
0
			public bool SetItemWithNoExpiration(string regionName, string key, object value, CacheDependency dependency)
			{
				if (value == null)
				{
					return false;
				}

				try
				{
					LocalCacheManager.Instance.SetItemWithNoExpiration(CacheName, regionName, key, value, dependency, null);

					return true;
				}
				catch (ArgumentException are)
				{
					Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, are.GetFriendlyToString()), LogCategory.Cache);
				}
				catch (ConfigurationException confExp)
				{
					if (confExp is IgnoredConfigurationException) // 这种类型的配置错误不做任何处理,以避免产生大量同类型的配置错误日志
					{
					}
					else
					{
						Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, confExp.GetFriendlyToString()), LogCategory.Cache);
					}
				}
				catch (Exception err)
				{
					Container.LogService.Warn(String.Format("{0}_{1}:{2}", regionName, key, err.GetFriendlyToString()), LogCategory.Cache);
				}

				return false;
			}