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
- MetadataUtilsSmi.cs
- WebPartConnectionsConnectVerb.cs
- StackBuilderSink.cs
- WebAdminConfigurationHelper.cs
- Barrier.cs
- TemplateBindingExtension.cs
- UIPropertyMetadata.cs
- ProviderSettingsCollection.cs
- MetadataItem.cs
- MultiPageTextView.cs
- Label.cs
- ModelPropertyCollectionImpl.cs
- UIServiceHelper.cs
- Semaphore.cs
- TextEmbeddedObject.cs
- ImageMapEventArgs.cs
- ListViewSortEventArgs.cs
- FrameAutomationPeer.cs
- WebHeaderCollection.cs
- PrintSystemException.cs
- smtppermission.cs
- SymbolType.cs
- MobileContainerDesigner.cs
- SchemaImporterExtension.cs
- BuildProviderCollection.cs
- _OSSOCK.cs
- Canvas.cs
- DiagnosticTrace.cs
- ViewPort3D.cs
- SmtpException.cs
- Context.cs
- ComponentChangedEvent.cs
- OdbcFactory.cs
- NullableLongMinMaxAggregationOperator.cs
- ProbeMatchesCD1.cs
- PagesSection.cs
- ReturnType.cs
- ReversePositionQuery.cs
- PrePostDescendentsWalker.cs
- figurelengthconverter.cs
- DataGridViewDataErrorEventArgs.cs
- PTUtility.cs
- EnumValidator.cs
- PrivilegedConfigurationManager.cs
- DataGridViewCell.cs
- HandleRef.cs
- parserscommon.cs
- QueryResponse.cs
- GenerateTemporaryTargetAssembly.cs
- SlotInfo.cs
- ProtocolsConfiguration.cs
- ViewStateModeByIdAttribute.cs
- XPathNavigator.cs
- StateManagedCollection.cs
- TileModeValidation.cs
- DispatcherEventArgs.cs
- ActivityMarkupSerializationProvider.cs
- SqlProcedureAttribute.cs
- SQLBytes.cs
- OleDbErrorCollection.cs
- WindowsTooltip.cs
- WindowsAuthenticationModule.cs
- JsonServiceDocumentSerializer.cs
- CompilerLocalReference.cs
- Formatter.cs
- ToolStripComboBox.cs
- CodeGotoStatement.cs
- PartialCachingAttribute.cs
- ConfigViewGenerator.cs
- Context.cs
- FullTextBreakpoint.cs
- HtmlInputRadioButton.cs
- UriTemplateTable.cs
- DataListCommandEventArgs.cs
- FixedSchema.cs
- WorkflowDesignerColors.cs
- SafePEFileHandle.cs
- DictionaryManager.cs
- PropertyRef.cs
- PageWrapper.cs
- TextDecoration.cs
- FixUpCollection.cs
- DataGridHeaderBorder.cs
- xamlnodes.cs
- TextServicesContext.cs
- SQLInt16Storage.cs
- InterleavedZipPartStream.cs
- ItemChangedEventArgs.cs
- sqlcontext.cs
- XslNumber.cs
- ManagedWndProcTracker.cs
- StoreContentChangedEventArgs.cs
- DataGridRelationshipRow.cs
- TypedDatasetGenerator.cs
- DispatcherHookEventArgs.cs
- PropertyGridCommands.cs
- ProfileBuildProvider.cs
- Terminate.cs
- PipelineModuleStepContainer.cs
- TreeViewAutomationPeer.cs