예제 #1
0
 /// <summary>Clear all entries related to a single file.</summary>
 /// <remarks>
 /// Clear all entries related to a single file.
 /// <p>
 /// Typically this method is invoked during
 /// <see cref="PackFile.Close()">PackFile.Close()</see>
 /// , when we
 /// know the pack is never going to be useful to us again (for example, it no
 /// longer exists on disk). A concurrent reader loading an entry from this
 /// same pack may cause the pack to become stuck in the cache anyway.
 /// </remarks>
 /// <param name="pack">the file to purge all entries of.</param>
 private void RemoveAll(PackFile pack)
 {
     for (int s = 0; s < tableSize; s++)
     {
         WindowCache.Entry e1 = table.Get(s);
         bool hasDead         = false;
         for (WindowCache.Entry e = e1; e != null; e = e.next)
         {
             if ([email protected] == pack)
             {
                 e.Kill();
                 hasDead = true;
             }
             else
             {
                 if (e.dead)
                 {
                     hasDead = true;
                 }
             }
         }
         if (hasDead)
         {
             table.CompareAndSet(s, e1, Clean(e1));
         }
     }
     Gc();
 }
예제 #2
0
 private void Evict()
 {
     while (IsFull())
     {
         int ptr = rng.Next(tableSize);
         WindowCache.Entry old = null;
         int slot = 0;
         for (int b = evictBatch - 1; b >= 0; b--, ptr++)
         {
             if (tableSize <= ptr)
             {
                 ptr = 0;
             }
             for (WindowCache.Entry e = table.Get(ptr); e != null; e = e.next)
             {
                 if (e.dead)
                 {
                     continue;
                 }
                 if (old == null || [email protected] < [email protected])
                 {
                     old  = e;
                     slot = ptr;
                 }
             }
         }
         if (old != null)
         {
             old.Kill();
             Gc();
             WindowCache.Entry e1 = table.Get(slot);
             table.CompareAndSet(slot, e1, Clean(e1));
         }
     }
 }
예제 #3
0
 private static WindowCache.Entry Clean(WindowCache.Entry top)
 {
     while (top != null && top.dead)
     {
         [email protected]();
         top = top.next;
     }
     if (top == null)
     {
         return(null);
     }
     WindowCache.Entry n = Clean(top.next);
     return(n == top.next ? top : new WindowCache.Entry(n, top.@ref));
 }
예제 #4
0
        /// <summary>Lookup a cached object, creating and loading it if it doesn't exist.</summary>
        /// <remarks>Lookup a cached object, creating and loading it if it doesn't exist.</remarks>
        /// <param name="pack">the pack that "contains" the cached object.</param>
        /// <param name="position">offset within <code>pack</code> of the object.</param>
        /// <returns>the object reference.</returns>
        /// <exception cref="System.IO.IOException">
        /// the object reference was not in the cache and could not be
        /// obtained by
        /// <see cref="Load(PackFile, long)">Load(PackFile, long)</see>
        /// .
        /// </exception>
        private ByteWindow GetOrLoad(PackFile pack, long position)
        {
            int slot = Slot(pack, position);

            WindowCache.Entry e1 = table.Get(slot);
            ByteWindow        v  = Scan(e1, pack, position);

            if (v != null)
            {
                return(v);
            }
            lock (LockCache(pack, position))
            {
                WindowCache.Entry e2 = table.Get(slot);
                if (e2 != e1)
                {
                    v = Scan(e2, pack, position);
                    if (v != null)
                    {
                        return(v);
                    }
                }
                v = Load(pack, position);
                WindowCache.Ref @ref = CreateRef(pack, position, v);
                Hit(@ref);
                for (; ;)
                {
                    WindowCache.Entry n = new WindowCache.Entry(Clean(e2), @ref);
                    if (table.CompareAndSet(slot, e2, n))
                    {
                        break;
                    }
                    e2 = table.Get(slot);
                }
            }
            if (evictLock.TryLock())
            {
                try
                {
                    Gc();
                    Evict();
                }
                finally
                {
                    evictLock.Unlock();
                }
            }
            return(v);
        }
예제 #5
0
 /// <summary>Clear every entry from the cache.</summary>
 /// <remarks>
 /// Clear every entry from the cache.
 /// <p>
 /// This is a last-ditch effort to clear out the cache, such as before it
 /// gets replaced by another cache that is configured differently. This
 /// method tries to force every cached entry through
 /// <see cref="Clear(Ref)">Clear(Ref)</see>
 /// to
 /// ensure that resources are correctly accounted for and cleaned up by the
 /// subclass. A concurrent reader loading entries while this method is
 /// running may cause resource accounting failures.
 /// </remarks>
 private void RemoveAll()
 {
     for (int s = 0; s < tableSize; s++)
     {
         WindowCache.Entry e1;
         do
         {
             e1 = table.Get(s);
             for (WindowCache.Entry e = e1; e != null; e = e.next)
             {
                 e.Kill();
             }
         }while (!table.CompareAndSet(s, e1, null));
     }
     Gc();
 }
예제 #6
0
 private ByteWindow Scan(WindowCache.Entry n, PackFile pack, long position)
 {
     for (; n != null; n = n.next)
     {
         WindowCache.Ref r = n.@ref;
         if (r.pack == pack && r.position == position)
         {
             ByteWindow v = r.Get();
             if (v != null)
             {
                 Hit(r);
                 return(v);
             }
             n.Kill();
             break;
         }
     }
     return(null);
 }
예제 #7
0
 private void Gc()
 {
     WindowCache.Ref r;
     while ((r = (WindowCache.Ref)queue.Poll()) != null)
     {
         // Sun's Java 5 and 6 implementation have a bug where a Reference
         // can be enqueued and dequeued twice on the same reference queue
         // due to a race condition within ReferenceQueue.enqueue(Reference).
         //
         // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6837858
         //
         // We CANNOT permit a Reference to come through us twice, as it will
         // skew the resource counters we maintain. Our canClear() check here
         // provides a way to skip the redundant dequeues, if any.
         //
         if (r.CanClear())
         {
             Clear(r);
             bool found           = false;
             int  s               = Slot(r.pack, r.position);
             WindowCache.Entry e1 = table.Get(s);
             for (WindowCache.Entry n = e1; n != null; n = n.next)
             {
                 if (n.@ref == r)
                 {
                     n.dead = true;
                     found  = true;
                     break;
                 }
             }
             if (found)
             {
                 table.CompareAndSet(s, e1, Clean(e1));
             }
         }
     }
 }
예제 #8
0
 internal Entry(WindowCache.Entry n, WindowCache.Ref r)
 {
     next = n;
     @ref = r;
 }