| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- //
- // System.Web.Caching.CacheItem
- //
- // Author(s):
- // Marek Habersack <[email protected]>
- //
- // (C) 2009 Novell, Inc (http://novell.com)
- //
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Text;
- using System.Threading;
- namespace System.Web.Caching
- {
- sealed class CacheItemPriorityQueue
- {
- sealed class Node
- {
- public CacheItem Data;
-
- public Node Left;
- public Node Right;
- public Node Parent;
- public Node Next;
- public Node Prev;
- public CacheItem SwapData (CacheItem newData)
- {
- CacheItem ret = Data;
- Data = newData;
-
- return ret;
- }
- public Node (CacheItem data)
- {
- Data = data;
- }
- }
-
- Node root;
- Node lastAdded;
- Node firstParent;
- Node lastParent;
- #if SYSTEMCORE_DEP
- ReaderWriterLockSlim queueLock;
- #endif
- public CacheItemPriorityQueue ()
- {
- #if SYSTEMCORE_DEP
- queueLock = new ReaderWriterLockSlim ();
- #endif
- }
-
- public void Enqueue (CacheItem item)
- {
- if (item == null)
- return;
- #if SYSTEMCORE_DEP
- bool locked = false;
- try {
- queueLock.EnterWriteLock ();
- locked = true;
- #endif
- Node node = new Node (item);
- if (root == null) {
- root = lastAdded = lastParent = firstParent = node;
- return;
- }
- if (lastParent.Left != null && lastParent.Right != null) {
- lastParent = lastParent.Next;
- if (lastParent == null) {
- lastParent = firstParent = firstParent.Left;
- lastAdded = null;
- }
- }
- node.Parent = lastParent;
- if (lastParent.Left == null)
- lastParent.Left = node;
- else
- lastParent.Right = node;
- if (lastAdded != null) {
- lastAdded.Next = node;
- node.Prev = lastAdded;
- }
-
- lastAdded = node;
- BubbleUp (node);
- #if SYSTEMCORE_DEP
- } finally {
- if (locked)
- queueLock.ExitWriteLock ();
- }
- #endif
- }
- public CacheItem Dequeue ()
- {
- CacheItem ret = null;
- #if SYSTEMCORE_DEP
- bool locked = false;
- try {
- queueLock.EnterWriteLock ();
- locked = true;
- #endif
- if (root == null)
- return null;
-
- if (root.Left == null && root.Right == null) {
- ret = root.Data;
- root = null;
- if (ret.Disabled)
- return null;
-
- return ret;
- }
- ret = root.Data;
- do {
- Node last = lastAdded;
- if (last == null)
- return null;
-
- if (last.Prev == null) {
- Node parent = last.Parent;
- while (true) {
- if (parent.Next == null)
- break;
- parent = parent.Next;
- }
- lastAdded = parent;
- } else {
- lastAdded = last.Prev;
- lastAdded.Next = null;
- }
- if (last.Parent.Left == last)
- last.Parent.Left = null;
- else
- last.Parent.Right = null;
-
- root.Data = last.Data;
- BubbleDown (root);
- } while (ret.Disabled);
- #if SYSTEMCORE_DEP
- } finally {
- if (locked)
- queueLock.ExitWriteLock ();
- }
- #endif
- return ret;
- }
- public CacheItem Peek ()
- {
- #if SYSTEMCORE_DEP
- bool locked = false;
- try {
- queueLock.EnterReadLock ();
- locked = true;
- #endif
- if (root == null)
- return null;
- #if SYSTEMCORE_DEP
- } finally {
- if (locked)
- queueLock.ExitReadLock ();
- }
- #endif
- return root.Data;
- }
-
- void BubbleDown (Node item)
- {
- if (item == null || (item.Left == null && item.Right == null))
- return;
- if (item.Left == null)
- SwapBubbleDown (item, item.Right);
- else if (item.Right == null)
- SwapBubbleDown (item, item.Left);
- else {
- if (item.Left.Data.ExpiresAt < item.Right.Data.ExpiresAt)
- SwapBubbleDown (item, item.Left);
- else
- SwapBubbleDown (item, item.Right);
- }
- }
- void SwapBubbleDown (Node item, Node otherItem)
- {
- if (otherItem.Data.ExpiresAt < item.Data.ExpiresAt) {
- item.Data = otherItem.SwapData (item.Data);
- BubbleDown (otherItem);
- }
- }
-
- void BubbleUp (Node item)
- {
- if (item == null || item.Data == null)
- return;
-
- Node parent = item.Parent;
- if (parent == null)
- return;
-
- if (item.Data.ExpiresAt > parent.Data.ExpiresAt)
- return;
- item.Data = parent.SwapData (item.Data);
-
- BubbleUp (parent);
- }
-
- public string GetDotScript ()
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append ("graph CacheItemPriorityQueue {\n");
- sb.Append ("\tnode [color=lightblue, style=filled];\n");
- if (root != null) {
- if (root.Left == null && root.Right == null)
- sb.AppendFormat ("\t{0};", root.Data.ExpiresAt);
- else
- TraverseTree (sb, root);
- }
- sb.Append ("}\n");
- return sb.ToString ();
- }
- void TraverseTree (StringBuilder sb, Node root)
- {
- if (root.Left != null) {
- sb.AppendFormat ("\t{0} -- {1};\n", root.Data.ExpiresAt, root.Left.Data.ExpiresAt);
- TraverseTree (sb, root.Left);
- }
- if (root.Right != null) {
- sb.AppendFormat ("\t{0} -- {1};\n", root.Data.ExpiresAt, root.Right.Data.ExpiresAt);
- TraverseTree (sb, root.Right);
- }
- }
- }
- }
|