예제 #1
0
        public async Task ValidateInvalidation()
        {
            var maxCapacity   = 10;
            var clock         = new MemoryClock();
            var maxAgeMinutes = maxCapacity + 10; // No resources should expire.
            var pool          = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), new ResourcePoolConfiguration()
            {
                MaximumAge                 = TimeSpan.FromMinutes(maxAgeMinutes),
                MaximumResourceCount       = maxCapacity,
                EnableInstanceInvalidation = true,
            }, resourceFactory: _ => new Resource(), clock);

            using (var wrapper = await pool.CreateAsync(new Key(1)))
            {
                wrapper.Invalidate();
            }

            // We actually do the cleanup during the next operation
            using (var wrapper = await pool.CreateAsync(new Key(2)))
            {
            }

            Assert.Equal(1, pool.Counter[ResourcePoolCounters.Cleaned].Value);
            Assert.Equal(2, pool.Counter[ResourcePoolCounters.Created].Value);
        }
예제 #2
0
        public async Task NoContractExceptionsWhenCleaning()
        {
            var capacity = 2;
            var context  = new Context(TestGlobal.Logger);

            for (var i = 0; i < 100_000; i++)
            {
                var pool = new ResourcePool <Key, Resource>(context, maxResourceCount: capacity, maxAgeMinutes: 1, resourceFactory: _ => new Resource());

                for (var j = 0; j < capacity; j++)
                {
                    using var wrapper = await pool.CreateAsync(new Key (j));

                    var value = wrapper.Value;
                }

                var createTask = pool.CreateAsync(new Key(capacity));
                var accessTask = pool.CreateAsync(new Key(0));

                var results = await Task.WhenAll(createTask, accessTask);

                results[0].Dispose();
                results[1].Dispose();
            }
        }
예제 #3
0
        public async Task DuplicateClientsAreTheSameObject()
        {
            var capacity = 2;
            var context  = new Context(TestGlobal.Logger);
            var pool     = new ResourcePool <Key, Resource>(context, maxResourceCount: capacity, maxAgeMinutes: 1, resourceFactory: _ => new Resource());

            using var obj0 = await pool.CreateAsync(new Key (0));

            using var obj1 = await pool.CreateAsync(new Key (0));

            Assert.Same(obj0.Value, obj1.Value);
        }
예제 #4
0
        public async Task DuplicateClientsAreTheSameObject()
        {
            var capacity = 2;
            var context  = new Context(TestGlobal.Logger);
            var pool     = new ResourcePool <Key, Resource>(context, new ResourcePoolConfiguration()
            {
                MaximumResourceCount = capacity,
                MaximumAge           = TimeSpan.FromMinutes(1),
            }, resourceFactory: _ => new Resource());

            using var obj0 = await pool.CreateAsync(new Key (0));

            using var obj1 = await pool.CreateAsync(new Key (0));

            Assert.Same(obj0.Value, obj1.Value);
        }
예제 #5
0
        public async Task IssueSameClientManyTimes()
        {
            var clock = new MemoryClock();
            var pool  = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), maxResourceCount: 1, maxAgeMinutes: 1, resourceFactory: _ => new Resource(), clock);
            var key   = new Key(1);

            using var originalWrapper = await pool.CreateAsync(key);

            var originalResource = originalWrapper.Value;

            for (var i = 0; i < 1000; i++)
            {
                using var newWrapper = await pool.CreateAsync(key);

                Assert.Same(newWrapper.Value, originalResource);
            }
        }
예제 #6
0
        public async Task ValidateSingleCleanup()
        {
            var maxCapacity   = 10;
            var clock         = new MemoryClock();
            var maxAgeMinutes = maxCapacity + 10; // No resources should expire.
            var pool          = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), new ResourcePoolConfiguration()
            {
                MaximumResourceCount = maxCapacity,
                MaximumAge           = TimeSpan.FromMinutes(maxAgeMinutes),
            }, resourceFactory: _ => new Resource(), clock);

            var resources = new List <Resource>();

            foreach (var num in Enumerable.Range(1, maxCapacity))
            {
                var key = new Key(num);
                using var wrapper = await pool.CreateAsync(key);

                resources.Add((wrapper.Value));
                clock.UtcNow += TimeSpan.FromMinutes(1); // First resource will be the oldest.
            }

            Assert.Equal(0, pool.Counter[ResourcePoolCounters.Cleaned].Value);
            Assert.Equal(maxCapacity, pool.Counter[ResourcePoolCounters.Created].Value);

            using (var wrapper = await pool.CreateAsync(new Key(maxCapacity + 1)))
            {
                resources.Add((wrapper.Value));
            }

            // We actually do the cleanup during the next operation
            using (var wrapper = await pool.CreateAsync(new Key(maxCapacity)))
            {
            }

            Assert.Equal(1, pool.Counter[ResourcePoolCounters.Cleaned].Value);
            Assert.Equal(maxCapacity + 1, pool.Counter[ResourcePoolCounters.Created].Value);

            foreach (var client in resources.Skip(1))
            {
                Assert.False(client.ShutdownStarted);
            }

            Assert.True(resources.First().ShutdownCompleted);
        }
예제 #7
0
        public async Task ValidateCleanupOfExpired()
        {
            var resourceCount = 10;
            var clock         = new MemoryClock();
            var maxAgeMinutes = 1;
            var pool          = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), new ResourcePoolConfiguration()
            {
                MaximumResourceCount = resourceCount,
                MaximumAge           = TimeSpan.FromMinutes(maxAgeMinutes),
            }, resourceFactory: _ => new Resource(), clock);

            var wrappers = new List <ResourceWrapper <Resource> >();

            for (var i = 0; i < resourceCount; i++)
            {
                using var wrapper = await pool.CreateAsync(new Key (i));

                Assert.True(wrapper.Value.StartupStarted);
                wrappers.Add(wrapper);
            }

            // Expire the resources
            clock.UtcNow += TimeSpan.FromMinutes(maxAgeMinutes);

            ResourceWrapper <Resource> wrapper2;

            using (wrapper2 = await pool.CreateAsync(new Key(-1)))
            {
            }

            Assert.Equal(resourceCount, pool.Counter[ResourcePoolCounters.Cleaned].Value);

            for (var i = 0; i < resourceCount; i++)
            {
                using var wrapper = await pool.CreateAsync(new Key (i));

                Assert.NotSame(wrapper.Value, wrappers[i].Value);
                Assert.Equal(1, wrapper.Uses);
                Assert.True(wrappers[i].Value.ShutdownCompleted);
            }
        }
예제 #8
0
        public async Task IssueSameClientManyTimes()
        {
            var clock = new MemoryClock();
            var pool  = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), new ResourcePoolConfiguration()
            {
                MaximumResourceCount = 1,
                MaximumAge           = TimeSpan.FromMinutes(1),
            }, resourceFactory: _ => new Resource(), clock);
            var key = new Key(1);

            using var originalWrapper = await pool.CreateAsync(key);

            var originalResource = originalWrapper.Value;

            for (var i = 0; i < 1000; i++)
            {
                using var newWrapper = await pool.CreateAsync(key);

                Assert.Same(newWrapper.Value, originalResource);
            }
        }
예제 #9
0
        public async Task CreateFailsAfterDispose()
        {
            var capacity = 2;
            var context  = new Context(TestGlobal.Logger);
            var pool     = new ResourcePool <Key, Resource>(context, maxResourceCount: capacity, maxAgeMinutes: 1, resourceFactory: _ => new Resource());

            pool.Dispose();

            await Assert.ThrowsAsync <ObjectDisposedException>(async() =>
            {
                using var obj1 = await pool.CreateAsync(new Key(0));
            });
        }
예제 #10
0
        public Task CreateFailsAfterDispose()
        {
            var capacity = 2;
            var context  = new Context(TestGlobal.Logger);
            var pool     = new ResourcePool <Key, Resource>(context, new ResourcePoolConfiguration()
            {
                MaximumResourceCount = capacity,
                MaximumAge           = TimeSpan.FromMinutes(1),
            }, resourceFactory: _ => new Resource());

            pool.Dispose();

            return(Assert.ThrowsAsync <ObjectDisposedException>(async() =>
            {
                using var obj1 = await pool.CreateAsync(new Key(0));
            }));
        }
예제 #11
0
        /// <summary>
        /// Use an existing <see cref="GrpcCopyClient"/> if possible, else create a new one.
        /// </summary>
        public async Task <TResult> UseWithInvalidationAsync <TResult>(OperationContext context, string host, int grpcPort, Func <OperationContext, IResourceWrapperAdapter <GrpcCopyClient>, Task <TResult> > operation)
        {
            var key = new GrpcCopyClientKey(host, grpcPort);

            switch (_configuration.ResourcePoolVersion)
            {
            case GrpcCopyClientCacheConfiguration.PoolVersion.Disabled:
            {
                var client = new GrpcCopyClient(key, _configuration.GrpcCopyClientConfiguration, sharedBufferPool: _grpcCopyClientBufferPool);

                await client.StartupAsync(context).ThrowIfFailure();

                var result = await operation(context, new DefaultResourceWrapperAdapter <GrpcCopyClient>(client));

                await client.ShutdownAsync(context).ThrowIfFailure();

                return(result);
            }

            case GrpcCopyClientCacheConfiguration.PoolVersion.V1:
            {
                Contract.AssertNotNull(_resourcePool);
                using var resourceWrapper = await _resourcePool.CreateAsync(key);

                return(await operation(context, new ResourceWrapperV1Adapter <GrpcCopyClient>(resourceWrapper)));
            }

            case GrpcCopyClientCacheConfiguration.PoolVersion.V2:
            {
                Contract.AssertNotNull(_resourcePoolV2);

                return(await _resourcePoolV2.UseAsync(context, key, async resourceWrapper =>
                    {
                        // This ensures that the operation we want to perform conforms to the cancellation. When the
                        // resource needs to be removed, the token will be cancelled. Once the operation completes, we
                        // will be able to proceed with shutdown.
                        using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.Token, resourceWrapper.ShutdownToken);
                        var nestedContext = new OperationContext(context, cancellationTokenSource.Token);
                        return await operation(nestedContext, new ResourceWrapperV2Adapter <GrpcCopyClient>(resourceWrapper));
                    }));
            }
            }

            throw new NotImplementedException($"Unhandled resource pool version `{_configuration.ResourcePoolVersion}`");
        }
예제 #12
0
        public async Task FillCacheWithoutRemovingClients()
        {
            var maxCapacity = 10;
            var clock       = new MemoryClock();
            var pool        = new ResourcePool <Key, Resource>(new Context(TestGlobal.Logger), maxResourceCount: maxCapacity, maxAgeMinutes: 1, resourceFactory: _ => new Resource(), clock);

            for (var i = 0; i < maxCapacity; i++)
            {
                using var wrapper = await pool.CreateAsync(new Key (i));
            }

            // Created all resources
            Assert.Equal(maxCapacity, pool.Counter.GetCounterValue(ResourcePoolCounters.Created));

            // Zero resources were cleaned
            Assert.Equal(0, pool.Counter.GetCounterValue(ResourcePoolCounters.Cleaned));

            // Zero resources were reused
            Assert.Equal(0, pool.Counter.GetCounterValue(ResourcePoolCounters.Reused));
        }