예제 #1
0
        static void EnsureClusterConfiguration(IDocumentStore store)
        {
            using (var s = store.OpenSession())
            {
                var getTopologyCmd = new GetClusterTopologyCommand();
                s.Advanced.RequestExecutor.Execute(getTopologyCmd, s.Advanced.Context);

                var topology = getTopologyCmd.Result.Topology;

                // Currently do not support clusters with more than one possible primary member. Watchers (passive replication targets) are OK.
                if (topology.Members.Count != 1)
                {
                    throw new InvalidOperationException("RavenDB Persistence does not support RavenDB clusters with more than one Leader/Member node. Only clusters with a single Leader and (optionally) Watcher nodes are supported.");
                }
            }
        }
        static void EnsureClusterConfiguration(IDocumentStore store)
        {
            using (var s = store.OpenSession())
            {
                var getTopologyCmd = new GetClusterTopologyCommand();
                s.Advanced.RequestExecutor.Execute(getTopologyCmd, s.Advanced.Context);

                var topology = getTopologyCmd.Result.Topology;

                // Currently do not support clusters.
                if (topology.AllNodes.Count != 1)
                {
                    throw new InvalidOperationException("RavenDB Persistence does not support RavenDB clusters with multiple nodes. Only a single-node configuration is supported.");
                }
            }
        }
예제 #3
0
        protected async Task <List <ProcessNode> > CreateCluster(string[] peers, IDictionary <string, string> customSettings = null, X509Certificate2 certificate = null)
        {
            var processes = new List <ProcessNode>();

            foreach (var peer in peers)
            {
                processes.Add(await GetServerAsync(peer));
            }

            var chosenOne = processes[0];

            using (var requestExecutor = ClusterRequestExecutor.CreateForSingleNode(chosenOne.Url, certificate))
                using (requestExecutor.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                {
                    foreach (var processNode in processes)
                    {
                        if (processNode == chosenOne)
                        {
                            continue;
                        }

                        var addCommand = new AddClusterNodeCommand(processNode.Url);
                        await requestExecutor.ExecuteAsync(addCommand, context);
                    }

                    var clusterCreated = await WaitForValueAsync(async() =>
                    {
                        var clusterTopology = new GetClusterTopologyCommand();
                        await requestExecutor.ExecuteAsync(clusterTopology, context);
                        return(clusterTopology.Result.Topology.Members.Count);
                    }, peers.Length);

                    Assert.True(clusterCreated == peers.Length, "Failed to create initial cluster");
                }

            return(processes);
        }
예제 #4
0
        public override async Task <bool> UpdateTopologyAsync(ServerNode node, int timeout, bool forceUpdate = false)
        {
            if (Disposed)
            {
                return(false);
            }
            var lockTaken = await _clusterTopologySemaphore.WaitAsync(timeout).ConfigureAwait(false);

            if (lockTaken == false)
            {
                return(false);
            }
            try
            {
                if (Disposed)
                {
                    return(false);
                }

                using (ContextPool.AllocateOperationContext(out JsonOperationContext context))
                {
                    var command = new GetClusterTopologyCommand();
                    await ExecuteAsync(node, null, context, command, shouldRetry : false).ConfigureAwait(false);

                    var serverHash = ServerHash.GetServerHash(node.Url);
                    ClusterTopologyLocalCache.TrySavingTopologyToLocalCache(serverHash, command.Result, context);

                    var results     = command.Result;
                    var newTopology = new Topology
                    {
                        Nodes = new List <ServerNode>(
                            from member in results.Topology.Members
                            select new ServerNode
                        {
                            Url        = member.Value,
                            ClusterTag = member.Key
                        }
                            )
                    };

                    if (_nodeSelector == null)
                    {
                        _nodeSelector = new NodeSelector(newTopology);
                        if (_readBalanceBehavior == ReadBalanceBehavior.FastestNode)
                        {
                            _nodeSelector.ScheduleSpeedTest();
                        }
                    }
                    else if (_nodeSelector.OnUpdateTopology(newTopology, forceUpdate: forceUpdate))
                    {
                        DisposeAllFailedNodesTimers();

                        if (_readBalanceBehavior == ReadBalanceBehavior.FastestNode)
                        {
                            _nodeSelector.ScheduleSpeedTest();
                        }
                    }

                    OnTopologyUpdated(newTopology);
                }
            }
            finally
            {
                _clusterTopologySemaphore.Release();
            }
            return(true);
        }
예제 #5
0
        public override async Task <bool> UpdateTopologyAsync(UpdateTopologyParameters parameters)
        {
            if (parameters is null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            if (Disposed)
            {
                return(false);
            }
            var lockTaken = await _clusterTopologySemaphore.WaitAsync(parameters.TimeoutInMs).ConfigureAwait(false);

            if (lockTaken == false)
            {
                return(false);
            }
            try
            {
                if (Disposed)
                {
                    return(false);
                }

                using (ContextPool.AllocateOperationContext(out JsonOperationContext context))
                {
                    var command = new GetClusterTopologyCommand(parameters.DebugTag);
                    await ExecuteAsync(parameters.Node, null, context, command, shouldRetry : false, sessionInfo : null, token : CancellationToken.None).ConfigureAwait(false);

                    ClusterTopologyLocalCache.TrySaving(TopologyHash, command.Result, Conventions, context);

                    var results     = command.Result;
                    var newTopology = new Topology
                    {
                        Nodes = new List <ServerNode>(
                            from member in results.Topology.Members
                            select new ServerNode
                        {
                            Url        = member.Value,
                            ClusterTag = member.Key
                        }
                            ),
                        Etag = results.Etag
                    };

                    TopologyEtag = results.Etag;

                    if (_nodeSelector == null)
                    {
                        _nodeSelector = new NodeSelector(newTopology);
                        if (Conventions.ReadBalanceBehavior == ReadBalanceBehavior.FastestNode)
                        {
                            _nodeSelector.ScheduleSpeedTest();
                        }
                    }
                    else if (_nodeSelector.OnUpdateTopology(newTopology, forceUpdate: parameters.ForceUpdate))
                    {
                        DisposeAllFailedNodesTimers();

                        if (Conventions.ReadBalanceBehavior == ReadBalanceBehavior.FastestNode)
                        {
                            _nodeSelector.ScheduleSpeedTest();
                        }
                    }

                    OnTopologyUpdatedInvoke(newTopology);
                }
            }
            catch (Exception)
            {
                if (Disposed == false)
                {
                    throw;
                }
            }
            finally
            {
                _clusterTopologySemaphore.Release();
            }

            return(true);
        }
예제 #6
0
        public async Task Initiate_Embedded_Replication()
        {
            #region Embedded_OpenStudio

            //this starts the embedded server
            EmbeddedServer.Instance.StartServer(new ServerOptions
            {
                ServerUrl = "http://localhost:8090" //if we don't specify a port, it will have random port
            });

            //this opens Embedded RavenDB Studio in the default browser
            EmbeddedServer.Instance.OpenStudioInBrowser();

            #endregion

            #region Embedded_Replication_Setup
            //first, initialize connection with one of cluster nodes
            var ravenClusterNodeUrl = "http://localhost:8080";
            using (var store = new DocumentStore
            {
                Urls = new[] { ravenClusterNodeUrl },
                Database = "Northwind"
            })
            {
                store.Initialize();

                //first, start the embedded server
                //note: by default the embedded server will use a random port.
                // if there is a need to replicate TO the embedded server, we would need to specify the port directly
                EmbeddedServer.Instance.StartServer(new ServerOptions
                {
                    ServerUrl = "http://localhost:8090"
                });

                //then, add embedded instance to existing cluster
                //(programmatically, this is done via REST)
                var embeddedServerUrl =
                    (await EmbeddedServer.Instance.GetServerUriAsync().ConfigureAwait(false)).ToString();
                var addToClusterCommandUrl = $"{ravenClusterNodeUrl}/admin/cluster/node?url={embeddedServerUrl}";
                await store.GetRequestExecutor()
                .HttpClient
                .SendAsync(
                    new HttpRequestMessage(
                        HttpMethod.Put,
                        addToClusterCommandUrl)).ConfigureAwait(false);

                var    getTopologyCommand = new GetClusterTopologyCommand();
                var    embeddedStore      = EmbeddedServer.Instance.GetDocumentStore("Northwind");
                string embeddedTag;
                using (var session = embeddedStore.OpenSession())
                {
                    //fetch topology info from embedded, so we can fetch the tag assigned by the cluster
                    await embeddedStore.GetRequestExecutor()
                    .ExecuteAsync(getTopologyCommand, session.Advanced.Context)
                    .ConfigureAwait(false);

                    embeddedTag = getTopologyCommand.Result.Topology.LastNodeId;
                }

                //this sends the command to add the database "Northwind" to its database group
                await store.Maintenance
                .Server
                .SendAsync(
                    new AddDatabaseNodeOperation(databaseName : "Northwind",
                                                 node : embeddedTag))
                .ConfigureAwait(false);
            }
            #endregion
        }