public async Task TestGarbageCollect()
        {
            var configuration = new RocksDbContentMetadataDatabaseConfiguration(_workingDirectory.Path)
            {
                CleanOnInitialize = false,
            };

            var context = new Context(Logger);
            var ctx     = new OperationContext(context);

            var keys = Enumerable.Range(0, 10).Select(i => (ShortHash)ContentHash.Random()).ToArray();

            void setBlob(RocksDbContentMetadataDatabase db, ShortHash key)
            {
                db.PutBlob(key, key.ToByteArray());
            }

            KeyCheckResult checkBlob(RocksDbContentMetadataDatabase db, ShortHash key)
            {
                if (db.TryGetBlob(key, out var blob))
                {
                    if (ByteArrayComparer.ArraysEqual(blob, key.ToByteArray()))
                    {
                        return(KeyCheckResult.Valid);
                    }
                    else
                    {
                        return(KeyCheckResult.Different);
                    }
                }
                else
                {
                    return(KeyCheckResult.Missing);
                }
            }

            {
                var db = new RocksDbContentMetadataDatabase(Clock, configuration);
                await db.StartupAsync(ctx).ShouldBeSuccess();

                db.SetGlobalEntry("test", "hello");
                setBlob(db, keys[0]);
                checkBlob(db, keys[0]).Should().Be(KeyCheckResult.Valid);

                await db.GarbageCollectAsync(ctx, force : true).ShouldBeSuccess();

                setBlob(db, keys[1]);
                checkBlob(db, keys[0]).Should().Be(KeyCheckResult.Valid);
                checkBlob(db, keys[1]).Should().Be(KeyCheckResult.Valid);

                await db.GarbageCollectAsync(ctx, force : true).ShouldBeSuccess();

                checkBlob(db, keys[0]).Should().Be(KeyCheckResult.Missing);
                checkBlob(db, keys[1]).Should().Be(KeyCheckResult.Valid);

                await db.ShutdownAsync(ctx).ShouldBeSuccess();
            }

            {
                var db = new RocksDbContentMetadataDatabase(Clock, configuration);
                await db.StartupAsync(ctx).ShouldBeSuccess();

                db.TryGetGlobalEntry("test", out var readValue);
                readValue.Should().Be("hello");

                setBlob(db, keys[2]);

                checkBlob(db, keys[0]).Should().Be(KeyCheckResult.Missing);
                checkBlob(db, keys[1]).Should().Be(KeyCheckResult.Valid);
                checkBlob(db, keys[2]).Should().Be(KeyCheckResult.Valid);
                await db.GarbageCollectAsync(ctx, force : true).ShouldBeSuccess();

                checkBlob(db, keys[0]).Should().Be(KeyCheckResult.Missing);
                checkBlob(db, keys[1]).Should().Be(KeyCheckResult.Missing);
                checkBlob(db, keys[2]).Should().Be(KeyCheckResult.Valid);

                await db.ShutdownAsync(ctx).ShouldBeSuccess();
            }
        }
Exemple #2
0
        private async Task RunTest(
            Func <OperationContext, ResilientGlobalCacheService, int, Task> runTestAsync,
            bool persistentStorageFailure = false,
            bool volatileStorageFailure   = false,
            IClock?clock   = null,
            int iterations = 1,
            Action <GlobalCacheServiceConfiguration>?modifyConfig = null)
        {
            var tracingContext   = new Context(Logger);
            var operationContext = new OperationContext(tracingContext);

            clock ??= SystemClock.Instance;

            var contentMetadataServiceConfiguration = new GlobalCacheServiceConfiguration()
            {
                Checkpoint  = new CheckpointManagerConfiguration(TestRootDirectoryPath / "CheckpointManager", default(MachineLocation)),
                EventStream = new ContentMetadataEventStreamConfiguration(),
            };

            modifyConfig?.Invoke(contentMetadataServiceConfiguration);

            using var database = LocalRedisProcessDatabase.CreateAndStartEmpty(_redisFixture, TestGlobal.Logger, SystemClock.Instance);
            var primaryFactory = await RedisDatabaseFactory.CreateAsync(
                operationContext,
                new LiteralConnectionStringProvider(database.ConnectionString),
                new RedisConnectionMultiplexerConfiguration()
            {
                LoggingSeverity = Severity.Error
            });

            var primaryDatabaseAdapter = new RedisDatabaseAdapter(primaryFactory, "keyspace");

            var centralStorage = new Dictionary <string, byte[]>();

            for (var iteration = 0; iteration < iterations; iteration++)
            {
                Tracer.Info(operationContext, $"Running iteration {iteration}");

                var redisVolatileEventStorage = new RedisWriteAheadEventStorage(new RedisVolatileEventStorageConfiguration(), primaryDatabaseAdapter, clock);

                IWriteAheadEventStorage volatileEventStorage = new FailingVolatileEventStorage();
                if (!volatileStorageFailure)
                {
                    volatileEventStorage = redisVolatileEventStorage;
                }

                IWriteBehindEventStorage persistentEventStorage = new FailingPersistentEventStorage();
                if (!persistentStorageFailure)
                {
                    persistentEventStorage = new MockPersistentEventStorage();
                }

                var contentMetadataEventStream = new ContentMetadataEventStream(
                    contentMetadataServiceConfiguration.EventStream,
                    volatileEventStorage,
                    persistentEventStorage);

                var rocksdbContentMetadataDatabaseConfiguration = new RocksDbContentMetadataDatabaseConfiguration(TestRootDirectoryPath / "ContentMetadataDatabase");
                var rocksDbContentMetadataStore = new RocksDbContentMetadataStore(clock, new RocksDbContentMetadataStoreConfiguration()
                {
                    Database = rocksdbContentMetadataDatabaseConfiguration,
                });

                var storage           = new MockCentralStorage(centralStorage);
                var checkpointManager = new CheckpointManager(
                    rocksDbContentMetadataStore.Database,
                    redisVolatileEventStorage,
                    storage,
                    contentMetadataServiceConfiguration.Checkpoint,
                    new CounterCollection <ContentLocationStoreCounters>());
                var resilientContentMetadataService = new ResilientGlobalCacheService(
                    contentMetadataServiceConfiguration,
                    checkpointManager,
                    rocksDbContentMetadataStore,
                    contentMetadataEventStream,
                    storage,
                    clock);

                await resilientContentMetadataService.StartupAsync(operationContext).ThrowIfFailure();
                await runTestAsync(operationContext, resilientContentMetadataService, iteration);

                await resilientContentMetadataService.ShutdownAsync(operationContext).ThrowIfFailure();
            }
        }