Ejemplo n.º 1
0
        private BoolResult Load(OperationContext context, StoreSlot activeSlot, bool clean = false)
        {
            try
            {
                var storeLocation = GetStoreLocation(activeSlot);

                if (clean && Directory.Exists(storeLocation))
                {
                    BuildXL.Native.IO.FileUtilities.DeleteDirectoryContents(storeLocation, deleteRootDirectory: true);
                }

                Directory.CreateDirectory(storeLocation);

                Tracer.Info(context, $"Creating rocksdb store at '{storeLocation}'.");

                var possibleStore = KeyValueStoreAccessor.Open(storeLocation,
                                                               additionalColumns: new[] { nameof(Columns.ClusterState), nameof(Columns.Metadata) },
                                                               rotateLogs: true,
                                                               failureHandler: failureEvent =>
                {
                    // By default, rethrow is true iff it is a user error. We invalidate only if it isn't
                    failureEvent.Invalidate = !failureEvent.Rethrow;
                },
                                                               invalidationHandler: failure => OnDatabaseInvalidated(context, failure),
                                                               onFailureDeleteExistingStoreAndRetry: _configuration.OnFailureDeleteExistingStoreAndRetry,
                                                               onStoreReset: failure => {
                    Tracer.Error(context, $"RocksDb critical error caused store to reset: {failure.DescribeIncludingInnerFailures()}");
                });

                if (possibleStore.Succeeded)
                {
                    var oldKeyValueStore = _keyValueStore;
                    var store            = possibleStore.Result;

                    if (oldKeyValueStore == null)
                    {
                        _keyValueStore = new KeyValueStoreGuard(store);
                    }
                    else
                    {
                        // Just replace the inner accessor
                        oldKeyValueStore.Replace(store);
                    }

                    _activeSlot    = activeSlot;
                    _storeLocation = storeLocation;
                }

                return(possibleStore.Succeeded ? BoolResult.Success : new BoolResult($"Failed to initialize a RocksDb store at {_storeLocation}:", possibleStore.Failure.DescribeIncludingInnerFailures()));
            }
            catch (Exception ex) when(ex.IsRecoverableIoException())
            {
                return(new BoolResult(ex));
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Open the datastore and populate the KeyValueStoreAccessor for the XLG++ DB
        /// </summary>
        public XldbDataStore(string storeDirectory,
                             bool defaultColumnKeyTracked = false,
                             IEnumerable <string> additionalKeyTrackedColumns = null,
                             bool openReadOnly           = true,
                             bool dropMismatchingColumns = false,
                             bool onFailureDeleteExistingStoreAndRetry = false)
        {
            var accessor = KeyValueStoreAccessor.Open(storeDirectory,
                                                      defaultColumnKeyTracked,
                                                      new string[] { EventColumnFamilyName, PipColumnFamilyName, StaticGraphColumnFamilyName },
                                                      additionalKeyTrackedColumns,
                                                      failureHandler: null,
                                                      openReadOnly,
                                                      dropMismatchingColumns,
                                                      onFailureDeleteExistingStoreAndRetry);

            if (accessor.Succeeded)
            {
                Accessor = accessor.Result;
            }
            else
            {
                Accessor = null;
                Console.Error.WriteLine("Could not create an accessor for RocksDB. Accessor is null! " + accessor.Failure.DescribeIncludingInnerFailures());
            }

            m_eventParserDictionary.Add(ExecutionEventId.FileArtifactContentDecided, FileArtifactContentDecidedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.WorkerList, WorkerListEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionPerformance, PipExecutionPerformanceEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DirectoryMembershipHashed, DirectoryMembershipHashedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessExecutionMonitoringReported, ProcessExecutionMonitoringReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessFingerprintComputation, ProcessFingerprintComputationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ExtraEventDataReported, ExtraEventDataReported.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DependencyViolationReported, DependencyViolationReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionStepPerformanceReported, PipExecutionStepPerformanceReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipCacheMiss, PipCacheMissEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ResourceUsageReported, StatusReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.BxlInvocation, BXLInvocationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionDirectoryOutputs, PipExecutionDirectoryOutputsEvent.Parser);

            // We only store non-meta pips (and no HashSourceFile pips) into this database, so module, hash, value, and specfile are not included in the parser dictionary
            m_pipParserDictionary.Add(PipType.CopyFile, CopyFile.Parser);
            m_pipParserDictionary.Add(PipType.WriteFile, WriteFile.Parser);
            m_pipParserDictionary.Add(PipType.Process, ProcessPip.Parser);
            m_pipParserDictionary.Add(PipType.SealDirectory, SealDirectory.Parser);
            m_pipParserDictionary.Add(PipType.Ipc, IpcPip.Parser);
        }
Ejemplo n.º 3
0
        /// <inheritdoc/>
        public override void Prepare()
        {
            var accessor = KeyValueStoreAccessor.Open(storeDirectory: OutputDirPath, additionalColumns: m_additionalColumns, openBulkLoad: false);

            if (accessor.Succeeded)
            {
                m_accessor          = accessor.Result;
                m_accessorSucceeded = true;
            }
            else
            {
                Console.Error.WriteLine("Could not access RocksDB datastore. Exiting analyzer.");
            }

            m_eventSequenceNumber = 1;
            m_eventCount          = 0;
        }
Ejemplo n.º 4
0
        public void ReadOnlyWorksWithHardlinks()
        {
            var storeDirectory = TestRootDirectoryPath / "store";
            var key            = ThreadSafeRandom.GetBytes(10);
            var value          = ThreadSafeRandom.GetBytes(10);

            // Create a RocksDb instance and write to it
            using (var accessor = KeyValueStoreAccessor.Open(storeDirectory.ToString()).Result)
            {
                var result = accessor.Use(store => store.Put(key, value));
                result.Succeeded.Should().BeTrue();
            }

            // Hardlink it to the target path
            var hardlinkPath = TestRootDirectoryPath / "hardlinks";

            FileSystem.CreateDirectory(hardlinkPath);
            foreach (var file in FileSystem.EnumerateFiles(storeDirectory, EnumerateOptions.None))
            {
                var source = file.FullPath;
                var target = hardlinkPath / file.FullPath.FileName;

                Logger.Info($"Found {source}. Linking to {target}");
                var result = FileSystem.CreateHardLink(source, target, replaceExisting: true);
                result.Should().Be(CreateHardLinkResult.Success);

                // Make sure nothing can be written to any of the files
                FileSystem.SetFileAttributes(target, System.IO.FileAttributes.Normal);
                FileSystem.SetFileAttributes(target, System.IO.FileAttributes.ReadOnly);
                FileSystem.DenyFileWrites(target);
                FileSystem.DenyAttributeWrites(target);
            }

            // Open the target in read-only mode and make sure we read the same value
            using (var accessor = KeyValueStoreAccessor.Open(hardlinkPath.ToString(), openReadOnly: true).Result)
            {
                var result = accessor.Use(store =>
                {
                    var found = store.TryGetValue(key, out var foundValue);
                    found.Should().BeTrue();
                    foundValue.Should().BeEquivalentTo(value);
                });
                result.Succeeded.Should().BeTrue();
            }
        }
Ejemplo n.º 5
0
        protected override Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            _accessor = KeyValueStoreAccessor.Open(new KeyValueStoreAccessor.RocksDbStoreArguments()
            {
                StoreDirectory             = _configuration.Path,
                AdditionalColumns          = new[] { nameof(Columns.Registers) },
                DropMismatchingColumns     = true,
                EnableStatistics           = true,
                RotateLogsNumFiles         = 5,
                RotateLogsMaxAge           = TimeSpan.FromDays(7),
                RotateLogsMaxFileSizeBytes = (ulong)"100MB".ToSize(),
                EnableWriteAheadLog        = _configuration.EnableWriteAheadLog,
                EnableFSync = _configuration.EnableFSync,
            }).ToResult(isNullAllowed: true).ThrowIfFailure();
            Contract.Assert(!_accessor.Disabled);

            return(BoolResult.SuccessTask);
        }
Ejemplo n.º 6
0
        private BoolResult Load(OperationContext context, StoreSlot activeSlot, bool clean = false)
        {
            try
            {
                var storeLocation = GetStoreLocation(activeSlot);

                if (clean && Directory.Exists(storeLocation))
                {
                    BuildXL.Native.IO.FileUtilities.DeleteDirectoryContents(storeLocation, deleteRootDirectory: true);
                }

                Directory.CreateDirectory(storeLocation);

                Tracer.Info(context, $"Creating rocksdb store at '{storeLocation}'.");

                var possibleStore = KeyValueStoreAccessor.Open(storeLocation,
                                                               additionalColumns: new[] { nameof(ClusterState) });
                if (possibleStore.Succeeded)
                {
                    var oldKeyValueStore = _keyValueStore;
                    var store            = possibleStore.Result;

                    if (oldKeyValueStore == null)
                    {
                        _keyValueStore = new KeyValueStoreGuard(store);
                    }
                    else
                    {
                        // Just replace the inner accessor
                        oldKeyValueStore.Replace(store);
                    }

                    _activeSlot    = activeSlot;
                    _storeLocation = storeLocation;
                }

                return(possibleStore.Succeeded ? BoolResult.Success : new BoolResult($"Failed to initialize a RocksDb store at {_storeLocation}:", possibleStore.Failure.DescribeIncludingInnerFailures()));
            }
            catch (Exception ex) when(ex.IsRecoverableIoException())
            {
                return(new BoolResult(ex));
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Open the datastore and populate the KeyValueStoreAccessor for the XLG++ DB
        /// </summary>
        public XldbDataStore(string storeDirectory,
                             bool defaultColumnKeyTracked                     = false,
                             IEnumerable <string> additionalColumns           = null,
                             IEnumerable <string> additionalKeyTrackedColumns = null,
                             Action <Failure> failureHandler                  = null,
                             bool openReadOnly           = false,
                             bool dropMismatchingColumns = false,
                             bool onFailureDeleteExistingStoreAndRetry = false)
        {
            var accessor = KeyValueStoreAccessor.Open(storeDirectory,
                                                      defaultColumnKeyTracked,
                                                      additionalColumns,
                                                      additionalKeyTrackedColumns,
                                                      failureHandler,
                                                      openReadOnly,
                                                      dropMismatchingColumns,
                                                      onFailureDeleteExistingStoreAndRetry);

            if (accessor.Succeeded)
            {
                Accessor = accessor.Result;
            }
            else
            {
                Accessor = null;
                Console.Error.WriteLine("Could not create an accessor for RocksDB. Accessor is null");
            }

            m_eventParserDictionary.Add(ExecutionEventId.FileArtifactContentDecided, FileArtifactContentDecidedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.WorkerList, WorkerListEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionPerformance, PipExecutionPerformanceEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DirectoryMembershipHashed, DirectoryMembershipHashedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessExecutionMonitoringReported, ProcessExecutionMonitoringReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessFingerprintComputation, ProcessFingerprintComputationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ExtraEventDataReported, ExtraEventDataReported.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DependencyViolationReported, DependencyViolationReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionStepPerformanceReported, PipExecutionStepPerformanceReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipCacheMiss, PipCacheMissEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ResourceUsageReported, StatusReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.BxlInvocation, BXLInvocationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionDirectoryOutputs, PipExecutionDirectoryOutputsEvent.Parser);
        }
Ejemplo n.º 8
0
        private BoolResult Load(OperationContext context, StoreSlot activeSlot, bool clean)
        {
            try
            {
                var storeLocation = GetStoreLocation(activeSlot);

                if (clean)
                {
                    Counters[ContentLocationDatabaseCounters.DatabaseCleans].Increment();

                    if (Directory.Exists(storeLocation))
                    {
                        FileUtilities.DeleteDirectoryContents(storeLocation, deleteRootDirectory: true);
                    }
                }

                bool dbAlreadyExists = Directory.Exists(storeLocation);
                Directory.CreateDirectory(storeLocation);

                Tracer.Info(context, $"Creating RocksDb store at '{storeLocation}'. Clean={clean}, Configured Epoch='{_configuration.Epoch}'");

                var possibleStore = KeyValueStoreAccessor.Open(
                    new RocksDbStoreConfiguration(storeLocation)
                {
                    AdditionalColumns          = ColumnNames,
                    RotateLogsMaxFileSizeBytes = _configuration.LogsKeepLongTerm ? 0ul : ((ulong)"1MB".ToSize()),
                    RotateLogsNumFiles         = _configuration.LogsKeepLongTerm ? 60ul : 1,
                    RotateLogsMaxAge           = TimeSpan.FromHours(_configuration.LogsKeepLongTerm ? 12 : 1),
                    EnableStatistics           = true,
                    FastOpen = true,
                    // We take the user's word here. This may be completely wrong, but we don't have enough
                    // information at this point to take a decision here. If a machine is master and demoted to
                    // worker, EventHub may continue to process events for a little while. If we set this to
                    // read-only during that checkpoint, those last few events will fail with RocksDbException.
                    // NOTE: we need to check that the database exists because RocksDb will refuse to open an empty
                    // read-only instance.
                    ReadOnly = _configuration.OpenReadOnly && dbAlreadyExists,
                    // The RocksDb database here is read-only from the perspective of the default column family,
                    // but read/write from the perspective of the ClusterState (which is rewritten on every
                    // heartbeat). This means that the database may perform background compactions on the column
                    // families, possibly triggering a RocksDb corruption "block checksum mismatch" error.
                    // Since the writes to ClusterState are relatively few, we can make-do with disabling
                    // compaction here and pretending like we are using a read-only database.
                    DisableAutomaticCompactions = !IsDatabaseWriteable,
                    LeveledCompactionDynamicLevelTargetSizes = true,
                    Compression = _configuration.Compression,
                    UseReadOptionsWithSetTotalOrderSeekInDbEnumeration     = _configuration.UseReadOptionsWithSetTotalOrderSeekInDbEnumeration,
                    UseReadOptionsWithSetTotalOrderSeekInGarbageCollection = _configuration.UseReadOptionsWithSetTotalOrderSeekInGarbageCollection,
                },
                    // When an exception is caught from within methods using the database, this handler is called to
                    // decide whether the exception should be rethrown in user code, and the database invalidated. Our
                    // policy is to only invalidate if it is an exception coming from RocksDb, but not from our code.
                    failureHandler: failureEvent =>
                {
                    // By default, rethrow is true iff it is a user error. We invalidate only if it isn't
                    failureEvent.Invalidate = !failureEvent.Rethrow;
                },
                    // The database may be invalidated for a number of reasons, all related to latent bugs in our code.
                    // For example, exceptions thrown from methods that are operating on the DB. If that happens, we
                    // call a user-defined handler. This is because the instance is invalid after this happens.
                    invalidationHandler: failure => OnDatabaseInvalidated(context, failure),
                    // It is possible we may fail to open an already existing database. This can happen (most commonly)
                    // due to corruption, among others. If this happens, then we want to recreate it from empty. This
                    // only helps for the memoization store.
                    onFailureDeleteExistingStoreAndRetry: _configuration.OnFailureDeleteExistingStoreAndRetry,
                    // If the previous flag is true, and it does happen that we invalidate the database, we want to log
                    // it explicitly.
                    onStoreReset: failure =>
                {
                    Tracer.Error(context, $"RocksDb critical error caused store to reset: {failure.DescribeIncludingInnerFailures()}");
                });

                if (possibleStore.Succeeded)
                {
                    var oldKeyValueStore = _keyValueStore;
                    var store            = possibleStore.Result;

                    if (oldKeyValueStore == null)
                    {
                        _keyValueStore = new KeyValueStoreGuard(store);
                        _keyValueStore.UseExclusive((db, state) =>
                        {
                            if (db.TryGetValue(nameof(GlobalKeys.ActiveColummGroup), out var activeColumnGroup))
                            {
                                _activeColumnsGroup = (ColumnGroup)Enum.Parse(typeof(ColumnGroup), activeColumnGroup);
                            }
                            else
                            {
                                _activeColumnsGroup = ColumnGroup.One;
                            }

                            return(true);
                        },
                                                    this).ThrowOnError();
                    }
                    else
                    {
                        // Just replace the inner accessor
                        oldKeyValueStore.Replace(store, db =>
                        {
                            if (db.TryGetValue(nameof(GlobalKeys.ActiveColummGroup), out var activeColumnGroup))
                            {
                                _activeColumnsGroup = (ColumnGroup)Enum.Parse(typeof(ColumnGroup), activeColumnGroup);
                            }
                            else
                            {
                                _activeColumnsGroup = ColumnGroup.One;
                            }
                        }).ThrowOnError();
                    }

                    _activeSlot    = activeSlot;
                    _storeLocation = storeLocation;
                }

                return(possibleStore.Succeeded ? BoolResult.Success : new BoolResult($"Failed to initialize a RocksDb store at {_storeLocation}:", possibleStore.Failure.DescribeIncludingInnerFailures()));
            }
            catch (Exception ex) when(ex.IsRecoverableIoException())
            {
                return(new BoolResult(ex));
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Open the datastore and populate the KeyValueStoreAccessor for the XLG++ DB
        /// </summary>
        public XldbDataStore(string storeDirectory,
                             bool defaultColumnKeyTracked = false,
                             IEnumerable <string> additionalKeyTrackedColumns = null,
                             bool openReadOnly           = true,
                             bool dropMismatchingColumns = false,
                             bool onFailureDeleteExistingStoreAndRetry = false)
        {
            if (File.Exists(Path.Combine(storeDirectory, XldbVersionFileName)))
            {
                using TextReader reader = File.OpenText(Path.Combine(storeDirectory, XldbVersionFileName));
                var version = int.Parse(reader.ReadLine());

                if (version > XldbVersion)
                {
                    throw new Exception($"The Xldb version you are trying to access is newer than your Xldb Datastore version. There may be breaking changes in this new version and so the accessor cannot be created. Exiting now ...");
                }
            }
            else
            {
                throw new Exception($"Xldb version file not found in storeDirectory. Cannot open the accessor with this version file and exiting now ...");
            }

            var accessor = KeyValueStoreAccessor.Open(storeDirectory,
                                                      defaultColumnKeyTracked,
                                                      new string[] { EventColumnFamilyName, PipColumnFamilyName, StaticGraphColumnFamilyName },
                                                      additionalKeyTrackedColumns,
                                                      failureHandler: null,
                                                      openReadOnly,
                                                      dropMismatchingColumns,
                                                      onFailureDeleteExistingStoreAndRetry);

            if (accessor.Succeeded)
            {
                m_accessor = accessor.Result;
            }
            else
            {
                m_accessor = null;
                throw new Exception($"Could not create an accessor for RocksDB. Accessor is null! Error is {accessor.Failure.DescribeIncludingInnerFailures()}");
            }

            m_eventParserDictionary.Add(ExecutionEventId.FileArtifactContentDecided, FileArtifactContentDecidedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.WorkerList, WorkerListEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionPerformance, PipExecutionPerformanceEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DirectoryMembershipHashed, DirectoryMembershipHashedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessExecutionMonitoringReported, ProcessExecutionMonitoringReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ProcessFingerprintComputation, ProcessFingerprintComputationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.BuildSessionConfiguration, BuildSessionConfigurationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.DependencyViolationReported, DependencyViolationReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionStepPerformanceReported, PipExecutionStepPerformanceReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipCacheMiss, PipCacheMissEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.ResourceUsageReported, StatusReportedEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.BxlInvocation, BxlInvocationEvent.Parser);
            m_eventParserDictionary.Add(ExecutionEventId.PipExecutionDirectoryOutputs, PipExecutionDirectoryOutputsEvent.Parser);

            // We only store non-meta pips (and no HashSourceFile pips) into this database, so module, hash, value, and specfile are not included in the parser dictionary
            m_pipParserDictionary.Add(PipType.CopyFile, CopyFile.Parser);
            m_pipParserDictionary.Add(PipType.WriteFile, WriteFile.Parser);
            m_pipParserDictionary.Add(PipType.Process, ProcessPip.Parser);
            m_pipParserDictionary.Add(PipType.SealDirectory, SealDirectory.Parser);
            m_pipParserDictionary.Add(PipType.Ipc, IpcPip.Parser);
        }
Ejemplo n.º 10
0
        private BoolResult Load(OperationContext context, StoreSlot activeSlot, bool clean)
        {
            try
            {
                var storeLocation = GetStoreLocation(activeSlot);

                if (Directory.Exists(storeLocation))
                {
                    // We backup right before loading. This means we should never loose any logs, but it also means
                    // the backup directory will only hold logs for DBs that have already been overwritten.
                    if (_logManager != null)
                    {
                        _logManager.BackupAsync(context, new AbsolutePath(storeLocation), activeSlot.ToString()).Result.IgnoreFailure();
                        Task.Run(() => _logManager.GarbageCollect(context)).FireAndForget(context, severityOnException: Severity.Error);
                    }

                    if (clean)
                    {
                        FileUtilities.DeleteDirectoryContents(storeLocation, deleteRootDirectory: true);
                    }
                }

                Directory.CreateDirectory(storeLocation);

                Tracer.Info(context, $"Creating RocksDb store at '{storeLocation}'.");

                var possibleStore = KeyValueStoreAccessor.Open(
                    new KeyValueStoreAccessor.RocksDbStoreArguments()
                {
                    StoreDirectory    = storeLocation,
                    AdditionalColumns = new[] { nameof(Columns.ClusterState), nameof(Columns.Metadata) },
                    RotateLogs        = true,
                    EnableStatistics  = true,
                    FastOpen          = true,
                },
                    // When an exception is caught from within methods using the database, this handler is called to
                    // decide whether the exception should be rethrown in user code, and the database invalidated. Our
                    // policy is to only invalidate if it is an exception coming from RocksDb, but not from our code.
                    failureHandler: failureEvent =>
                {
                    // By default, rethrow is true iff it is a user error. We invalidate only if it isn't
                    failureEvent.Invalidate = !failureEvent.Rethrow;
                },
                    // The database may be invalidated for a number of reasons, all related to latent bugs in our code.
                    // For example, exceptions thrown from methods that are operating on the DB. If that happens, we
                    // call a user-defined handler. This is because the instance is invalid after this happens.
                    invalidationHandler: failure => OnDatabaseInvalidated(context, failure),
                    // It is possible we may fail to open an already existing database. This can happen (most commonly)
                    // due to corruption, among others. If this happens, then we want to recreate it from empty. This
                    // only helps for the memoization store.
                    onFailureDeleteExistingStoreAndRetry: _configuration.OnFailureDeleteExistingStoreAndRetry,
                    // If the previous flag is true, and it does happen that we invalidate the database, we want to log
                    // it explicitly.
                    onStoreReset: failure =>
                {
                    Tracer.Error(context, $"RocksDb critical error caused store to reset: {failure.DescribeIncludingInnerFailures()}");
                });

                if (possibleStore.Succeeded)
                {
                    var oldKeyValueStore = _keyValueStore;
                    var store            = possibleStore.Result;

                    if (oldKeyValueStore == null)
                    {
                        _keyValueStore = new KeyValueStoreGuard(store);
                    }
                    else
                    {
                        // Just replace the inner accessor
                        oldKeyValueStore.Replace(store);
                    }

                    _activeSlot    = activeSlot;
                    _storeLocation = storeLocation;
                }

                return(possibleStore.Succeeded ? BoolResult.Success : new BoolResult($"Failed to initialize a RocksDb store at {_storeLocation}:", possibleStore.Failure.DescribeIncludingInnerFailures()));
            }
            catch (Exception ex) when(ex.IsRecoverableIoException())
            {
                return(new BoolResult(ex));
            }
        }
Ejemplo n.º 11
0
        private BoolResult Load(OperationContext context, StoreSlot activeSlot, bool clean)
        {
            try
            {
                var storeLocation = GetStoreLocation(activeSlot);

                if (Directory.Exists(storeLocation))
                {
                    if (clean)
                    {
                        FileUtilities.DeleteDirectoryContents(storeLocation, deleteRootDirectory: true);
                    }
                }

                Directory.CreateDirectory(storeLocation);

                Tracer.Info(context, $"Creating RocksDb store at '{storeLocation}'.");

                var possibleStore = KeyValueStoreAccessor.Open(
                    new KeyValueStoreAccessor.RocksDbStoreArguments()
                {
                    StoreDirectory             = storeLocation,
                    AdditionalColumns          = new[] { nameof(Columns.ClusterState), nameof(Columns.Metadata) },
                    RotateLogsMaxFileSizeBytes = _configuration.LogsKeepLongTerm ? 0ul : ((ulong)"1MB".ToSize()),
                    RotateLogsNumFiles         = _configuration.LogsKeepLongTerm ? 60ul : 1,
                    RotateLogsMaxAge           = TimeSpan.FromHours(_configuration.LogsKeepLongTerm ? 12 : 1),
                    EnableStatistics           = true,
                    FastOpen = true,
                },
                    // When an exception is caught from within methods using the database, this handler is called to
                    // decide whether the exception should be rethrown in user code, and the database invalidated. Our
                    // policy is to only invalidate if it is an exception coming from RocksDb, but not from our code.
                    failureHandler: failureEvent =>
                {
                    // By default, rethrow is true iff it is a user error. We invalidate only if it isn't
                    failureEvent.Invalidate = !failureEvent.Rethrow;
                },
                    // The database may be invalidated for a number of reasons, all related to latent bugs in our code.
                    // For example, exceptions thrown from methods that are operating on the DB. If that happens, we
                    // call a user-defined handler. This is because the instance is invalid after this happens.
                    invalidationHandler: failure => OnDatabaseInvalidated(context, failure),
                    // It is possible we may fail to open an already existing database. This can happen (most commonly)
                    // due to corruption, among others. If this happens, then we want to recreate it from empty. This
                    // only helps for the memoization store.
                    onFailureDeleteExistingStoreAndRetry: _configuration.OnFailureDeleteExistingStoreAndRetry,
                    // If the previous flag is true, and it does happen that we invalidate the database, we want to log
                    // it explicitly.
                    onStoreReset: failure =>
                {
                    Tracer.Error(context, $"RocksDb critical error caused store to reset: {failure.DescribeIncludingInnerFailures()}");
                });

                if (possibleStore.Succeeded)
                {
                    var oldKeyValueStore = _keyValueStore;
                    var store            = possibleStore.Result;

                    if (oldKeyValueStore == null)
                    {
                        _keyValueStore = new KeyValueStoreGuard(store);
                    }
                    else
                    {
                        // Just replace the inner accessor
                        oldKeyValueStore.Replace(store);
                    }

                    _activeSlot    = activeSlot;
                    _storeLocation = storeLocation;
                }

                return(possibleStore.Succeeded ? BoolResult.Success : new BoolResult($"Failed to initialize a RocksDb store at {_storeLocation}:", possibleStore.Failure.DescribeIncludingInnerFailures()));
            }
            catch (Exception ex) when(ex.IsRecoverableIoException())
            {
                return(new BoolResult(ex));
            }
        }