public WriteCache(IOperationCacheRepository transactionCacheRepository, ILogger <WriteCache> logger, bool persistToDisk = true) { _operationCacheRepository = transactionCacheRepository; _logger = logger; _persistToDisk = persistToDisk; //Load persistent queue into memory if (_persistToDisk) { _logger.LogDebug("Loading transactions to queue..."); OperationQueue = _operationCacheRepository.GetOperationQueueAsync().GetAwaiter().GetResult().ToList(); TransitQueue = _operationCacheRepository.GetTransitQueueAsync().GetAwaiter().GetResult().ToList().ToDictionary(swo => swo.Id, swo => swo); } else { _logger.LogWarning("Queue has been set to transient mode. Queue data will not be persisted to disk"); } }
public DataService( ILoggerFactory loggerFactory, IShardRepository shardRepository, IDataRouter dataRouter, IStateMachine <State> stateMachine, NodeStateService nodeStateService, ClusterClient clusterClient, IOptions <ClusterOptions> clusterOptions, IOperationCacheRepository transactionCacheRepository, IOptions <NodeOptions> nodeOptions) { _nodeStateService = nodeStateService; _nodeOptions = nodeOptions.Value; _clusterOptions = clusterOptions.Value; _stateMachine = stateMachine; _writeCache = new WriteCache(transactionCacheRepository, loggerFactory.CreateLogger <WriteCache>(), _nodeOptions.PersistWriteQueue); _logger = loggerFactory.CreateLogger <DataService <State> >(); _shardRepository = shardRepository; _clusterClient = clusterClient; Reader = new Reader <State>( loggerFactory.CreateLogger <Reader <State> >(), shardRepository, dataRouter, stateMachine, nodeStateService, clusterClient);; Allocator = new Allocator <State>( loggerFactory.CreateLogger <Allocator <State> >(), shardRepository, dataRouter, stateMachine, nodeStateService, clusterClient); Writer = new Writer <State>(loggerFactory.CreateLogger <Writer <State> >(), shardRepository, dataRouter, stateMachine, nodeStateService, clusterClient ); Syncer = new Syncer <State>(shardRepository, loggerFactory.CreateLogger <Syncer <State> >(), stateMachine, clusterClient, nodeStateService, Writer); _writeTask = new Task(async() => { //Before you write you should first dequeue all transactions if (_writeCache.TransitQueue.Count() > 0) { _logger.LogInformation("Found transactions in transit, attempting to reapply them..."); foreach (var operationKV in _writeCache.TransitQueue.ToDictionary(entry => entry.Key, entry => entry.Value)) { var operation = operationKV.Value; try { var result = await Writer.WriteShardData(operation.Data, operation.Operation, operation.Id, operation.TransactionDate); } catch (Exception e) { _logger.LogError("Failed to apply operation " + operation.Id + " with exception " + e.Message + Environment.NewLine + e.StackTrace); try { await _writeCache.CompleteOperation(operation.Id); } catch (Exception completionError) { _logger.LogError("Error removing operation from transit queue with error " + completionError.Message + Environment.NewLine + completionError.StackTrace + Environment.NewLine + JsonConvert.SerializeObject(operation, Formatting.Indented)); } } } } while (true) { try { var operation = await _writeCache.DequeueOperation(); if (operation != null) { try { var result = await Writer.WriteShardData(operation.Data, operation.Operation, operation.Id, operation.TransactionDate); } catch (Exception e) { _logger.LogError("Failed to write operation with exception " + e.Message + Environment.NewLine + JsonConvert.SerializeObject(operation, Formatting.Indented)); } await _writeCache.CompleteOperation(operation.Id); } else { //Release write thread for a small amount of time await Task.Delay(100); } } catch (Exception e) { _logger.LogError("Encountered critical write error " + e.Message + Environment.NewLine + e.StackTrace); } } }); _writeTask.Start(); TaskUtility.RestartTask(ref _indexCreationTask, async() => await CreateIndexLoop()); _allocationTask = new Task(async() => await AllocateShards()); _allocationTask.Start(); _replicaValidationChecksTask = Task.Run(async() => await CheckAllReplicas()); _objectLockWatcher = new Task(async() => await CheckLocks()); _objectLockWatcher.Start(); if (_nodeOptions.EnablePerformanceLogging) { var performancePrinting = new Task(() => { while (true) { Console.Clear(); Console.WriteLine("Performance Report..."); foreach (var value in totals) { Console.WriteLine(value.Key + ":" + (value.Value / totalRequests)); } Console.WriteLine("Queue:" + _writeCache.OperationsInQueue); Task.Delay(1000); } }); performancePrinting.Start(); } }