| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. |
| | 3 | |
|
| | 4 | | using System; |
| | 5 | | using System.Collections.Generic; |
| | 6 | | using Azure.Core; |
| | 7 | | using Azure.Messaging.ServiceBus.Core; |
| | 8 | |
|
| | 9 | | namespace Azure.Messaging.ServiceBus |
| | 10 | | { |
| | 11 | | /// <summary> |
| | 12 | | /// A set of <see cref="ServiceBusMessage" /> with size constraints known up-front, |
| | 13 | | /// intended to be sent to the Queue/Topic as a single batch. |
| | 14 | | /// A <see cref="ServiceBusMessageBatch"/> can be created using |
| | 15 | | /// <see cref="ServiceBusSender.CreateMessageBatchAsync(System.Threading.CancellationToken)"/>. |
| | 16 | | /// Messages can be added to the batch using the <see cref="TryAddMessage"/> method on the batch. |
| | 17 | | /// </summary> |
| | 18 | | /// |
| | 19 | | public sealed class ServiceBusMessageBatch : IDisposable |
| | 20 | | { |
| | 21 | | /// <summary>An object instance to use as the synchronization root for ensuring the thread-safety of operations. |
| 22 | 22 | | private readonly object _syncGuard = new object(); |
| | 23 | |
|
| | 24 | | /// <summary>A flag indicating that the batch is locked, such as when in use during a send batch operation.</sum |
| | 25 | | private bool _locked = false; |
| | 26 | |
|
| | 27 | | /// <summary> |
| | 28 | | /// The maximum size allowed for the batch, in bytes. This includes the messages in the batch as |
| | 29 | | /// well as any overhead for the batch itself when sent to the Queue/Topic. |
| | 30 | | /// </summary> |
| | 31 | | /// |
| 2 | 32 | | public long MaxSizeInBytes => InnerBatch.MaxSizeInBytes; |
| | 33 | |
|
| | 34 | | /// <summary> |
| | 35 | | /// The size of the batch, in bytes, as it will be sent to the Queue/Topic. |
| | 36 | | /// </summary> |
| | 37 | | /// |
| 2 | 38 | | public long SizeInBytes => InnerBatch.SizeInBytes; |
| | 39 | |
|
| | 40 | | /// <summary> |
| | 41 | | /// The count of messages contained in the batch. |
| | 42 | | /// </summary> |
| | 43 | | /// |
| 6 | 44 | | public int Count => InnerBatch.Count; |
| | 45 | |
|
| | 46 | | /// <summary> |
| | 47 | | /// The transport-specific batch responsible for performing the batch operations |
| | 48 | | /// in a manner compatible with the associated <see cref="TransportSender" />. |
| | 49 | | /// </summary> |
| | 50 | | /// |
| 38 | 51 | | private TransportMessageBatch InnerBatch { get; } |
| | 52 | |
|
| | 53 | | /// <summary> |
| | 54 | | /// Initializes a new instance of the <see cref="ServiceBusMessageBatch"/> class. |
| | 55 | | /// </summary> |
| | 56 | | /// |
| | 57 | | /// <param name="transportBatch">The transport-specific batch responsible for performing the batch operations.< |
| | 58 | | /// |
| | 59 | | /// <remarks> |
| | 60 | | /// As an internal type, this class performs only basic sanity checks against its arguments. It |
| | 61 | | /// is assumed that callers are trusted and have performed deep validation. |
| | 62 | | /// |
| | 63 | | /// Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose; |
| | 64 | | /// creation of clones or otherwise protecting the parameters is assumed to be the purview of the |
| | 65 | | /// caller. |
| | 66 | | /// </remarks> |
| | 67 | | /// |
| 22 | 68 | | internal ServiceBusMessageBatch(TransportMessageBatch transportBatch) |
| | 69 | | { |
| 22 | 70 | | Argument.AssertNotNull(transportBatch, nameof(transportBatch)); |
| 20 | 71 | | InnerBatch = transportBatch; |
| 20 | 72 | | } |
| | 73 | |
|
| | 74 | | /// <summary> |
| | 75 | | /// Attempts to add a message to the batch, ensuring that the size |
| | 76 | | /// of the batch does not exceed its maximum. |
| | 77 | | /// </summary> |
| | 78 | | /// |
| | 79 | | /// <param name="message">Message to attempt to add to the batch.</param> |
| | 80 | | /// |
| | 81 | | /// <returns><c>true</c> if the message was added; otherwise, <c>false</c>.</returns> |
| | 82 | | /// |
| | 83 | | public bool TryAddMessage(ServiceBusMessage message) |
| | 84 | | { |
| 18 | 85 | | lock (_syncGuard) |
| | 86 | | { |
| 18 | 87 | | AssertNotLocked(); |
| 14 | 88 | | return InnerBatch.TryAddMessage(message); |
| | 89 | | } |
| 14 | 90 | | } |
| | 91 | |
|
| | 92 | | /// <summary> |
| | 93 | | /// Performs the task needed to clean up resources used by the <see cref="ServiceBusMessageBatch" />. |
| | 94 | | /// </summary> |
| | 95 | | /// |
| | 96 | | public void Dispose() |
| | 97 | | { |
| 6 | 98 | | lock (_syncGuard) |
| | 99 | | { |
| 6 | 100 | | AssertNotLocked(); |
| 4 | 101 | | InnerBatch.Dispose(); |
| 4 | 102 | | } |
| 4 | 103 | | } |
| | 104 | |
|
| | 105 | | /// <summary> |
| | 106 | | /// Clears the batch, removing all messages and resetting the |
| | 107 | | /// available size. |
| | 108 | | /// </summary> |
| | 109 | | /// |
| | 110 | | internal void Clear() |
| | 111 | | { |
| 4 | 112 | | lock (_syncGuard) |
| | 113 | | { |
| 4 | 114 | | AssertNotLocked(); |
| 2 | 115 | | InnerBatch.Clear(); |
| 2 | 116 | | } |
| 2 | 117 | | } |
| | 118 | |
|
| | 119 | | /// <summary> |
| | 120 | | /// Represents the batch as an enumerable set of specific representations of a message. |
| | 121 | | /// </summary> |
| | 122 | | /// |
| | 123 | | /// <typeparam name="T">The specific message representation being requested.</typeparam> |
| | 124 | | /// |
| | 125 | | /// <returns>The set of messages as an enumerable of the requested type.</returns> |
| | 126 | | /// |
| 6 | 127 | | internal IEnumerable<T> AsEnumerable<T>() => InnerBatch.AsEnumerable<T>(); |
| | 128 | |
|
| | 129 | | /// <summary> |
| | 130 | | /// Locks the batch to prevent new messages from being added while a service |
| | 131 | | /// operation is active. |
| | 132 | | /// </summary> |
| | 133 | | /// |
| | 134 | | internal void Lock() |
| | 135 | | { |
| 10 | 136 | | lock (_syncGuard) |
| | 137 | | { |
| 10 | 138 | | _locked = true; |
| 10 | 139 | | } |
| 10 | 140 | | } |
| | 141 | |
|
| | 142 | | /// <summary> |
| | 143 | | /// Unlocks the batch, allowing new messages to be added. |
| | 144 | | /// </summary> |
| | 145 | | /// |
| | 146 | | internal void Unlock() |
| | 147 | | { |
| 10 | 148 | | lock (_syncGuard) |
| | 149 | | { |
| 10 | 150 | | _locked = false; |
| 10 | 151 | | } |
| 10 | 152 | | } |
| | 153 | |
|
| | 154 | | /// <summary> |
| | 155 | | /// Validates that the batch is not in a locked state, triggering an |
| | 156 | | /// invalid operation if it is. |
| | 157 | | /// </summary> |
| | 158 | | /// |
| | 159 | | /// <exception cref="InvalidOperationException">Occurs when the batch is locked.</exception> |
| | 160 | | /// |
| | 161 | | private void AssertNotLocked() |
| | 162 | | { |
| 28 | 163 | | if (_locked) |
| | 164 | | { |
| 8 | 165 | | throw new InvalidOperationException(Resources.MessageBatchIsLocked); |
| | 166 | | } |
| 20 | 167 | | } |
| | 168 | | } |
| | 169 | | } |