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
- DnsPermission.cs
- FormViewPagerRow.cs
- CodeObject.cs
- SimpleBitVector32.cs
- safesecurityhelperavalon.cs
- ControlBuilder.cs
- FixedNode.cs
- PersistChildrenAttribute.cs
- Wizard.cs
- LinkClickEvent.cs
- _SslState.cs
- ReferencedType.cs
- VariantWrapper.cs
- DebugView.cs
- Vector3DAnimationUsingKeyFrames.cs
- DateTimeSerializationSection.cs
- RunClient.cs
- Padding.cs
- RegionData.cs
- DependencyObjectType.cs
- ValidatorCompatibilityHelper.cs
- GridViewAutoFormat.cs
- TemporaryBitmapFile.cs
- DetailsViewModeEventArgs.cs
- TextTreeInsertUndoUnit.cs
- DataGridCell.cs
- BrowserCapabilitiesFactory.cs
- FormsAuthenticationModule.cs
- StorageBasedPackageProperties.cs
- CommonGetThemePartSize.cs
- AssemblyBuilder.cs
- EncoderBestFitFallback.cs
- ChtmlCommandAdapter.cs
- SplineQuaternionKeyFrame.cs
- SrgsText.cs
- ButtonField.cs
- TraceSection.cs
- ServicesExceptionNotHandledEventArgs.cs
- PackageDocument.cs
- DataGridViewIntLinkedList.cs
- DATA_BLOB.cs
- DropShadowEffect.cs
- XmlConverter.cs
- ContentType.cs
- HtmlShim.cs
- RemotingConfiguration.cs
- ModuleConfigurationInfo.cs
- IPipelineRuntime.cs
- DataGridViewCell.cs
- XmlSerializer.cs
- ListenerChannelContext.cs
- HttpContextServiceHost.cs
- InstanceDataCollection.cs
- ContainerParagraph.cs
- OrderByQueryOptionExpression.cs
- UiaCoreProviderApi.cs
- EDesignUtil.cs
- StringUtil.cs
- SqlTriggerContext.cs
- OraclePermission.cs
- ToolStripAdornerWindowService.cs
- RoutedEventValueSerializer.cs
- SqlDataSourceView.cs
- OdbcEnvironment.cs
- XpsPartBase.cs
- Point.cs
- ObjectParameter.cs
- OdbcCommand.cs
- DoubleLink.cs
- InstanceKey.cs
- ProjectedSlot.cs
- ToolStripStatusLabel.cs
- HwndStylusInputProvider.cs
- XmlExceptionHelper.cs
- SymbolMethod.cs
- PropertyTab.cs
- WindowsNonControl.cs
- CatalogPartCollection.cs
- EntityEntry.cs
- ToolStripItemEventArgs.cs
- HostingEnvironmentException.cs
- ReachVisualSerializerAsync.cs
- PropertyMetadata.cs
- EventMappingSettings.cs
- Separator.cs
- CredentialCache.cs
- BridgeDataRecord.cs
- TrustLevelCollection.cs
- TransactionFlowElement.cs
- CryptoApi.cs
- Operand.cs
- DataGridViewMethods.cs
- GenericTextProperties.cs
- DataStreams.cs
- KeyValuePair.cs
- SQLMembershipProvider.cs
- DocobjHost.cs
- HtmlSelect.cs
- HttpModuleCollection.cs
- ThemeDictionaryExtension.cs