private void LoadEventIndexData() { var chunks = _eventIndexChunkManager.GetAllChunks(); var count = 0L; var stopWatch = new Stopwatch(); var totalStopWatch = new Stopwatch(); totalStopWatch.Start(); foreach (Chunk chunk in chunks) { stopWatch.Restart(); _logger.Info(chunk); var dataPosition = chunk.ChunkHeader.ChunkDataStartPosition; var recordQueue = new Queue <IndexRecord>(); while (true) { var record = _eventIndexChunkReader.TryReadAt(dataPosition, ReadIndexRecord, false); if (record == null) { break; } if (string.IsNullOrEmpty(record.IndexInfo)) { continue; } var indexArray = record.IndexInfo.Split(IndexSeparator); foreach (var index in indexArray) { if (string.IsNullOrEmpty(index)) { continue; } var itemArray = index.Split(IndexContentSeparator); var aggregateRootId = itemArray[0]; _aggregateLatestVersionDict[aggregateRootId] = new AggregateLatestVersionData { Version = int.Parse(itemArray[1]), LogPosition = long.Parse(itemArray[2]) }; count++; if (count % 1000000 == 0) { _logger.Info("Event index loaded: " + count); } } dataPosition += record.RecordSize + 4 + 4; } _logger.Info("Event index chunk read complete, timeSpent: " + stopWatch.Elapsed.TotalSeconds); } _logger.Info("Event index chunk read all complete, total timeSpent: " + totalStopWatch.Elapsed.TotalSeconds); _isEventIndexLoaded = true; if (_isCommandIndexLoaded) { _loadIndexWaitHandle.Set(); } }
private void RefreshMemoryCache(string aggregateRootId, ref AggregateLatestVersionData aggregateLatestVersionData, EventStreamRecord record) { if (aggregateLatestVersionData != null) { var oldLastActiveTimestamp = aggregateLatestVersionData.LastActiveTimestamp; aggregateLatestVersionData.Update(record.LogPosition, record.Version); var newLastActiveTimestamp = aggregateLatestVersionData.LastActiveTimestamp; _aggregateIndexCacheDict.UpdateTimeKeyDict(aggregateRootId, oldLastActiveTimestamp, newLastActiveTimestamp); } else { aggregateLatestVersionData = new AggregateLatestVersionData(record.LogPosition, record.Version); _aggregateIndexCacheDict.AddOrUpdate(aggregateRootId, aggregateLatestVersionData); } _commandIndexCacheDict.AddOrUpdate(record.CommandId, new CommandIndexData(record.CommandCreateTimestamp)); }
private bool CheckAggregateRootLatestVersionMatch(string aggregateRootId, long firstInputEventVersion, out AggregateLatestVersionData aggregateLatestVersionData) { aggregateLatestVersionData = GetAggregateRootLatestVersionData(aggregateRootId); if (aggregateLatestVersionData != null) { if (aggregateLatestVersionData.Version + 1 != firstInputEventVersion) { return(false); } } else if (firstInputEventVersion != 1) { return(false); } return(true); }
private bool CheckAggregateEvents(string aggregateRootId, IList <IEventStream> eventStreamList, EventAppendResult eventAppendResult, out AggregateLatestVersionData aggregateLatestVersionData) { aggregateLatestVersionData = null; //检查版本号是否连续 if (!IsEventStreamVersionSequential(aggregateRootId, eventStreamList)) { eventAppendResult.DuplicateEventAggregateRootIdList.Add(aggregateRootId); return(false); } //检查命令是否重复 var duplicatedCommandIdList = CheckDuplicatedCommands(eventStreamList); if (duplicatedCommandIdList.Count > 0) { eventAppendResult.DuplicateCommandAggregateRootIdList.Add(aggregateRootId, duplicatedCommandIdList); return(false); } //检查版本号是否是基于当前聚合根最新的版本号而进行的修改 if (!CheckAggregateRootLatestVersionMatch(aggregateRootId, eventStreamList.First().Version, out aggregateLatestVersionData)) { eventAppendResult.DuplicateEventAggregateRootIdList.Add(aggregateRootId); return(false); } return(true); }
public EventAppendResult AppendEventStream(IEventStream eventStream) { lock (_lockObj) { //判断命令是否重复 var commandCacheKey = BuildCommandCacheKey(eventStream.CommandCreateTimestamp); if (_commandIndexDict.TryGetValue(commandCacheKey, out ConcurrentDictionary <string, byte> commandIndexDict)) { if (commandIndexDict.ContainsKey(eventStream.CommandId)) { return(EventAppendResult.DuplicateCommand); } } //判断版本号是否冲突,使用内存中仅保留每个聚合根最新版本的字典来实现 if (_aggregateLatestVersionDict.TryGetValue(eventStream.AggregateRootId, out AggregateLatestVersionData aggregateLatestVersionData)) { if (eventStream.Version != (aggregateLatestVersionData.Version + 1)) { return(EventAppendResult.InvalidEventVersion); } } else if (eventStream.Version != 1) { return(EventAppendResult.InvalidEventVersion); } //写入eventStream到文件 var record = new EventStreamRecord { AggregateRootId = eventStream.AggregateRootId, AggregateRootType = eventStream.AggregateRootType, Version = eventStream.Version, CommandId = eventStream.CommandId, Timestamp = eventStream.Timestamp, CommandCreateTimestamp = eventStream.CommandCreateTimestamp, Events = eventStream.Events }; if (aggregateLatestVersionData != null) { record.PreviousRecordLogPosition = aggregateLatestVersionData.LogPosition; } _eventDataChunkWriter.Write(record); //更新聚合根最新的事件版本 if (aggregateLatestVersionData != null) { aggregateLatestVersionData.Version = record.Version; aggregateLatestVersionData.LogPosition = record.LogPosition; } else { aggregateLatestVersionData = new AggregateLatestVersionData { Version = record.Version, LogPosition = record.LogPosition }; _aggregateLatestVersionDict[eventStream.AggregateRootId] = aggregateLatestVersionData; } //添加命令索引到内存字典 _commandIndexDict .GetOrAdd(commandCacheKey, k => new ConcurrentDictionary <string, byte>()) .TryAdd(eventStream.CommandId, 1); //添加事件到事件队列,以便进行异步持久化事件索引和命令索引 _eventStreamRecordQueue.Enqueue(record); return(EventAppendResult.Success); } }