public virtual unsafe void Execute(TransactionOperationContext context, Table items, long index, DatabaseRecord record, RachisState state, out object result)
        {
            BlittableJsonReaderObject itemBlittable = null;
            var itemKey = GetItemId();

            using (Slice.From(context.Allocator, itemKey.ToLowerInvariant(), out Slice valueNameLowered))
            {
                if (items.ReadByKey(valueNameLowered, out TableValueReader reader))
                {
                    var ptr = reader.Read(2, out int size);
                    itemBlittable = new BlittableJsonReaderObject(ptr, size, context);
                }

                itemBlittable = GetUpdatedValue(index, record, context, itemBlittable, state);

                // if returned null, means, there is nothing to update and we just wanted to delete the value
                if (itemBlittable == null)
                {
                    items.DeleteByKey(valueNameLowered);
                    result = GetResult();
                    return;
                }

                // here we get the item key again, in case it was changed (a new entity, etc)
                itemKey = GetItemId();
            }

            using (Slice.From(context.Allocator, itemKey, out Slice valueName))
                using (Slice.From(context.Allocator, itemKey.ToLowerInvariant(), out Slice valueNameLowered))
                {
                    ClusterStateMachine.UpdateValue(index, items, valueNameLowered, valueName, itemBlittable);
                    result = GetResult();
                }
        }
Esempio n. 2
0
        public long FindFreeId(ClusterOperationContext context, long subscriptionId)
        {
            if (SubscriptionId.HasValue)
            {
                return(SubscriptionId.Value);
            }

            bool idTaken;

            do
            {
                idTaken = false;
                foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(context,
                                                                                    SubscriptionState.SubscriptionPrefix(DatabaseName)))
                {
                    if (keyValue.Value.TryGet(nameof(SubscriptionState.SubscriptionId), out long id) == false)
                    {
                        continue;
                    }

                    if (id == subscriptionId)
                    {
                        subscriptionId--; //  we don't care if this end up as a negative value, we need only to be unique
                        idTaken = true;
                        break;
                    }
                }
            } while (idTaken);

            return(subscriptionId);
        }
Esempio n. 3
0
        public void RecomputeChangesStatesAsExpected()
        {
            var clusterState = new ClusterStateMachine();
            var cfg          = new ClusterStateRecomputeConfiguration()
            {
                // Force recompute to run
                RecomputeFrequency = TimeSpan.Zero,
            };

            var nowUtc = _clock.UtcNow;

            // We want to test all possible state machine transitions. To do so, we generate a very specific instance
            // of cluster state meant to transition the way we expect instead of actually simulating each possible
            // branch.

            var       n1 = MachineLocation.Create("node2", 0);
            MachineId n1Id;

            (clusterState, n1Id) = clusterState.ForceRegisterMachineWithState(n1, nowUtc, MachineState.DeadUnavailable);

            var       n2 = MachineLocation.Create("node3", 0);
            MachineId n2Id;

            (clusterState, n2Id) = clusterState.ForceRegisterMachineWithState(n2, nowUtc, MachineState.DeadExpired);

            var       n3 = MachineLocation.Create("node4", 0);
            MachineId n3Id;

            (clusterState, n3Id) = clusterState.ForceRegisterMachineWithState(n3, nowUtc - cfg.ActiveToDeadExpiredInterval, MachineState.Open);

            var       n4 = MachineLocation.Create("node5", 0);
            MachineId n4Id;

            (clusterState, n4Id) = clusterState.ForceRegisterMachineWithState(n4, nowUtc - cfg.ActiveToClosedInterval, MachineState.Open);

            var       n5 = MachineLocation.Create("node6", 0);
            MachineId n5Id;

            (clusterState, n5Id) = clusterState.ForceRegisterMachineWithState(n5, nowUtc, MachineState.Open);

            var       n6 = MachineLocation.Create("node7", 0);
            MachineId n6Id;

            (clusterState, n6Id) = clusterState.ForceRegisterMachineWithState(n6, nowUtc - cfg.ClosedToDeadExpiredInterval, MachineState.Closed);

            var       n7 = MachineLocation.Create("node8", 0);
            MachineId n7Id;

            (clusterState, n7Id) = clusterState.ForceRegisterMachineWithState(n7, nowUtc, MachineState.Closed);

            clusterState = clusterState.Recompute(cfg, nowUtc);

            clusterState.GetStatus(n1Id).ThrowIfFailure().State.Should().Be(MachineState.DeadUnavailable);
            clusterState.GetStatus(n2Id).ThrowIfFailure().State.Should().Be(MachineState.DeadExpired);
            clusterState.GetStatus(n3Id).ThrowIfFailure().State.Should().Be(MachineState.DeadExpired);
            clusterState.GetStatus(n4Id).ThrowIfFailure().State.Should().Be(MachineState.Closed);
            clusterState.GetStatus(n5Id).ThrowIfFailure().State.Should().Be(MachineState.Open);
            clusterState.GetStatus(n6Id).ThrowIfFailure().State.Should().Be(MachineState.DeadExpired);
            clusterState.GetStatus(n7Id).ThrowIfFailure().State.Should().Be(MachineState.Closed);
        }
Esempio n. 4
0
        public void Test_InvalidTopology()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterException    cex     = null;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Primary, out localState,
                                                                    ex => cex = ex);

            var remoteState = new NodeState {
                Role = NodeRole.Primary, Status = NodeStatus.Connecting
            };

            machine.RaiseEvent(localState, machine.PartnerStatusReceived, remoteState);
            Assert.AreEqual(ClusterFailureReason.InvalidTopology, cex.Reason);
            Assert.AreEqual("Stopped", stateChanged.Previous.Name);
            Assert.AreEqual("Final", stateChanged.Current.Name);

            machine = CreateClusterStateMachine(observer, NodeRole.Backup, out localState, ex => cex = ex);

            remoteState = new NodeState {
                Role = NodeRole.Backup, Status = NodeStatus.Connecting
            };
            machine.RaiseEvent(localState, machine.PartnerStatusReceived, remoteState);
            Assert.AreEqual(ClusterFailureReason.InvalidTopology, cex.Reason);
            Assert.AreEqual("Stopped", stateChanged.Previous.Name);
            Assert.AreEqual("Final", stateChanged.Current.Name);
        }
Esempio n. 5
0
        public void Test_SplitBrain_Backup()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterException    cex     = null;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Backup, out localState,
                                                                    ex => cex = ex);
            var newState = new InstanceState
            {
                CurrentState = machine.Active,
                Role         = NodeRole.Backup,
                Status       = NodeStatus.Active
            };

            machine.TransitionToState(newState, machine.Active);

            var remoteState = new NodeState {
                Role = NodeRole.Primary, Status = NodeStatus.Active
            };

            machine.RaiseEvent(newState, machine.PartnerStatusReceived, remoteState);

            Assert.AreEqual(ClusterFailureReason.SplitBrain, cex.Reason);
            Assert.AreEqual("Stopped", stateChanged.Previous.Name);
            Assert.AreEqual("Final", stateChanged.Current.Name);
        }
Esempio n. 6
0
        public void RavenDB_13724()
        {
            var folder = NewDataPath(forceCreateDir: true, prefix: Guid.NewGuid().ToString());

            DoNotReuseServer();

            var zipPath = new PathSetting("SchemaUpgrade/Issues/SystemVersion/RavenDB_13724.zip");

            Assert.True(File.Exists(zipPath.FullPath));

            ZipFile.ExtractToDirectory(zipPath.FullPath, folder);

            using (var server = GetNewServer(new ServerCreationOptions {
                DeletePrevious = false, RunInMemory = false, DataDirectory = folder, RegisterForDisposal = false
            }))
                using (server.ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                    using (context.OpenReadTransaction())
                    {
                        var db  = server.ServerStore.Cluster.GetDatabaseNames(context).Single();
                        var ids = new HashSet <long>();
                        foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(context, SubscriptionState.SubscriptionPrefix(db)))
                        {
                            var state = JsonDeserializationClient.SubscriptionState(keyValue.Value);
                            Assert.True(ids.Add(state.SubscriptionId));
                        }
                    }
        }
Esempio n. 7
0
        public void RegisterMachineTransitionTests()
        {
            var clusterState = new ClusterStateMachine();
            var nowUtc       = _clock.UtcNow;

            // During transition, all machines will be added forcefully without regard for the consistency of the data
            // structure
            clusterState = clusterState.ForceRegisterMachine(new MachineId(3), MachineLocation.Create("A", 0), nowUtc);
            clusterState.NextMachineId.Should().Be(4);

            clusterState = clusterState.ForceRegisterMachine(new MachineId(8), MachineLocation.Create("B", 0), nowUtc);
            clusterState.NextMachineId.Should().Be(9);

            clusterState = clusterState.ForceRegisterMachine(new MachineId(16), MachineLocation.Create("C", 0), nowUtc);
            clusterState.NextMachineId.Should().Be(17);

            clusterState = clusterState.ForceRegisterMachine(new MachineId(20), MachineLocation.Create("D", 0), nowUtc);
            clusterState.NextMachineId.Should().Be(21);

            clusterState = clusterState.ForceRegisterMachine(new MachineId(23), MachineLocation.Create("D", 0), nowUtc);
            clusterState.NextMachineId.Should().Be(24);

            // After transition, adding proceeds as usual, by appending to the end basically
            MachineId n1Id;

            (clusterState, n1Id) = clusterState.RegisterMachine(MachineLocation.Create("Machine Gets Added After Transition", 0), nowUtc);
            n1Id.Index.Should().Be(24);
            clusterState.NextMachineId.Should().Be(25);
        }
Esempio n. 8
0
        public override unsafe void Execute(TransactionOperationContext context, Table items, long index, DatabaseRecord record, RachisState state, out object result)
        {
            result = null;

            var itemKey = SubscriptionState.GenerateSubscriptionItemKeyName(DatabaseName, SubscriptionName);

            using (Slice.From(context.Allocator, itemKey.ToLowerInvariant(), out Slice valueNameLowered))
                using (Slice.From(context.Allocator, itemKey, out Slice valueName))
                {
                    if (items.ReadByKey(valueNameLowered, out var tvr) == false)
                    {
                        throw new RachisApplyException($"Cannot find subscription {index}");
                    }

                    var ptr = tvr.Read(2, out int size);
                    var doc = new BlittableJsonReaderObject(ptr, size, context);

                    var subscriptionState = JsonDeserializationClient.SubscriptionState(doc);
                    subscriptionState.Disabled = Disable;
                    using (var obj = context.ReadObject(subscriptionState.ToJson(), "subscription"))
                    {
                        ClusterStateMachine.UpdateValue(index, items, valueNameLowered, valueName, obj);
                    }
                }
        }
Esempio n. 9
0
        public override unsafe void Execute(TransactionOperationContext context, Table items, long index, DatabaseRecord record, bool isPassive, out object result)
        {
            result = null;
            var subscriptionId = SubscriptionId ?? index;

            SubscriptionName = string.IsNullOrEmpty(SubscriptionName) ? subscriptionId.ToString() : SubscriptionName;
            var receivedSubscriptionState = context.ReadObject(new SubscriptionState
            {
                Query = Query,
                ChangeVectorForNextBatchStartingPoint = InitialChangeVector,
                SubscriptionId   = subscriptionId,
                SubscriptionName = SubscriptionName,
                LastTimeServerMadeProgressWithDocuments = DateTime.UtcNow,
                Disabled = Disabled,
                LastClientConnectionTime = DateTime.Now
            }.ToJson(), SubscriptionName);
            BlittableJsonReaderObject modifiedSubscriptionState = null;

            try
            {
                string subscriptionItemName = SubscriptionState.GenerateSubscriptionItemKeyName(DatabaseName, SubscriptionName);

                using (Slice.From(context.Allocator, subscriptionItemName, out Slice valueName))
                    using (Slice.From(context.Allocator, subscriptionItemName.ToLowerInvariant(), out Slice valueNameLowered))
                    {
                        if (items.ReadByKey(valueNameLowered, out TableValueReader tvr))
                        {
                            var ptr = tvr.Read(2, out int size);
                            var doc = new BlittableJsonReaderObject(ptr, size, context);

                            var existingSubscriptionState = JsonDeserializationClient.SubscriptionState(doc);

                            if (SubscriptionId != existingSubscriptionState.SubscriptionId)
                            {
                                throw new InvalidOperationException("A subscription could not be modified because the name '" + subscriptionItemName +
                                                                    "' is already in use in a subscription with different Id.");
                            }

                            if (Enum.TryParse(InitialChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorState) && changeVectorState == Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange)
                            {
                                if (receivedSubscriptionState.Modifications == null)
                                {
                                    receivedSubscriptionState.Modifications = new DynamicJsonValue();
                                }

                                receivedSubscriptionState.Modifications[nameof(SubscriptionState.ChangeVectorForNextBatchStartingPoint)] = existingSubscriptionState.ChangeVectorForNextBatchStartingPoint;
                                modifiedSubscriptionState = context.ReadObject(receivedSubscriptionState, SubscriptionName);
                            }
                        }

                        ClusterStateMachine.UpdateValue(subscriptionId, items, valueNameLowered, valueName, modifiedSubscriptionState ?? receivedSubscriptionState);
                    }
            }
            finally
            {
                receivedSubscriptionState.Dispose();
                modifiedSubscriptionState?.Dispose();
            }
        }
Esempio n. 10
0
 public long GetAllSubscriptionsCount()
 {
     using (_serverStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
         using (context.OpenReadTransaction())
         {
             return(ClusterStateMachine.ReadValuesStartingWith(context, SubscriptionState.SubscriptionPrefix(_db.Name))
                    .Count());
         }
 }
Esempio n. 11
0
        public void Test_Start_When_Initial()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Primary, out localState);

            Assert.AreEqual("Initial", stateChanged.Previous.Name);
            Assert.AreEqual("Connecting", stateChanged.Current.Name);
        }
Esempio n. 12
0
        public override unsafe void Execute(TransactionOperationContext context, Table items, long index, DatabaseRecord record, RachisState state, out object result)
        {
            result = null;
            var subscriptionId = SubscriptionId ?? index;

            SubscriptionName = string.IsNullOrEmpty(SubscriptionName) ? subscriptionId.ToString() : SubscriptionName;

            var subscriptionItemName = SubscriptionState.GenerateSubscriptionItemKeyName(DatabaseName, SubscriptionName);

            using (Slice.From(context.Allocator, subscriptionItemName, out Slice valueName))
                using (Slice.From(context.Allocator, subscriptionItemName.ToLowerInvariant(), out Slice valueNameLowered))
                {
                    if (items.ReadByKey(valueNameLowered, out TableValueReader tvr))
                    {
                        var ptr = tvr.Read(2, out int size);
                        var doc = new BlittableJsonReaderObject(ptr, size, context);

                        var existingSubscriptionState = JsonDeserializationClient.SubscriptionState(doc);

                        if (SubscriptionId != existingSubscriptionState.SubscriptionId)
                        {
                            throw new RachisApplyException("A subscription could not be modified because the name '" + subscriptionItemName +
                                                           "' is already in use in a subscription with different Id.");
                        }

                        if (string.IsNullOrEmpty(InitialChangeVector) == false && InitialChangeVector == nameof(Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange))
                        {
                            InitialChangeVector = existingSubscriptionState.ChangeVectorForNextBatchStartingPoint;
                        }
                        else
                        {
                            AssertValidChangeVector();
                        }
                    }
                    else
                    {
                        AssertValidChangeVector();
                    }

                    using (var receivedSubscriptionState = context.ReadObject(new SubscriptionState
                    {
                        Query = Query,
                        ChangeVectorForNextBatchStartingPoint = InitialChangeVector,
                        SubscriptionId = subscriptionId,
                        SubscriptionName = SubscriptionName,
                        LastBatchAckTime = null,
                        Disabled = Disabled,
                        MentorNode = MentorNode,
                        LastClientConnectionTime = null
                    }.ToJson(), SubscriptionName))
                    {
                        ClusterStateMachine.UpdateValue(subscriptionId, items, valueNameLowered, valueName, receivedSubscriptionState);
                    }
                }
        }
Esempio n. 13
0
        public void FullBackupTo(string backupPath)
        {
            using (var file = new FileStream(backupPath, FileMode.Create))
                using (var package = new ZipArchive(file, ZipArchiveMode.Create, leaveOpen: true))
                    using (_serverStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                        using (context.OpenReadTransaction())
                        {
                            var databaseRecord = _serverStore.Cluster.ReadDatabase(context, Name);
                            Debug.Assert(databaseRecord != null);

                            var zipArchiveEntry = package.CreateEntry(RestoreSettings.FileName, CompressionLevel.Optimal);
                            using (var zipStream = zipArchiveEntry.Open())
                                using (var writer = new BlittableJsonTextWriter(context, zipStream))
                                {
                                    //TODO: encrypt this file using the MasterKey
                                    //http://issues.hibernatingrhinos.com/issue/RavenDB-7546

                                    writer.WriteStartObject();

                                    // save the database record
                                    writer.WritePropertyName(nameof(RestoreSettings.DatabaseRecord));
                                    var databaseRecordBlittable = EntityToBlittable.ConvertEntityToBlittable(databaseRecord, DocumentConventions.Default, context);
                                    context.Write(writer, databaseRecordBlittable);

                                    // save the database values (subscriptions, periodic backups statuses, etl states...)
                                    writer.WriteComma();
                                    writer.WritePropertyName(nameof(RestoreSettings.DatabaseValues));
                                    writer.WriteStartObject();

                                    var first = true;
                                    foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(context,
                                                                                                        Helpers.ClusterStateMachineValuesPrefix(Name)))
                                    {
                                        if (first == false)
                                        {
                                            writer.WriteComma();
                                        }

                                        first = false;

                                        writer.WritePropertyName(keyValue.Key.ToString());
                                        context.Write(writer, keyValue.Value);
                                    }
                                    writer.WriteEndObject();
                                    // end of dictionary

                                    writer.WriteEndObject();
                                }

                            BackupMethods.Full.ToFile(GetAllStoragesEnvironmentInformation(), package);

                            file.Flush(true); // make sure that we fully flushed to disk
                        }
        }
Esempio n. 14
0
 public IEnumerable <SubscriptionGeneralDataAndStats> GetAllSubscriptions(TransactionOperationContext serverStoreContext, bool history, int start, int take)
 {
     foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(serverStoreContext,
                                                                         SubscriptionState.SubscriptionPrefix(_db.Name)))
     {
         var subscriptionState       = JsonDeserializationClient.SubscriptionState(keyValue.Value);
         var subscriptionGeneralData = new SubscriptionGeneralDataAndStats(subscriptionState);
         GetSubscriptionInternal(subscriptionGeneralData, history);
         yield return(subscriptionGeneralData);
     }
 }
Esempio n. 15
0
        public void Test_Primary_BecomeStandAlone_WhenInitialConnectToBackup_Fails()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Primary, out localState, becomeActiveWhenPrimaryOnInitialConnectionTimeout: true);

            machine.RaiseEvent(localState, machine.LostPartner, localState);

            Assert.AreEqual("Connecting", stateChanged.Previous.Name);
            Assert.AreEqual("Active", stateChanged.Current.Name);
        }
Esempio n. 16
0
        private static ClusterStateMachine CreateClusterStateMachine(MockStateObserver observer, NodeRole role,
                                                                     out InstanceState localState, Action <ClusterException> clusterExceptionAction = null, bool becomeActiveWhenPrimaryOnInitialConnectionTimeout = false)
        {
            var machine = new ClusterStateMachine(clusterExceptionAction ?? Assert.IsNull, s => true, becomeActiveWhenPrimaryOnInitialConnectionTimeout);

            machine.StateChanged.Subscribe(observer);
            localState = new InstanceState {
                Role = role
            };
            machine.RaiseEvent(localState, machine.Start);
            return(machine);
        }
Esempio n. 17
0
        public void HeartbeatDoesntChangeRecomputeTime()
        {
            var       clusterState = new ClusterStateMachine();
            MachineId n1Id;

            (clusterState, n1Id) = clusterState.RegisterMachine(new MachineLocation("node1"), _clock.UtcNow);

            _clock.Increment(TimeSpan.FromMinutes(1));
            clusterState = clusterState.Heartbeat(n1Id, _clock.UtcNow, MachineState.Open).ThrowIfFailure().Next;

            clusterState.LastStateMachineRecomputeTimeUtc.Should().Be(DateTime.MinValue);
        }
Esempio n. 18
0
        public void RegisterMachineEmitsIdsInSequence()
        {
            var       clusterState = new ClusterStateMachine();
            var       nowUtc       = _clock.UtcNow;
            MachineId machineId;

            (clusterState, machineId) = clusterState.RegisterMachine(new MachineLocation("node1"), nowUtc);
            machineId.Index.Should().Be(1);

            (_, machineId) = clusterState.RegisterMachine(new MachineLocation("node2"), nowUtc);
            machineId.Index.Should().Be(2);
        }
Esempio n. 19
0
        public static ClusterManager Create(DocumentDatabase systemDatabase, DatabasesLandlord databasesLandlord)
        {
            if (systemDatabase == null)
            {
                throw new ArgumentNullException("systemDatabase");
            }

            if (databasesLandlord == null)
            {
                throw new ArgumentNullException("databasesLandlord");
            }

            DatabaseHelper.AssertSystemDatabase(systemDatabase);

            var configuration      = systemDatabase.Configuration;
            var nodeConnectionInfo = CreateSelfConnection(systemDatabase);

            StorageEnvironmentOptions options;

            if (configuration.Core.RunInMemory == false)
            {
                var directoryPath = Path.Combine(configuration.Core.DataDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "Raft");
                if (Directory.Exists(directoryPath) == false)
                {
                    Directory.CreateDirectory(directoryPath);
                }

                options = StorageEnvironmentOptions.ForPath(directoryPath);
            }
            else
            {
                options = StorageEnvironmentOptions.CreateMemoryOnly(configuration.Storage.TempPath);
            }

            var transport         = new HttpTransport(nodeConnectionInfo.Name, systemDatabase.WorkContext.CancellationToken);
            var stateMachine      = new ClusterStateMachine(systemDatabase, databasesLandlord);
            var raftEngineOptions = new RaftEngineOptions(nodeConnectionInfo, options, transport, stateMachine)
            {
                ElectionTimeout              = (int)configuration.Cluster.ElectionTimeout.AsTimeSpan.TotalMilliseconds,
                HeartbeatTimeout             = (int)configuration.Cluster.HeartbeatTimeout.AsTimeSpan.TotalMilliseconds,
                MaxLogLengthBeforeCompaction = configuration.Cluster.MaxLogLengthBeforeCompaction,
                MaxEntriesPerRequest         = configuration.Cluster.MaxEntriesPerRequest,
                MaxStepDownDrainTime         = configuration.Cluster.MaxStepDownDrainTime.AsTimeSpan
            };
            var raftEngine = new RaftEngine(raftEngineOptions);

            stateMachine.RaftEngine = raftEngine;

            return(new ClusterManager(raftEngine));
        }
Esempio n. 20
0
        public void HeartbeatUpdatesLastHeartbeatTimeAndState()
        {
            var       clusterState = new ClusterStateMachine();
            MachineId machineId;

            (clusterState, machineId) = clusterState.RegisterMachine(new MachineLocation("node1"), _clock.UtcNow);

            _clock.Increment(TimeSpan.FromMinutes(1));
            clusterState = clusterState.Heartbeat(machineId, _clock.UtcNow, MachineState.Open).ThrowIfFailure().Next;

            var r = clusterState.GetStatus(machineId).ShouldBeSuccess().Value;

            r.LastHeartbeatTimeUtc.Should().Be(_clock.UtcNow);
            r.State.Should().Be(MachineState.Open);
        }
Esempio n. 21
0
        public static List <string> GetDatabases(UpdateStep step)
        {
            var dbs = new List <string>();

            using (var items = step.ReadTx.OpenTable(ClusterStateMachine.ItemsSchema, ClusterStateMachine.Items))
                using (Slice.From(step.ReadTx.Allocator, DbKey, out var loweredPrefix))
                {
                    foreach (var result in items.SeekByPrimaryKeyPrefix(loweredPrefix, Slices.Empty, 0))
                    {
                        dbs.Add(ClusterStateMachine.GetCurrentItemKey(result.Value).Substring(DbKey.Length));
                    }
                }

            return(dbs);
        }
Esempio n. 22
0
        public void Test_Backup_Found_Primary()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Backup, out localState);

            var remoteState = new NodeState {
                Role = NodeRole.Primary, Status = NodeStatus.Connecting
            };

            machine.RaiseEvent(localState, machine.PartnerStatusReceived, remoteState);

            Assert.AreEqual("Connecting", stateChanged.Previous.Name);
            Assert.AreEqual("Passive", stateChanged.Current.Name);
        }
Esempio n. 23
0
        private static long GetSubscriptionCountOnNode(DocumentDatabase database, DatabaseRecord dbRecord, ServerStore serverStore, TransactionOperationContext context)
        {
            long taskCountOnNode = 0;

            foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(context, SubscriptionState.SubscriptionPrefix(database.Name)))
            {
                var subscriptionState = JsonDeserializationClient.SubscriptionState(keyValue.Value);
                var taskTag           = database.WhoseTaskIsIt(dbRecord.Topology, subscriptionState, subscriptionState);
                if (serverStore.NodeTag == taskTag)
                {
                    taskCountOnNode++;
                }
            }

            return(taskCountOnNode);
        }
Esempio n. 24
0
        public void RecomputeDoesntRunIfNotNeeded()
        {
            var now     = _clock.UtcNow;
            var current = new ClusterStateMachine()
            {
                LastStateMachineRecomputeTimeUtc = now,
            };

            var cfg = new ClusterStateRecomputeConfiguration()
            {
                RecomputeFrequency = TimeSpan.FromMilliseconds(1),
            };

            var next = current.Recompute(cfg, now);

            next.Should().BeEquivalentTo(current);
        }
Esempio n. 25
0
        internal static bool UpdateCertificatesTableInternal(UpdateStep step)
        {
            var schema = ClusterStateMachine.CertificatesSchema;

            var readCertsTable  = step.ReadTx.OpenTable(schema, ClusterStateMachine.CertificatesSlice);
            var writeCertsTable = step.WriteTx.OpenTable(schema, ClusterStateMachine.CertificatesSlice);

            using (var context = JsonOperationContext.ShortTermSingleUse())
            {
                foreach (var cert in readCertsTable.SeekByPrimaryKey(Slices.Empty, 0))
                {
                    (string key, BlittableJsonReaderObject doc) = GetCurrentItem(step.WriteTx, context, cert);

                    using (doc)
                    {
                        var def = JsonDeserializationServer.CertificateDefinition(doc);
                        From11.DropCertificatePrefixFromDefinition(def, out var touched);

                        var loweredKey = key.ToLowerInvariant();

                        if (loweredKey != key)
                        {
                            // we have upper cased key (thumbprint)
                            // let's remove current record from table and force writing it again with lower cased key value

                            using (Slice.From(step.WriteTx.Allocator, key, out Slice keySlice))
                                writeCertsTable.DeleteByKey(keySlice);

                            touched = true;
                        }

                        if (touched)
                        {
                            using (Slice.From(step.WriteTx.Allocator, def.PublicKeyPinningHash, out Slice hashSlice))
                                using (Slice.From(step.WriteTx.Allocator, loweredKey, out Slice keySlice))
                                    using (var newCert = context.ReadObject(def.ToJson(), "certificate/updated"))
                                    {
                                        ClusterStateMachine.UpdateCertificate(writeCertsTable, keySlice, hashSlice, newCert);
                                    }
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 26
0
        public string GetSubscriptionNameById(TransactionOperationContext serverStoreContext, long id)
        {
            foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(serverStoreContext,
                                                                                SubscriptionState.SubscriptionPrefix(_db.Name)))
            {
                if (keyValue.Value.TryGet(nameof(SubscriptionState.SubscriptionId), out long _id) == false)
                {
                    continue;
                }
                if (_id == id)
                {
                    if (keyValue.Value.TryGet(nameof(SubscriptionState.SubscriptionName), out string name))
                    {
                        return(name);
                    }
                }
            }

            return(null);
        }
Esempio n. 27
0
        public void Test_LostPartner_During_Any_Should_LogException()
        {
            StateChanged <InstanceState> stateChanged = null;
            var                 observer = new MockStateObserver(s => stateChanged = s, Assert.IsNull);
            InstanceState       localState;
            ClusterException    cex     = null;
            ClusterStateMachine machine = CreateClusterStateMachine(observer, NodeRole.Primary, out localState,
                                                                    ex => cex = ex);

            var remoteState = new NodeState {
                Role = NodeRole.Backup, Status = NodeStatus.Passive
            };

            machine.RaiseEvent(localState, machine.PartnerStatusReceived, remoteState);

            machine.RaiseEvent(localState, machine.LostPartner, localState);
            Assert.AreEqual(ClusterFailureReason.LostPartner, cex.Reason);
            Assert.AreEqual("Connecting", stateChanged.Previous.Name);
            Assert.AreEqual("Active", stateChanged.Current.Name);
        }
Esempio n. 28
0
        public void HeartbeatKeepsOtherRecordsAsIs()
        {
            var clusterState = new ClusterStateMachine();
            var nowUtc       = _clock.UtcNow;

            MachineId n1Id;

            (clusterState, n1Id) = clusterState.RegisterMachine(new MachineLocation("node1"), nowUtc);

            MachineId n2Id;

            (clusterState, n2Id) = clusterState.RegisterMachine(new MachineLocation("node2"), nowUtc);

            _clock.Increment(TimeSpan.FromMinutes(1));
            clusterState = clusterState.Heartbeat(n1Id, _clock.UtcNow, MachineState.Closed).ThrowIfFailure().Next;

            var r = clusterState.GetStatus(n2Id).ShouldBeSuccess().Value;

            r.LastHeartbeatTimeUtc.Should().Be(nowUtc);
            r.State.Should().Be(MachineState.Open);
        }
Esempio n. 29
0
        public void RegisterNewMachineUsesCorrectDefaults()
        {
            var       clusterState = new ClusterStateMachine();
            var       nowUtc       = _clock.UtcNow;
            MachineId machineId;

            var machineLocation = new MachineLocation("node1");

            (clusterState, machineId) = clusterState.RegisterMachine(machineLocation, nowUtc);
            machineId.Index.Should().Be(MachineId.MinValue);

            var record = clusterState.GetStatus(machineId).ThrowIfFailure();

            record.Should().BeEquivalentTo(new MachineRecord()
            {
                Id                   = new MachineId(MachineId.MinValue),
                Location             = machineLocation,
                State                = ClusterStateMachine.InitialState,
                LastHeartbeatTimeUtc = nowUtc,
            });
        }
Esempio n. 30
0
        private IEnumerable <OngoingTask> CollectSubscriptionTasks(TransactionOperationContext context, DatabaseRecord databaseRecord, ClusterTopology clusterTopology)
        {
            foreach (var keyValue in ClusterStateMachine.ReadValuesStartingWith(context, SubscriptionState.SubscriptionPrefix(databaseRecord.DatabaseName)))
            {
                var subscriptionState = JsonDeserializationClient.SubscriptionState(keyValue.Value);
                var tag = databaseRecord.Topology.WhoseTaskIsIt(subscriptionState, ServerStore.Engine.CurrentState);

                yield return(new OngoingTaskSubscription
                {
                    // Supply only needed fields for List View
                    ResponsibleNode = new NodeId
                    {
                        NodeTag = tag,
                        NodeUrl = clusterTopology.GetUrlFromTag(tag)
                    },
                    TaskName = subscriptionState.SubscriptionName,
                    TaskState = subscriptionState.Disabled ? OngoingTaskState.Disabled : OngoingTaskState.Enabled,
                    TaskId = subscriptionState.SubscriptionId,
                    Query = subscriptionState.Query
                });
            }
        }
 private static ClusterStateMachine CreateClusterStateMachine(MockStateObserver observer, NodeRole role,
     out InstanceState localState, Action<ClusterException> clusterExceptionAction = null)
 {
     var machine = new ClusterStateMachine(clusterExceptionAction ?? Assert.IsNull, s => true);
     machine.StateChanged.Subscribe(observer);
     localState = new InstanceState {Role = role};
     machine.RaiseEvent(localState, machine.Start);
     return machine;
 }
 private static ClusterStateMachine CreateClusterStateMachine(MockStateObserver observer, NodeRole role,
     out InstanceState localState, Action<ClusterException> clusterExceptionAction = null, bool becomeActiveWhenPrimaryOnInitialConnectionTimeout = false)
 {
     var machine = new ClusterStateMachine(clusterExceptionAction ?? Assert.IsNull, s => true, becomeActiveWhenPrimaryOnInitialConnectionTimeout);
     machine.StateChanged.Subscribe(observer);
     localState = new InstanceState { Role = role };
     machine.RaiseEvent(localState, machine.Start);
     return machine;
 }