private Byte[] PublishMessages(Byte[] data, Queue <LogEntry> publishQueue, TimeSpan timeout) { LogBook logBook = DeserializeLogBook(data); logBook.TrimStaleEntries(DateTime.UtcNow - _minMessageAge); Int64 logSize = logBook.CalculateLogSize(); // Start slot timer after deserializing log so deserialization doesn't starve the slot time Stopwatch slotTimer = Stopwatch.StartNew(); DateTime batchTime = DateTime.UtcNow; // Try to exhaust the publish queue but don't keep a write lock forever while (publishQueue.Count > 0 && slotTimer.Elapsed < timeout) { // Check if the next message will fit in the log if (logSize + LogEntry.Overhead + publishQueue.Peek().Message.Length > _memoryMappedFile.MaxFileSize) { break; } // Write the entry to the log LogEntry entry = publishQueue.Dequeue(); entry.Id = ++logBook.LastId; entry.Timestamp = batchTime; logBook.Entries.Add(entry); logSize += LogEntry.Overhead + entry.Message.Length; // Skip counting empty messages though, they are skipped on the receiving end anyway if (entry.Message.Length == 0) { continue; } Interlocked.Increment(ref _messagesPublished); } // Flush the updated log to the memory mapped file using MemoryStream memoryStream = new MemoryStream((Int32)logSize); Serializer.Serialize(memoryStream, logBook); return(memoryStream.ToArray()); }