/// <summary>Tries to peek (or receive) a message using the queue-specific <paramref name="lookupId"/></summary> /// <remarks>Within a transaction you cannot receive a message that you moved to a subqueue within the same transaction</remarks> /// <param name="properties">The properties to read</param> /// <param name="lookupId">The <see cref="Message.LookupId"/> of the message to read</param> /// <param name="action">Receive or peek a message?</param> /// <param name="timeout">The time allowed, defaults to infinite. Use <see cref="TimeSpan.Zero"/> to return without waiting</param> /// <param name="transaction">can be NULL for no transaction, a <see cref="QueueTransaction"/>, <see cref="QueueTransaction.Single"/>, or <see cref="QueueTransaction.Dtc"/>.</param> /// <returns>The message, or NULL if the message was not found or the receive times out</returns> public unsafe Message Lookup(Properties properties, long lookupId, LookupAction action = LookupAction.ReceiveCurrent, TimeSpan?timeout = null, QueueTransaction transaction = null) { if (IsClosed) { throw new ObjectDisposedException(nameof(Queue)); } uint timeoutMS = TimeoutInMs(timeout); var msg = new Message(); int res; msg.Props.SetForRead(properties); for (;;) // loop because we might need to adjust memory size { var props = msg.Props.Allocate(); try { IntPtr txnHandle; if (transaction.TryGetHandle(out txnHandle)) { res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, txnHandle); } else { res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, transaction.InternalTransaction); } } finally { msg.Props.Free(); } if ((ErrorCode)res == ErrorCode.IOTimeout || (ErrorCode)res == ErrorCode.MessageNotFound) { return(null); } if (Native.NotEnoughMemory(res)) { msg.Props.IncreaseBufferSize(); continue; // try again } if (Native.IsError(res)) { throw new QueueException(res); } msg.Props.ResizeBody(); return(msg); } }
public unsafe Task <Message> ReceiveAsync() { // create overlapped with callback that sets the task complete source var overlapped = new Overlapped(); var nativeOverlapped = overlapped.Pack(EndReceive, null); try { for (;;) { // receive, may complete synchronously or call the async callback on the overlapped defined above int res = Native.ReceiveMessage(handle, timeoutMS, action, Props, nativeOverlapped, null, cursor, IntPtr.Zero); // successfully completed synchronously but no enough memory if (Native.NotEnoughMemory(res)) { Message.Props.Free(); Message.Props.IncreaseBufferSize(); Props = Message.Props.Allocate(); continue; // try again } if (Native.IsError(res)) { Message.Props.Free(); Overlapped.Free(nativeOverlapped); Tcs.TrySetException(new QueueException(unchecked (res))); // we really want Task.FromException... return(Tcs.Task); } return(Tcs.Task); } } catch (ObjectDisposedException ex) { Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled)); return(Tcs.Task); } }
public unsafe void EndReceive(uint code, uint bytes, NativeOverlapped *native) { Overlapped.Free(native); Message.Props.Free(); lock (Outstanding) Outstanding.Remove(this); if (code == 995) // operation aborted { Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled)); return; } var result = Native.GetOverlappedResult(native); try { switch (result) { case 0: Message.Props.ResizeBody(); Tcs.TrySetResult(Message); break; case (int)ErrorCode.InsufficientResources: Tcs.SetException(new OutOfMemoryException("async receive operation reported InsufficientResources")); break; case (int)ErrorCode.IOTimeout: Tcs.TrySetResult(null); break; default: // successfully completed but no enough memory if (Native.NotEnoughMemory(result)) { Message.Props.Free(); Message.Props.IncreaseBufferSize(); Props = Message.Props.Allocate(); var overlapped = new Overlapped(); var nativeOverlapped = overlapped.Pack(EndReceive, null); int res = Native.ReceiveMessage(handle, timeoutMS, action, Props, nativeOverlapped, null, cursor, IntPtr.Zero); if (res == MQ_INFORMATION_OPERATION_PENDING) // running asynchronously { return; } // call completed synchronously Message.Props.Free(); Overlapped.Free(nativeOverlapped); if (!Native.IsError(res)) { Message.Props.ResizeBody(); Tcs.TrySetResult(Message); return; } } // some other error Tcs.TrySetException(new QueueException(unchecked ((int)code))); // or do we use the result? break; } } catch (ObjectDisposedException ex) { Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled)); } }