Example #1
0
        public async void ReplicateCreateOperation()
        {
            Guid recordId = Guid.NewGuid();

            await _shardManager.Handle(new ReplicateShardWriteOperation()
            {
                Operation =
                    new ShardWriteOperation()
                {
                    Id        = Guid.NewGuid().ToString(),
                    Operation = ShardOperationOptions.Create,
                    Data      = new TestData()
                    {
                        ShardId   = TestUtility.DefaultShardId,
                        ShardType = "number",
                        Data      = 100,
                        Id        = recordId
                    },
                    Pos       = 1,
                    ShardHash = ObjectUtility.HashStrings("", recordId.ToString())
                }
            });

            var result = await _shardManager.Handle(
                new RequestDataShard()
            {
                ObjectId = recordId,
                Type     = "number",
            });

            Assert.True(result.IsSuccessful);
            Assert.NotNull(result.Data);
            Assert.Equal(100, ((TestData)result.Data).Data);
        }
Example #2
0
        public async void ConsecutiveReplicationTest()
        {
            Guid   recordId         = Guid.NewGuid();
            string transactionId    = Guid.NewGuid().ToString();
            var    firstTransaction = await _shardManager.Handle(new ReplicateShardWriteOperation()
            {
                Operation = new ShardWriteOperation()
                {
                    Id        = transactionId,
                    Operation = ShardOperationOptions.Create,
                    Pos       = 1,
                    Data      = new TestData()
                    {
                        ShardId   = TestUtility.DefaultShardId,
                        ShardType = "number",
                        Data      = 100,
                        Id        = recordId
                    },
                    ShardHash = ObjectUtility.HashStrings("", transactionId)
                }
            });

            var secondTransactionId = Guid.NewGuid().ToString();
            await _shardManager.Handle(new ReplicateShardWriteOperation()
            {
                Operation = new ShardWriteOperation()
                {
                    Id        = secondTransactionId,
                    Operation = ShardOperationOptions.Update,
                    Pos       = 2,
                    Data      =
                        new TestData()
                    {
                        ShardId   = TestUtility.DefaultShardId,
                        ShardType = "number",
                        Data      = 101,
                        Id        = recordId
                    },
                    ShardHash = ObjectUtility.HashStrings(ObjectUtility.HashStrings("", transactionId), secondTransactionId)
                }
            });

            var result = await _shardManager.Handle(new RequestDataShard()
            {
                ObjectId = recordId,
                Type     = "number"
            });

            Assert.True(result.IsSuccessful);
            Assert.NotNull(result.Data);
            Assert.Equal(101, ((TestData)result.Data).Data);
        }
Example #3
0
        public async Task <WriteShardDataResponse> WriteShardData(ShardData data, ShardOperationOptions operationType, string operationId, DateTime transactionDate)
        {
            ShardWriteOperation operation = new ShardWriteOperation()
            {
                Data            = data,
                Id              = operationId,
                Operation       = operationType,
                TransactionDate = transactionDate
            };

            ShardWriteOperation lastOperation = await GetOrPopulateOperationCache(operation.Data.ShardId.Value);

            //Start at 1
            operation.Pos = lastOperation == null ? 1 : lastOperation.Pos + 1;
            var hash = lastOperation == null ? "" : lastOperation.ShardHash;

            operation.ShardHash = ObjectUtility.HashStrings(hash, operation.Id);
            _logger.LogDebug(_nodeStateService.GetNodeLogId() + "writing new operation " + operationId + " with data " + Environment.NewLine + JsonConvert.SerializeObject(data, Formatting.Indented));
            //Write the data

            var writeOperation = await _shardRepository.AddShardWriteOperationAsync(operation); //Add shard operation

            if (writeOperation)
            {
                ApplyOperationToDatastore(operation);
                var shardMetadata = _stateMachine.GetShard(operation.Data.ShardType, operation.Data.ShardId.Value);
                //Mark operation as applied
                await _shardRepository.MarkShardWriteOperationAppliedAsync(operation.Id);

                //Update the cache
                UpdateOperationCache(operation.Data.ShardId.Value, operation);
                ConcurrentBag <Guid> InvalidNodes = new ConcurrentBag <Guid>();
                //All allocations except for your own
                var tasks = shardMetadata.InsyncAllocations.Where(id => id != _nodeStateService.Id).Select(async allocation =>
                {
                    try
                    {
                        var result = await _clusterClient.Send(allocation, new ReplicateShardWriteOperation()
                        {
                            Operation = operation
                        });

                        if (result.IsSuccessful)
                        {
                            _logger.LogDebug(_nodeStateService.GetNodeLogId() + "Successfully replicated all " + shardMetadata.Id + "shards.");
                        }
                        else
                        {
                            throw new Exception("Failed to replicate data to shard " + shardMetadata.Id + " to node " + allocation + " for operation " + operation.ToString() + Environment.NewLine + JsonConvert.SerializeObject(operation, Formatting.Indented));
                        }
                    }
                    catch (TaskCanceledException e)
                    {
                        _logger.LogError(_nodeStateService.GetNodeLogId() + "Failed to replicate shard " + shardMetadata.Id + " on node " + allocation + " for operation " + operation.Pos + " as request timed out, marking shard as not insync...");
                        InvalidNodes.Add(allocation);
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(_nodeStateService.GetNodeLogId() + "Failed to replicate shard " + shardMetadata.Id + " for operation " + operation.Pos + " with error " + e.Message + ", marking shard as not insync..." + Environment.NewLine + e.StackTrace);
                        InvalidNodes.Add(allocation);
                    }
                });

                await Task.WhenAll(tasks);

                if (InvalidNodes.Count() > 0)
                {
                    await _clusterClient.Send(new ExecuteCommands()
                    {
                        Commands = new List <BaseCommand>()
                        {
                            new UpdateShardMetadataAllocations()
                            {
                                ShardId = data.ShardId.Value,
                                Type    = data.ShardType,
                                StaleAllocationsToAdd     = InvalidNodes.ToHashSet(),
                                InsyncAllocationsToRemove = InvalidNodes.ToHashSet()
                            }
                        },
                        WaitForCommits = true
                    });

                    _logger.LogInformation(_nodeStateService.GetNodeLogId() + " had stale virtual machines.");
                }

                return(new WriteShardDataResponse()
                {
                    Pos = operation.Pos,
                    ShardHash = operation.ShardHash,
                    IsSuccessful = true
                });
            }
            else
            {
                return(new WriteShardDataResponse()
                {
                    IsSuccessful = false
                });
            }
        }
Example #4
0
        public async Task <bool> ReplicateShardWriteOperationAsync(ShardWriteOperation operation)
        {
            // Get the last operation
            ShardWriteOperation lastOperation;
            var startTime = DateTime.Now;

            if (operation.Pos != 1)
            {
                while ((lastOperation = await GetOrPopulateOperationCache(operation.Data.ShardId.Value)) == null || !lastOperation.Applied || lastOperation.Pos < operation.Pos - 1)
                {
                    //Assume in the next 3 seconds you should receive the previos requests
                    if ((DateTime.Now - startTime).TotalMilliseconds > 3000)
                    {
                        return(false);
                    }
                    await Task.Delay(100);
                }

                if (lastOperation.Pos != operation.Pos - 1)
                {
                    lastOperation = await _shardRepository.GetShardWriteOperationAsync(operation.Data.ShardId.Value, operation.Pos - 1);
                }

                string newHash;
                if ((newHash = ObjectUtility.HashStrings(lastOperation.ShardHash, operation.Id)) != operation.ShardHash)
                {
                    //Critical error with data concurrency, revert back to last known good commit via the resync process
                    _logger.LogError(_nodeStateService.GetNodeLogId() + "Failed to check the hash for operation " + operation.Id + ", marking shard as out of sync...");
                    throw new Exception(_nodeStateService.GetNodeLogId() + "Failed to check the hash for operation " + operation.Id + ", marking shard as out of sync...");
                }
            }

            // if (operation.Pos > 1)
            //{
            //   lock (_shardLastOperationCache[operation.Data.ShardId.Value])
            //  {
            //The operation must already be being applied

            /* if (_shardLastOperationCache[operation.Data.ShardId.Value].Pos >= operation.Pos)
             * {
             *   throw new Exception("There must be a replication process being run");
             * }*/

            _shardRepository.AddShardWriteOperationAsync(operation).GetAwaiter().GetResult();
            //Run shard operation
            ApplyOperationToDatastore(operation);
            _shardRepository.MarkShardWriteOperationAppliedAsync(operation.Id).GetAwaiter().GetResult();
            //Update the cache
            UpdateOperationCache(operation.Data.ShardId.Value, operation);
            //}

            /* }
             * else
             * {
             *   await _shardRepository.AddShardWriteOperationAsync(operation);
             *   //Run shard operation
             *   ApplyOperationToDatastore(operation);
             *   await _shardRepository.MarkShardWriteOperationAppliedAsync(operation.Id);
             *   //Update the cache
             *   UpdateOperationCache(operation.Data.ShardId.Value, operation);
             * }*/

            return(true);
        }