/// <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);
            }
        }
Exemple #2
0
        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);
            }
        }
Exemple #3
0
        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));
            }
        }