protected override void Create(SingleNodeOptions options) { var dbPath = Path.GetFullPath(ResolveDbPath(options.DbPath, options.HttpPort)); _dbLock = new ExclusiveDbLock(dbPath); if (!_dbLock.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive lock on DB at '{0}'.", dbPath)); } var db = new TFChunkDb(CreateDbConfig(dbPath, options.CachedChunks, options.ChunksCacheSize)); var vnodeSettings = GetVNodeSettings(options); var dbVerifyHashes = !options.SkipDbVerify; var runProjections = options.RunProjections; Log.Info("\n{0,-25} {1}\n{2,-25} {3} (0x{3:X})\n{4,-25} {5} (0x{5:X})\n{6,-25} {7} (0x{7:X})\n{8,-25} {9} (0x{9:X})\n", "DATABASE:", db.Config.Path, "WRITER CHECKPOINT:", db.Config.WriterCheckpoint.Read(), "CHASER CHECKPOINT:", db.Config.ChaserCheckpoint.Read(), "EPOCH CHECKPOINT:", db.Config.EpochCheckpoint.Read(), "TRUNCATE CHECKPOINT:", db.Config.TruncateCheckpoint.Read()); var enabledNodeSubsystems = runProjections >= RunProjections.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; _projections = new Projections.Core.ProjectionsSubsystem(options.ProjectionThreads, runProjections); _node = new SingleVNode(db, vnodeSettings, dbVerifyHashes, ESConsts.MemTableEntryCount, _projections); RegisterWebControllers(enabledNodeSubsystems); RegisterUIProjections(); }
public async Task can_release_when_running_in_task_pool() { using var sut = new ExclusiveDbLock(GetDbPath()); Assert.True(sut.Acquire()); Assert.True(sut.IsAcquired); await Task.Delay(1); sut.Release(); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = opts.Db; if (!opts.MemDb) { var absolutePath = Path.GetFullPath(dbPath); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive lock on DB at '{0}'.", dbPath)); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive Cluster Node mutex '{0}'.", _clusterNodeMutex.MutexName)); } if (!opts.DiscoverViaDns && opts.GossipSeed.Length == 0) { if (opts.ClusterSize == 1) { Log.Info("DNS discovery is disabled, but no gossip seed endpoints have been specified. Since " + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified " + "using the `GossipSeed` option."); } } var runProjections = opts.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; _node = BuildNode(opts); RegisterWebControllers(enabledNodeSubsystems, opts); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = opts.Db; if (opts.Insecure) { Log.Warning( "\n==============================================================================================================\n" + "INSECURE MODE IS ON. THIS MODE IS *NOT* RECOMMENDED FOR PRODUCTION USE.\n" + "INSECURE MODE WILL DISABLE ALL AUTHENTICATION, AUTHORIZATION AND TRANSPORT SECURITY FOR ALL CLIENTS AND NODES.\n" + "==============================================================================================================\n"); } var deprecationMessages = string.Empty; if (opts.EnableAtomPubOverHTTP) { deprecationMessages += "- AtomPub over HTTP Interface has been deprecated as of version 20.6.0. It is recommended to use gRPC instead.\n"; } if (opts.DisableInternalTcpTls) { deprecationMessages += $"- The '{nameof(Options.DisableInternalTcpTls)}' option has been deprecated as of version 20.6.1 and currently has no effect. " + $"Please use the '{nameof(Options.Insecure)}' option instead.\n"; } if (opts.EnableExternalTCP) { deprecationMessages += "- The Legacy TCP Client Interface has been deprecated as of version 20.6.0. " + $"The External TCP Interface can be re-enabled with the '{nameof(Options.EnableExternalTCP)}' option. " + "It is recommended to use gRPC instead.\n"; } if (opts.DisableExternalTcpTls) { deprecationMessages += $"- The '{nameof(Options.DisableExternalTcpTls)}' option has been deprecated as of version 20.6.1.\n"; } if (!opts.GossipOnSingleNode) { deprecationMessages += $"- The '{nameof(Options.GossipOnSingleNode)}' option has been deprecated as of version 21.2\n"; } if (deprecationMessages.Any()) { Log.Warning($"DEPRECATED\n{deprecationMessages}"); } if (!opts.MemDb) { var absolutePath = Path.GetFullPath(dbPath); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive lock on DB at '{dbPath}'."); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive Cluster Node mutex '{_clusterNodeMutex.MutexName}'."); } if (!opts.DiscoverViaDns && opts.GossipSeed.Length == 0) { if (opts.ClusterSize == 1) { Log.Information( "DNS discovery is disabled, but no gossip seed endpoints have been specified. Since " + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified " + "using the `GossipSeed` option."); } } var runProjections = opts.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; Node = BuildNode(opts, LoadConfig); RegisterWebControllers(enabledNodeSubsystems, opts); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = opts.Db; if (opts.Dev) { Log.Warn( "\n========================================================================================================\n" + "DEVELOPMENT MODE IS ON. THIS MODE IS *NOT* INTENDED FOR PRODUCTION USE.\n" + "WHEN IN DEVELOPMENT MODE EVENT STORE WILL\n" + " - NOT WRITE ANY DATA TO DISK.\n" + " - USE A SELF SIGNED CERTIFICATE.\n" + "========================================================================================================\n"); } if (!opts.MemDb) { var absolutePath = Path.GetFullPath(dbPath); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive lock on DB at '{0}'.", dbPath)); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive Cluster Node mutex '{0}'.", _clusterNodeMutex.MutexName)); } if (!opts.DiscoverViaDns && opts.GossipSeed.Length == 0) { if (opts.ClusterSize == 1) { Log.Info("DNS discovery is disabled, but no gossip seed endpoints have been specified. Since " + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified " + "using the `GossipSeed` option."); } } var runProjections = opts.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; _node = BuildNode(opts); RegisterWebControllers(enabledNodeSubsystems, opts); _host = new WebHostBuilder() .UseKestrel(o => { o.Listen(opts.IntIp, opts.IntHttpPort); o.Listen(opts.ExtIp, opts.ExtHttpPort, listenOptions => listenOptions.UseHttps(_node.Certificate)); }) .UseStartup(new ClusterVNodeStartup(_node)) .ConfigureLogging(logging => { logging.ClearProviders(); logging.SetMinimumLevel(LogLevel.Warning); }) .UseNLog() .Build(); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = Path.GetFullPath(ResolveDbPath(opts.DbPath, opts.ExternalHttpPort)); if (!opts.InMemDb) { _dbLock = new ExclusiveDbLock(dbPath); if (!_dbLock.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive lock on DB at '{0}'.", dbPath)); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new Exception(string.Format("Couldn't acquire exclusive Cluster Node mutex '{0}'.", _clusterNodeMutex.MutexName)); } var dbConfig = CreateDbConfig(dbPath, opts.CachedChunks, opts.ChunksCacheSize, opts.InMemDb); FileStreamExtensions.ConfigureFlush(disableFlushToDisk: opts.UnsafeDisableFlushToDisk); var db = new TFChunkDb(dbConfig); var vNodeSettings = GetClusterVNodeSettings(opts); IGossipSeedSource gossipSeedSource; if (opts.DiscoverViaDns) { gossipSeedSource = new DnsGossipSeedSource(opts.ClusterDns, opts.ClusterGossipPort); } else { if (opts.GossipSeeds.Length == 0) { if (opts.ClusterSize > 1) { Log.Error(string.Format("DNS discovery is disabled, but no gossip seed endpoints have been specified. " + "Specify gossip seeds using the --{0} command line option.", Opts.GossipSeedCmd)); } else { Log.Info(string.Format("DNS discovery is disabled, but no gossip seed endpoints have been specified. Since" + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified" + "seeds using the --{0} command line option.", Opts.GossipSeedCmd)); } } gossipSeedSource = new KnownEndpointGossipSeedSource(opts.GossipSeeds); } var dbVerifyHashes = !opts.SkipDbVerify; var runProjections = opts.RunProjections; Log.Info("\n{0,-25} {1}\n" + "{2,-25} {3}\n" + "{4,-25} {5} (0x{5:X})\n" + "{6,-25} {7} (0x{7:X})\n" + "{8,-25} {9} (0x{9:X})\n" + "{10,-25} {11} (0x{11:X})\n", "INSTANCE ID:", vNodeSettings.NodeInfo.InstanceId, "DATABASE:", db.Config.Path, "WRITER CHECKPOINT:", db.Config.WriterCheckpoint.Read(), "CHASER CHECKPOINT:", db.Config.ChaserCheckpoint.Read(), "EPOCH CHECKPOINT:", db.Config.EpochCheckpoint.Read(), "TRUNCATE CHECKPOINT:", db.Config.TruncateCheckpoint.Read()); var enabledNodeSubsystems = runProjections >= RunProjections.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; _projections = new Projections.Core.ProjectionsSubsystem(opts.ProjectionThreads, opts.RunProjections); _node = new ClusterVNode(db, vNodeSettings, gossipSeedSource, dbVerifyHashes, opts.MaxMemTableSize, _projections); RegisterWebControllers(enabledNodeSubsystems, vNodeSettings); RegisterUiProjections(); }
public ClusterVNodeHostedService(ClusterVNodeOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } _options = options.Projections.RunProjections >= ProjectionType.System ? options.WithSubsystem(new ProjectionsSubsystem( new ProjectionSubsystemOptions( options.Projections.ProjectionThreads, options.Projections.RunProjections, options.Application.StartStandardProjections, TimeSpan.FromMinutes(options.Projections.ProjectionsQueryExpiry), options.Projections.FaultOutOfOrderProjections, options.Projections.ProjectionCompilationTimeout, options.Projections.ProjectionExecutionTimeout))) : options; if (!_options.Database.MemDb) { var absolutePath = Path.GetFullPath(_options.Database.Db); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive lock on DB at '{_options.Database.Db}'."); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive Cluster Node mutex '{_clusterNodeMutex.MutexName}'."); } var authorizationConfig = string.IsNullOrEmpty(_options.Auth.AuthorizationConfig) ? _options.Application.Config : _options.Auth.AuthorizationConfig; var authenticationConfig = string.IsNullOrEmpty(_options.Auth.AuthenticationConfig) ? _options.Application.Config : _options.Auth.AuthenticationConfig; var pluginLoader = new PluginLoader(new DirectoryInfo(Locations.PluginsDirectory)); var plugInContainer = FindPlugins(); if (_options.Database.DbLogFormat == DbLogFormat.V2) { var logFormatFactory = new LogV2FormatAbstractorFactory(); Node = ClusterVNode.Create(_options, logFormatFactory, GetAuthenticationProviderFactory(), GetAuthorizationProviderFactory(), GetPersistentSubscriptionConsumerStrategyFactories()); } else if (_options.Database.DbLogFormat == DbLogFormat.ExperimentalV3) { var logFormatFactory = new LogV3FormatAbstractorFactory(); Node = ClusterVNode.Create(_options, logFormatFactory, GetAuthenticationProviderFactory(), GetAuthorizationProviderFactory(), GetPersistentSubscriptionConsumerStrategyFactories()); } else { throw new ArgumentOutOfRangeException("Unexpected log format specified."); } var runProjections = _options.Projections.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : Array.Empty <NodeSubsystems>(); RegisterWebControllers(enabledNodeSubsystems); AuthorizationProviderFactory GetAuthorizationProviderFactory() { if (_options.Application.Insecure) { return(new AuthorizationProviderFactory(_ => new PassthroughAuthorizationProviderFactory())); } var authorizationTypeToPlugin = new Dictionary <string, AuthorizationProviderFactory> { { "internal", new AuthorizationProviderFactory(components => new LegacyAuthorizationProviderFactory(components.MainQueue)) } }; foreach (var potentialPlugin in pluginLoader.Load <IAuthorizationPlugin>()) { try { var commandLine = potentialPlugin.CommandLineName.ToLowerInvariant(); Log.Information( "Loaded authorization plugin: {plugin} version {version} (Command Line: {commandLine})", potentialPlugin.Name, potentialPlugin.Version, commandLine); authorizationTypeToPlugin.Add(commandLine, new AuthorizationProviderFactory(_ => potentialPlugin.GetAuthorizationProviderFactory(authorizationConfig))); } catch (CompositionException ex) { Log.Error(ex, "Error loading authentication plugin."); } } if (!authorizationTypeToPlugin.TryGetValue(_options.Auth.AuthorizationType.ToLowerInvariant(), out var factory)) { throw new ApplicationInitializationException( $"The authorization type {_options.Auth.AuthorizationType} is not recognised. If this is supposed " + $"to be provided by an authorization plugin, confirm the plugin DLL is located in {Locations.PluginsDirectory}." + Environment.NewLine + $"Valid options for authorization are: {string.Join(", ", authorizationTypeToPlugin.Keys)}."); } return(factory); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = opts.Db; if (opts.Dev) { Log.Warning( "\n========================================================================================================\n" + "DEVELOPMENT MODE IS ON. THIS MODE IS *NOT* INTENDED FOR PRODUCTION USE.\n" + "WHEN IN DEVELOPMENT MODE EVENT STORE WILL\n" + " - NOT WRITE ANY DATA TO DISK.\n" + " - USE A SELF SIGNED CERTIFICATE.\n" + "========================================================================================================\n"); } Log.Information( "\nINTERFACES\n" + "External TCP (Protobuf)\n" + $"\tEnabled\t: {opts.EnableExternalTCP}\n" + $"\tPort\t: {(opts.ExtTcpPort)}\n" + "External HTTP (AtomPub)\n" + $"\tEnabled\t: {opts.EnableAtomPubOverHTTP}\n" + $"\tPort\t: {opts.ExtHttpPort}\n"); if (opts.EnableAtomPubOverHTTP) { Log.Warning("\n DEPRECATION WARNING: AtomPub over HTTP Interface has been deprecated as of version 20.02. It is recommended to use gRPC instead.\n"); } if (opts.EnableExternalTCP) { Log.Warning( "\n DEPRECATION WARNING: The Legacy TCP Client Interface has been deprecated as of version 20.02. " + $"The External TCP Interface can be re-enabled with the '{nameof(Options.EnableExternalTCP)}' option. " + "It is recommended to use gRPC instead.\n"); } if (!opts.MemDb) { var absolutePath = Path.GetFullPath(dbPath); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new Exception($"Couldn't acquire exclusive lock on DB at '{dbPath}'."); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new Exception($"Couldn't acquire exclusive Cluster Node mutex '{_clusterNodeMutex.MutexName}'."); } if (!opts.DiscoverViaDns && opts.GossipSeed.Length == 0) { if (opts.ClusterSize == 1) { Log.Information( "DNS discovery is disabled, but no gossip seed endpoints have been specified. Since " + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified " + "using the `GossipSeed` option."); } } var runProjections = opts.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; Node = BuildNode(opts); RegisterWebControllers(enabledNodeSubsystems, opts); }
public void releasing_before_acquiring_throws() { using var sut = new ExclusiveDbLock(GetDbPath()); Assert.Throws <InvalidOperationException>(() => sut.Release()); }
public void acquiring_twice_throws() { using var sut = new ExclusiveDbLock(GetDbPath()); sut.Acquire(); Assert.Throws <InvalidOperationException>(() => sut.Acquire()); }
protected override void Create(ClusterNodeOptions opts) { var dbPath = opts.Db; if (opts.Dev) { Log.Warning( "\n========================================================================================================\n" + "DEVELOPMENT MODE IS ON. THIS MODE IS *NOT* INTENDED FOR PRODUCTION USE.\n" + "WHEN IN DEVELOPMENT MODE EVENTSTOREDB WILL\n" + " - DISABLE TLS ON ALL TCP INTERFACES.\n" + " - ENABLE THE ATOMPUB PROTOCOL OVER HTTP.\n" + "========================================================================================================\n"); } else if (opts.Insecure) { Log.Warning( "\n========================================================================================================\n" + "INSECURE MODE IS ON. THIS MODE IS *NOT* RECOMMENDED FOR PRODUCTION USE.\n" + "WHEN IN INSECURE MODE EVENTSTOREDB WILL\n" + " - DISABLE ALL AUTHENTICATION AND AUTHORIZATION.\n" + " - DISABLE TLS ON ALL TCP AND HTTP INTERFACES.\n" + "========================================================================================================\n"); } Log.Information( "\nINTERFACES\n" + "External TCP (Protobuf)\n" + $"\tEnabled\t: {opts.EnableExternalTCP}\n" + $"\tPort\t: {(opts.ExtTcpPort)}\n" + "HTTP (AtomPub)\n" + $"\tEnabled\t: {opts.EnableAtomPubOverHTTP}\n" + $"\tPort\t: {opts.HttpPort}\n"); if (opts.EnableAtomPubOverHTTP) { Log.Warning( "\n DEPRECATION WARNING: AtomPub over HTTP Interface has been deprecated as of version 20.6.0. It is recommended to use gRPC instead.\n"); } if (opts.DisableInternalTcpTls) { Log.Warning( $"\n DEPRECATION WARNING: The '{nameof(Options.DisableInternalTcpTls)}' option has been deprecated as of version 20.6.1 and currently has no effect. " + $"Please use the '{nameof(Options.Insecure)}' option instead.\n"); } if (opts.EnableExternalTCP) { Log.Warning( "\n DEPRECATION WARNING: The Legacy TCP Client Interface has been deprecated as of version 20.6.0. " + $"The External TCP Interface can be re-enabled with the '{nameof(Options.EnableExternalTCP)}' option. " + "It is recommended to use gRPC instead.\n"); } if (opts.DisableExternalTcpTls) { Log.Warning( $"\n DEPRECATION WARNING: The '{nameof(Options.DisableExternalTcpTls)}' option has been deprecated as of version 20.6.1.\n"); } if (!opts.MemDb) { var absolutePath = Path.GetFullPath(dbPath); if (Runtime.IsWindows) { absolutePath = absolutePath.ToLower(); } _dbLock = new ExclusiveDbLock(absolutePath); if (!_dbLock.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive lock on DB at '{dbPath}'."); } } _clusterNodeMutex = new ClusterNodeMutex(); if (!_clusterNodeMutex.Acquire()) { throw new InvalidConfigurationException($"Couldn't acquire exclusive Cluster Node mutex '{_clusterNodeMutex.MutexName}'."); } if (!opts.DiscoverViaDns && opts.GossipSeed.Length == 0) { if (opts.ClusterSize == 1) { Log.Information( "DNS discovery is disabled, but no gossip seed endpoints have been specified. Since " + "the cluster size is set to 1, this may be intentional. Gossip seeds can be specified " + "using the `GossipSeed` option."); } } var runProjections = opts.RunProjections; var enabledNodeSubsystems = runProjections >= ProjectionType.System ? new[] { NodeSubsystems.Projections } : new NodeSubsystems[0]; Node = BuildNode(opts, LoadConfig); RegisterWebControllers(enabledNodeSubsystems, opts); }