Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Security / TimeBoundedCache.cs / 1 / TimeBoundedCache.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.ServiceModel.Security { using System; using System.ServiceModel; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; using System.ServiceModel.Channels; ////// NOTE: this class does minimum argument checking as it is all internal /// internal class TimeBoundedCache { static WaitCallback purgeCallback; ReaderWriterLock cacheLock; Hashtable entries; // if there are less than lowWaterMark entries, no purging is done int lowWaterMark; int maxCacheItems; DateTime nextPurgeTimeUtc; TimeSpan purgeInterval; PurgingMode purgingMode; IOThreadTimer purgingTimer; bool doRemoveNotification; protected TimeBoundedCache(int lowWaterMark, int maxCacheItems, IEqualityComparer keyComparer, PurgingMode purgingMode, TimeSpan purgeInterval, bool doRemoveNotification) { this.entries = new Hashtable(keyComparer); this.cacheLock = new ReaderWriterLock(); this.lowWaterMark = lowWaterMark; this.maxCacheItems = maxCacheItems; this.purgingMode = purgingMode; this.purgeInterval = purgeInterval; this.doRemoveNotification = doRemoveNotification; this.nextPurgeTimeUtc = DateTime.UtcNow.Add(this.purgeInterval); } public int Count { get { return this.entries.Count; } } static WaitCallback PurgeCallback { get { if (purgeCallback == null) { purgeCallback = new WaitCallback(PurgeCallbackStatic); } return purgeCallback; } } protected int Capacity { get { return this.maxCacheItems; } } protected Hashtable Entries { get { return this.entries; } } protected ReaderWriterLock CacheLock { get { return this.cacheLock; } } protected bool TryAddItem(object key, object item, DateTime expirationTime, bool replaceExistingEntry) { return this.TryAddItem(key, new ExpirableItem(item, expirationTime), replaceExistingEntry); } void CancelTimerIfNeeded() { if (this.Count == 0 && this.purgingTimer != null) { this.purgingTimer.Cancel(); this.purgingTimer = null; } } void StartTimerIfNeeded() { if (this.purgingMode != PurgingMode.TimerBasedPurge) { return; } if (this.purgingTimer == null) { this.purgingTimer = new IOThreadTimer(PurgeCallback, this, false); this.purgingTimer.Set(this.purgeInterval); } } protected bool TryAddItem(object key, IExpirableItem item, bool replaceExistingEntry) { bool lockHeld = false; try { try { } finally { this.cacheLock.AcquireWriterLock(-1); lockHeld = true; } PurgeIfNeeded(); EnforceQuota(); IExpirableItem currentItem = this.entries[key] as IExpirableItem; if (currentItem == null || IsExpired(currentItem)) { this.entries[key] = item; } else if (!replaceExistingEntry) { return false; } else { this.entries[key] = item; } if (currentItem != null && doRemoveNotification) { this.OnRemove(ExtractItem(currentItem)); } StartTimerIfNeeded(); return true; } finally { if (lockHeld) { this.cacheLock.ReleaseWriterLock(); } } } protected bool TryReplaceItem(object key, object item, DateTime expirationTime) { bool lockHeld = false; try { try { } finally { this.cacheLock.AcquireWriterLock(-1); lockHeld = true; } PurgeIfNeeded(); EnforceQuota(); IExpirableItem currentItem = this.entries[key] as IExpirableItem; if (currentItem == null || IsExpired(currentItem)) { return false; } else { this.entries[key] = new ExpirableItem(item, expirationTime); if (currentItem != null && doRemoveNotification) { this.OnRemove(ExtractItem(currentItem)); } StartTimerIfNeeded(); return true; } } finally { if (lockHeld) { this.cacheLock.ReleaseWriterLock(); } } } protected void ClearItems() { bool lockHeld = false; try { try { } finally { this.cacheLock.AcquireWriterLock(-1); lockHeld = true; } int count = this.entries.Count; if (doRemoveNotification) { foreach (IExpirableItem item in this.entries.Values) { OnRemove(ExtractItem(item)); } } this.entries.Clear(); CancelTimerIfNeeded(); } finally { if (lockHeld) { this.cacheLock.ReleaseWriterLock(); } } } protected object GetItem(object key) { bool lockHeld = false; try { try { } finally { this.cacheLock.AcquireReaderLock(-1); lockHeld = true; } IExpirableItem item = this.entries[key] as IExpirableItem; if (item == null) { return null; } else if (IsExpired(item)) { // this is a stale item return null; } else { return ExtractItem(item); } } finally { if (lockHeld) { this.cacheLock.ReleaseReaderLock(); } } } protected virtual ArrayList OnQuotaReached(Hashtable cacheTable) { this.ThrowQuotaReachedException(); return null; } protected virtual void OnRemove(object item) { } protected bool TryRemoveItem(object key) { bool lockHeld = false; try { try { } finally { this.cacheLock.AcquireWriterLock(-1); lockHeld = true; } PurgeIfNeeded(); IExpirableItem currentItem = this.entries[key] as IExpirableItem; bool result = (currentItem != null) && !IsExpired(currentItem); if (currentItem != null) { this.entries.Remove(key); if (doRemoveNotification) { this.OnRemove(ExtractItem(currentItem)); } CancelTimerIfNeeded(); } return result; } finally { if (lockHeld) { this.cacheLock.ReleaseWriterLock(); } } } void EnforceQuota() { if (!(this.cacheLock.IsWriterLockHeld == true)) { // we failfast here because if we don't have the lock we could corrupt the cache DiagnosticUtility.DebugAssert("Cache write lock is not held."); DiagnosticUtility.FailFast("Cache write lock is not held."); } if (this.Count >= this.maxCacheItems) { ArrayList keysToBeRemoved; keysToBeRemoved = this.OnQuotaReached(this.entries); if (keysToBeRemoved != null) { for (int i = 0; i < keysToBeRemoved.Count; ++i) { this.entries.Remove(keysToBeRemoved[i]); } } CancelTimerIfNeeded(); if (this.Count >= this.maxCacheItems) { this.ThrowQuotaReachedException(); } } } protected object ExtractItem(IExpirableItem val) { ExpirableItem wrapper = (val as ExpirableItem); if (wrapper != null) { return wrapper.Item; } else { return val; } } bool IsExpired(IExpirableItem item) { DiagnosticUtility.DebugAssert(item.ExpirationTime == DateTime.MaxValue || item.ExpirationTime.Kind == DateTimeKind.Utc, ""); return (item.ExpirationTime <= DateTime.UtcNow); } bool ShouldPurge() { if (this.Count >= this.maxCacheItems) { return true; } else if (this.purgingMode == PurgingMode.AccessBasedPurge && DateTime.UtcNow > this.nextPurgeTimeUtc && this.Count > this.lowWaterMark) { return true; } else { return false; } } void PurgeIfNeeded() { if (!(this.cacheLock.IsWriterLockHeld == true)) { // we failfast here because if we don't have the lock we could corrupt the cache DiagnosticUtility.DebugAssert("Cache write lock is not held."); DiagnosticUtility.FailFast("Cache write lock is not held."); } if (ShouldPurge()) { PurgeStaleItems(); } } ////// This method must be called from within a writer lock /// void PurgeStaleItems() { if (!(this.cacheLock.IsWriterLockHeld == true)) { // we failfast here because if we don't have the lock we could corrupt the cache DiagnosticUtility.DebugAssert("Cache write lock is not held."); DiagnosticUtility.FailFast("Cache write lock is not held."); } ArrayList expiredItems = new ArrayList(); foreach (object key in this.entries.Keys) { IExpirableItem item = this.entries[key] as IExpirableItem; if (IsExpired(item)) { // this is a stale item. Remove! this.OnRemove(ExtractItem(item)); expiredItems.Add(key); } } for (int i = 0; i < expiredItems.Count; ++i) { this.entries.Remove(expiredItems[i]); } CancelTimerIfNeeded(); this.nextPurgeTimeUtc = DateTime.UtcNow.Add(this.purgeInterval); } void ThrowQuotaReachedException() { string message = SR.GetString(SR.CacheQuotaReached, this.maxCacheItems); Exception inner = new QuotaExceededException(message); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner)); } static void PurgeCallbackStatic(object state) { TimeBoundedCache self = (TimeBoundedCache)state; bool lockHeld = false; try { try { } finally { self.cacheLock.AcquireWriterLock(-1); lockHeld = true; } if (self.purgingTimer == null) { return; } self.PurgeStaleItems(); if (self.Count > 0 && self.purgingTimer != null) { self.purgingTimer.Set(self.purgeInterval); } } finally { if (lockHeld) { self.cacheLock.ReleaseWriterLock(); } } } internal interface IExpirableItem { DateTime ExpirationTime { get; } } internal class ExpirableItemComparer : IComparer{ static ExpirableItemComparer instance; public static ExpirableItemComparer Default { get { if (instance == null) { instance = new ExpirableItemComparer(); } return instance; } } // positive, if item1 will expire before item2. public int Compare(IExpirableItem item1, IExpirableItem item2) { if (ReferenceEquals(item1, item2)) { return 0; } DiagnosticUtility.DebugAssert(item1.ExpirationTime.Kind == item2.ExpirationTime.Kind, ""); if (item1.ExpirationTime < item2.ExpirationTime) { return 1; } else if (item1.ExpirationTime > item2.ExpirationTime) { return -1; } else { return 0; } } } internal sealed class ExpirableItem : IExpirableItem { DateTime expirationTime; object item; public ExpirableItem(object item, DateTime expirationTime) { this.item = item; DiagnosticUtility.DebugAssert( expirationTime == DateTime.MaxValue || expirationTime.Kind == DateTimeKind.Utc, ""); this.expirationTime = expirationTime; } public DateTime ExpirationTime { get { return this.expirationTime; } } public object Item { get { return this.item; } } } } enum PurgingMode { TimerBasedPurge, AccessBasedPurge } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ProvidersHelper.cs
- MissingSatelliteAssemblyException.cs
- TrackingProfile.cs
- DeviceContexts.cs
- ProviderSettingsCollection.cs
- ListBindingHelper.cs
- TemplatedAdorner.cs
- SQLGuidStorage.cs
- MatrixCamera.cs
- MenuAutoFormat.cs
- DesignerActionGlyph.cs
- DesignerTransactionCloseEvent.cs
- TreeNode.cs
- Expression.cs
- CursorConverter.cs
- InvariantComparer.cs
- SqlTypeSystemProvider.cs
- TypedOperationInfo.cs
- ProvidePropertyAttribute.cs
- WasAdminWrapper.cs
- TextServicesProperty.cs
- Crypto.cs
- Tag.cs
- DrawTreeNodeEventArgs.cs
- CommonProperties.cs
- _StreamFramer.cs
- ValidatorUtils.cs
- NameValueSectionHandler.cs
- ProcessInputEventArgs.cs
- TransformerInfo.cs
- UserControlParser.cs
- TransactionState.cs
- SQLGuid.cs
- XmlSchemaSimpleTypeList.cs
- TraceLog.cs
- HashMembershipCondition.cs
- ProgressBarRenderer.cs
- RoleBoolean.cs
- MultiDataTrigger.cs
- HttpWriter.cs
- PolicyManager.cs
- _CookieModule.cs
- WindowsFont.cs
- ServerValidateEventArgs.cs
- WindowsTab.cs
- TextEndOfLine.cs
- IgnoreFlushAndCloseStream.cs
- RtfControls.cs
- Simplifier.cs
- TypeAccessException.cs
- ObjectStorage.cs
- StoreContentChangedEventArgs.cs
- ApplicationHost.cs
- X509ServiceCertificateAuthenticationElement.cs
- QueryOpeningEnumerator.cs
- DataGridViewBand.cs
- RangeBaseAutomationPeer.cs
- PersonalizationAdministration.cs
- NativeMethods.cs
- XmlDataImplementation.cs
- DropShadowBitmapEffect.cs
- HttpListenerPrefixCollection.cs
- Point3DCollectionConverter.cs
- SectionVisual.cs
- ViewLoader.cs
- ValidationUtility.cs
- LineVisual.cs
- SubMenuStyleCollection.cs
- WebPartEditVerb.cs
- PathStreamGeometryContext.cs
- OptionalColumn.cs
- SafeRegistryKey.cs
- StrokeIntersection.cs
- SqlCacheDependency.cs
- KeyboardEventArgs.cs
- CacheEntry.cs
- __ConsoleStream.cs
- XmlWriterSettings.cs
- EtwProvider.cs
- SerializationInfo.cs
- Pair.cs
- ListChangedEventArgs.cs
- Row.cs
- Inline.cs
- FilterEventArgs.cs
- SerialErrors.cs
- RequestCache.cs
- CrossAppDomainChannel.cs
- ColorConvertedBitmap.cs
- pingexception.cs
- DataRecordObjectView.cs
- ReaderWriterLock.cs
- Rijndael.cs
- PageEventArgs.cs
- EntityContainerEntitySet.cs
- ControlAdapter.cs
- CompilerParameters.cs
- PrintDialog.cs
- ControlAdapter.cs
- IntersectQueryOperator.cs