コード例 #1
0
        /// <summary>
        /// Gets a dynamic view of the underlying cache based on the parameters given.
        /// </summary>
        /// <param name="mode">View mode.</param>
        /// <param name="startKey">Start key of view.</param>
        /// <param name="endKey">End key of view.</param>
        /// <param name="tailCount">Number of items to include in view.</param>
        /// <param name="tailRange">Tail duration function. Takes last item's key and returns a new startKey.</param>
        /// <returns>An instance of <see cref="ObservableKeyedView"/>.</returns>
        /// <exception cref="ArgumentException"><paramref name="startKey"/> must be less than or equal to <paramref name="endKey"/>.</exception>
        public ObservableKeyedView GetView(ObservableKeyedView.ViewMode mode, TKey startKey, TKey endKey, uint tailCount, Func <TKey, TKey> tailRange)
        {
            if (this.keyComparer.Compare(startKey, endKey) > 0)
            {
                throw new ArgumentException($"startKey ({startKey}) must be less than or equal to endKey ({endKey}).");
            }

            var viewKey = Tuple.Create(startKey, endKey, tailCount, tailRange);
            WeakReference <ObservableKeyedView> weakView = null;
            ObservableKeyedView view = null;

            if (this.views.TryGetValue(viewKey, out weakView))
            {
                if (weakView.TryGetTarget(out view))
                {
                    return(view);
                }
                else
                {
                    view = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                    weakView.SetTarget(view);
                }
            }
            else
            {
                view     = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                weakView = new WeakReference <ObservableKeyedView>(view);
                this.views.Add(viewKey, weakView);
            }

            return(view);
        }
コード例 #2
0
        /// <summary>
        /// Gets a dynamic view of the underlying cache based on the parameters given.
        /// </summary>
        /// <param name="mode">View mode.</param>
        /// <param name="startKey">Start key of view.</param>
        /// <param name="endKey">End key of view.</param>
        /// <param name="tailCount">Number of items to include in view.</param>
        /// <param name="tailRange">Tail duration function. Takes last item's key and returns a new startKey.</param>
        /// <returns>An instance of <see cref="ObservableKeyedView"/>.</returns>
        /// <exception cref="ArgumentException"><paramref name="startKey"/> must be less than or equal to <paramref name="endKey"/>.</exception>
        public ObservableKeyedView GetView(ObservableKeyedView.ViewMode mode, TKey startKey, TKey endKey, uint tailCount, Func <TKey, TKey> tailRange)
        {
            if (this.keyComparer.Compare(startKey, endKey) > 0)
            {
                throw new ArgumentException($"startKey ({startKey}) must be less than or equal to endKey ({endKey}).");
            }

            var viewKey = Tuple.Create(startKey, endKey, tailCount, tailRange);
            WeakReference <ObservableKeyedView> weakView = null;
            ObservableKeyedView view = null;

            if (this.views.TryGetValue(viewKey, out weakView))
            {
                if (weakView.TryGetTarget(out view))
                {
                    return(view);
                }
                else
                {
                    view = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                    weakView.SetTarget(view);

                    // Sometimes the weak view gets deleted between when we grab it to check
                    // if it has a hard reference and when we actually set the new hard reference
                    // that we just created.  If that happens, then the following code makes sure
                    // the weak view gets put back into the collection.
                    this.views[viewKey] = weakView;
                }
            }
            else
            {
                view     = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                weakView = new WeakReference <ObservableKeyedView>(view);
                this.views.Add(viewKey, weakView);
            }

            return(view);
        }
コード例 #3
0
 public Enumerator(ObservableKeyedView view)
 {
     this.view  = view;
     this.index = 0;
     this.value = default(TItem);
 }
コード例 #4
0
        /// <summary>
        /// Walks views and prunes out dead (GC'd) views and the resulting unreferenced data.
        /// </summary>
        private void PruneCache()
        {
            // More than one call to PruneCache can be queued. Only process the first one.
            if (!this.needsPruning)
            {
                return;
            }

            this.needsPruning = false;

            // track whether we did any pruning to adjust our threshold
            bool didPrune = false;

            // find dead views
            ObservableKeyedView view = null;
            var deadViews            = this.views.Where(v => !v.Value.TryGetTarget(out view));

            // remove dead views from views collection
            foreach (var deadView in deadViews.ToList())
            {
                this.views.Remove(deadView.Key);
            }

            // remove cached items that are no longer referenced by a view
            var liveViews  = this.views.OrderBy(lv => lv.Key.Item1, this.keyComparer).ThenBy(lv => lv.Key.Item2, this.keyComparer);
            int startIndex = 0;

            foreach (var liveView in liveViews)
            {
                // find exclusive endIndex of range to be removed
                int endIndex = startIndex;
                while (this.Count > endIndex && this.keyComparer.Compare(this.getKeyForItem(this[endIndex]), liveView.Key.Item1) < 0)
                {
                    endIndex++;
                }

                // remove items preceding current live view
                if (endIndex > startIndex)
                {
                    this.RemoveRange(startIndex, endIndex - startIndex);
                    didPrune = true;
                }

                // advance startIndex to end of current live view
                while (this.Count > startIndex && this.keyComparer.Compare(this.getKeyForItem(this[startIndex]), liveView.Key.Item2) < 0)
                {
                    startIndex++;
                }
            }

            // remove items after last live view
            if (startIndex == 0)
            {
                // no live view that contains any data - clear all
                this.Clear();
                didPrune = true;
            }
            else
            {
                // at least one live view that contains data - remove to the end
                if (this.Count > startIndex)
                {
                    this.RemoveRange(startIndex, this.Count - startIndex);
                    didPrune = true;
                }
            }

            // adjust pruning threshold
            this.pruneThreshold = didPrune ?
                                  Math.Max(this.pruneThreshold >> 1, ObservableSortedCollection <TItem> .DefaultCapacity >> 2) :
                                  Math.Min(this.pruneThreshold << 1, ObservableSortedCollection <TItem> .DefaultCapacity << 2);
        }