public async void TestActiveLockCount()
        {
            var provider = new AsyncLockProvider();
            var task     = provider.TryExecuteAsync("1", 1500, CancellationToken.None, async() =>
            {
                await Task.Delay(50);
            });
            var task2 = provider.TryExecuteAsync("2", 1500, CancellationToken.None, async() =>
            {
                await Task.Delay(50);
            });
            var task2B = provider.TryExecuteAsync("2", 1500, CancellationToken.None, async() =>
            {
                await Task.Delay(50);
            });
            var task3 = provider.TryExecuteAsync("3", 1500, CancellationToken.None, async() =>
            {
                await Task.Delay(50);
                throw new Exception();
            });

            Assert.Equal(3, provider.GetActiveLockCount());
            await task;
            await task2;
            await task2B;
            await Assert.ThrowsAsync <Exception>(async() => await task3);

            Assert.Equal(0, provider.GetActiveLockCount());
        }
Пример #2
0
        public Task ProcessAsync(HttpContext current, IAsyncResponsePlan e)
        {
            //Use alternate cache key if provided
            string key = e.RequestCachingKey;

            //If cached, serve it.
            var c = cache.Get(key);

            if (c != null)
            {
                Serve(current, e, c);
                return(Task.FromResult(0));
            }
            //If not, let's cache it.
            return(asyncLocks.TryExecuteAsync(key, 3000, async delegate()
            {
                c = cache.Get(key);
                if (c == null)
                {
                    using (var data = new MemoryStream(4096))
                    {
                        await e.CreateAndWriteResultAsync(data, e);//Very long-running call
                        c = new MemCacheResult(data.CopyToBytes(true));
                    }
                    cache.Set(key, c);//Save to cache (may trigger cleanup)
                }
                Serve(current, e, c);
                return;
            }));
        }
Пример #3
0
        public async Task <IVirtualFileAsync> GetFileIfCachedAsync(string virtualPath, NameValueCollection queryString, IVirtualFileAsync original)
        {
            //Use alternate cache key if provided
            string key = original is IVirtualFileSourceCacheKey ? ((IVirtualFileSourceCacheKey)original).GetCacheKey(true) : original.VirtualPath;
            //If cached, serve it.
            CachedVirtualFile c = cache.Get(key);

            if (c != null)
            {
                return(c);
            }
            //If not, let's cache it.
            if ("mem".Equals(queryString["scache"], StringComparison.OrdinalIgnoreCase))
            {
                await asyncLocks.TryExecuteAsync(key, 3000, async delegate()
                {
                    c = cache.Get(key);
                    if (c == null)
                    {
                        using (Stream data = await original.OpenAsync())
                        {//Very long-running call
                            c = new CachedVirtualFile(original.VirtualPath, await data.CopyToBytesAsync(true, 0x1000));
                        }
                        cache.Set(key, c);//Save to cache (may trigger cleanup)
                    }
                });

                return(c);
            }
            return(null);
        }
Пример #4
0
        /// <summary>
        /// Skips the record if there is delete contention for a file.
        /// Only counts bytes as deleted if the physical file is deleted successfully.
        /// Deletes db record whether file exists or not.
        /// </summary>
        /// <param name="shard"></param>
        /// <param name="record"></param>
        /// <param name="writeLocks"></param>
        /// <returns></returns>
        private async Task <long> TryDeleteRecord(int shard, ICacheDatabaseRecord record, AsyncLockProvider writeLocks)
        {
            long bytesDeleted = 0;
            var  unused       = await writeLocks.TryExecuteAsync(record.RelativePath, 0, CancellationToken.None, async() =>
            {
                var physicalPath = PathBuilder.GetPhysicalPathFromRelativePath(record.RelativePath);
                try
                {
                    if (File.Exists(physicalPath))
                    {
                        File.Delete(physicalPath);
                        await Database.DeleteRecord(shard, record);
                        bytesDeleted = record.DiskSize;
                    }
                    else
                    {
                        await Database.DeleteRecord(shard, record);
                    }
                }
                catch (IOException ioException)
                {
                    if (physicalPath.Contains(".moving_"))
                    {
                        // We already moved it. All we can do is update the last deletion attempt
                        await Database.UpdateLastDeletionAttempt(shard, record.RelativePath, DateTime.UtcNow);
                        return;
                    }

                    var movedRelativePath = record.RelativePath + ".moving_" +
                                            new Random().Next(int.MaxValue).ToString("x", CultureInfo.InvariantCulture);
                    var movedPath = PathBuilder.GetPhysicalPathFromRelativePath(movedRelativePath);
                    try
                    {
                        //Move it so it usage will decrease and it can be deleted later
                        //TODO: This is not transactional, as the db record is written *after* the file is moved
                        //This should be split up into create and delete
                        (Options.MoveFileOverwriteFunc ?? File.Move)(physicalPath, movedPath);
                        await Database.ReplaceRelativePathAndUpdateLastDeletion(shard, record, movedRelativePath,
                                                                                DateTime.UtcNow);
                        Logger?.LogError(ioException, "HybridCache: Error deleting file, moved for eventual deletion - {Path}", record.RelativePath);
                    }
                    catch (IOException ioException2)
                    {
                        await Database.UpdateLastDeletionAttempt(shard, record.RelativePath, DateTime.UtcNow);
                        Logger?.LogError(ioException2, "HybridCache: Failed to move file for eventual deletion - {Path}", record.RelativePath);
                    }
                }
            });

            return(bytesDeleted);
        }
        public void TestConcurrency()
        {
            var provider    = new AsyncLockProvider();
            int sharedValue = 0;
            var tasks       = Enumerable.Range(0, 10).Select(async unused =>
                                                             Assert.True(await provider.TryExecuteAsync("1", 15000, CancellationToken.None, async() =>
            {
                var oldValue = sharedValue;
                sharedValue++;
                await Task.Delay(5);
                sharedValue = oldValue;
            }))).ToArray();

            Assert.True(provider.MayBeLocked("1"));
            Assert.Equal(1, provider.GetActiveLockCount());
            Task.WaitAll(tasks);
            Assert.Equal(0, sharedValue);
            Assert.Equal(0, provider.GetActiveLockCount());
        }