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
- ParenExpr.cs
- BuildManager.cs
- OleDbErrorCollection.cs
- StringConcat.cs
- CreateParams.cs
- InternalsVisibleToAttribute.cs
- KeyGestureConverter.cs
- CharStorage.cs
- Pen.cs
- SponsorHelper.cs
- SoapSchemaMember.cs
- PolyBezierSegment.cs
- StandardBindingCollectionElement.cs
- BaseDataListComponentEditor.cs
- TargetInvocationException.cs
- GridLength.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- _UncName.cs
- Page.cs
- Cursor.cs
- GZipStream.cs
- StreamGeometry.cs
- CollectionViewGroupRoot.cs
- XNodeValidator.cs
- QueryOperator.cs
- DataBoundControlHelper.cs
- TrackBarRenderer.cs
- SecurityTokenSerializer.cs
- TextRangeProviderWrapper.cs
- WinInetCache.cs
- CodeMemberMethod.cs
- Thumb.cs
- ReadOnlyHierarchicalDataSourceView.cs
- NullReferenceException.cs
- BadImageFormatException.cs
- SamlAdvice.cs
- ServiceDescriptions.cs
- PrivateUnsafeNativeCompoundFileMethods.cs
- CryptoApi.cs
- DoubleUtil.cs
- Polygon.cs
- DataListItemCollection.cs
- WindowsSysHeader.cs
- CompatibleIComparer.cs
- PreviewKeyDownEventArgs.cs
- DelayLoadType.cs
- FunctionImportMapping.ReturnTypeRenameMapping.cs
- D3DImage.cs
- WebPartEventArgs.cs
- TypeLoadException.cs
- DurableInstanceContextProvider.cs
- XmlIlVisitor.cs
- CheckBox.cs
- Receive.cs
- FixedTextSelectionProcessor.cs
- Tile.cs
- AdapterDictionary.cs
- XmlMapping.cs
- SettingsBase.cs
- HttpProcessUtility.cs
- DataContract.cs
- LinkClickEvent.cs
- TypedTableBase.cs
- SyntaxCheck.cs
- KoreanLunisolarCalendar.cs
- Pair.cs
- MetadataReference.cs
- WebPartUserCapability.cs
- TlsnegoTokenProvider.cs
- MarkupCompilePass2.cs
- TreeWalkHelper.cs
- UniqueEventHelper.cs
- HMAC.cs
- SchemaNames.cs
- Converter.cs
- FlowDocumentPaginator.cs
- FileSystemEventArgs.cs
- DateTimeUtil.cs
- SqlCaseSimplifier.cs
- HttpMethodAttribute.cs
- M3DUtil.cs
- HttpCookieCollection.cs
- Tokenizer.cs
- PrintingPermission.cs
- Converter.cs
- ProcessManager.cs
- FormViewCommandEventArgs.cs
- ObjectSecurityT.cs
- CachedFontFamily.cs
- SocketAddress.cs
- DrawListViewItemEventArgs.cs
- MergeLocalizationDirectives.cs
- VectorKeyFrameCollection.cs
- InputBindingCollection.cs
- MailDefinition.cs
- WebServiceClientProxyGenerator.cs
- BooleanAnimationUsingKeyFrames.cs
- SelectionRangeConverter.cs
- FontConverter.cs
- AppSecurityManager.cs