Ejemplo n.º 1
0
        // Calling thread need to be first take writelock
        private bool SetInternal(string key, DiskCacheEntry diskEntry)
        {
            if (_inUse.ContainsKey(key))
            {
                return(false);
            }

            if (_lruCache.ContainsKey(key))
            {
                return(false);
            }
            Volatile.Write(ref diskEntry.InCache, true);

            diskEntry.Ref(); // for the LRU cache's reference.
            if (diskEntry.Refs == 1)
            {
                _lruCache.Add(key, diskEntry);
            }
            else if (diskEntry.Refs > 1)
            {
                _inUse.TryAdd(key, diskEntry);
            }
            Debug.Assert(diskEntry.Refs > 0, "disk entry should have at least 1 reference");

            return(true);
        }
Ejemplo n.º 2
0
        public async Task <ICacheEntry> GetOrAddAsync(string key, Func <string, Stream, ICacheControl, Task> valueFactory, ICacheControl cacheControl, CancellationToken ct)
        {
            using (await _rwLock.ReadLockAsync())
            {
                ICacheEntry found = GetInternal(key);
                if (!(found is EmptyCacheEntry))
                {
                    found.Ref(); // this entry remain valid after releasing the lock
                    return(found);
                }
            }

            using (await _rwLock.WriteLockAsync())
            {
                ICacheEntry found = GetInternal(key);
                if (!(found is EmptyCacheEntry))
                {
                    found.Ref(); // this entry remain valid after releasing the lock
                    return(found);
                }

                var randomPath = await _fs.WriteAtomicAsync((sink, cancel) => valueFactory(key, sink, cacheControl), _cacheTmpPath, ct).ConfigureAwait(false);

                var tmpEntry = new DiskCacheEntry(key, randomPath, this);
                if (!cacheControl.NoStore)
                {
                    SetInternal(key, tmpEntry);
                }

                var entry = GetInternal(key);
                entry.Ref();
                return(entry);
            }
        }
Ejemplo n.º 3
0
        internal void DeleteEntry(DiskCacheEntry diskCacheEntry)
        {
            var refs = diskCacheEntry.Refs;

            Debug.Assert(refs == 0, "disk entry should have 0 reference");
            _fs.FileDelete(diskCacheEntry.EntryPath, _cacheTmpPath);
            diskCacheEntry.EntryPath = "";
        }
Ejemplo n.º 4
0
 void FinishErase(string key, DiskCacheEntry entry)
 {
     if (entry != null)
     {
         Volatile.Write(ref entry.InCache, false);
         entry.DisposeAsync().Wait(); // not inside LRU cache anymore
     }
 }
Ejemplo n.º 5
0
        public async Task ReleaseAsync(DiskCacheEntry entry)
        {
            int refCount;

            // If InCache == false this is called from FinishErase with _lock already held and cause deadlock
            if (Volatile.Read(ref entry.InCache))
            {
                using (await _rwLock.WriteLockAsync())
                {
                    // entry is in "_inUse" and refcount is between 1 .. N
                    // Call Unref inside the lock to avoid other thread incrementing concurrently
                    refCount = entry.Unref();
                    if (refCount == 1)
                    {
                        // Entry is still in cache but no longer in use.
                        if (_inUse.TryRemove(entry.Key, out _))
                        {
                            _lruCache.Add(entry.Key, entry);
                        }
                    }
                    if (refCount <= 0)
                    {
                        _inUse.TryRemove(entry.Key, out _);
                        entry.Delete();
                        return;
                    }
                }
            }
            else
            {
                // its safe to decrment unref because Entry is not in cache anymore and refcount can only decrease now
                if (entry.Refs > 0)
                {
                    refCount = entry.Unref();
                    if (refCount == 0)
                    {
                        _inUse.TryRemove(entry.Key, out _);
                        entry.Delete();
                        return;
                    }
                }
            }
        }
Ejemplo n.º 6
0
 internal Stream ReadEntry(DiskCacheEntry diskCacheEntry)
 {
     Debug.Assert(diskCacheEntry.Refs > 0, "disk entry should have at least 1 reference");
     Debug.Assert(diskCacheEntry.EntryPath != "", "disk entry have been deleted");
     return(_fs.FileOpenRead(diskCacheEntry.EntryPath));
 }