예제 #1
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="target"></param>
        /// <param name="buffer"></param>
        public void QueueArray <T>(RpcRequest type, string target, IArray <T> buffer) where T : struct
        {
            var headerSize  = FastStructure.SizeOf <InteropMessageHeader>();
            var elementSize = FastStructure.SizeOf <T>();

            if (headerSize + elementSize * buffer.Length > messageProducer.NodeBufferSize)
            {
                throw new Exception($"Cannot queue {buffer.Length} elements of {typeof(T)} - will not fit in a single message");
            }

            // Construct a header with metadata for the array
            var header = new InteropMessageHeader {
                type   = type,
                length = buffer.MaxLength,
                index  = buffer.Offset,
                count  = buffer.Length
            };

            // Remove any queued messages with the same outbound header
            RemoveQueuedMessage(target, ref header);

            InteropLogger.Debug($"    QA-> {target}:{type:F}");
            outboundQueue.Enqueue(new InteropMessage
            {
                target   = target,
                header   = header,
                producer = (tar, hdr, ptr) => {
                    buffer.CopyTo(ptr, 0, buffer.Length);
                    return(elementSize * buffer.Length);
                }
            });
        }
예제 #2
0
        public bool ReplaceOrQueue <T>(RpcRequest type, string target, ref T data) where T : struct
        {
            var header = new InteropMessageHeader {
                type  = type,
                index = 0,
                count = 0
            };

            var payload = FastStructure.ToBytes(ref data);

            // If it's already queued, replace the payload
            var queued = FindQueuedMessage(target, ref header);

            if (queued != null)
            {
                queued.payload = payload;
                return(true);
            }

            outboundQueue.Enqueue(new InteropMessage
            {
                target  = target,
                header  = header,
                payload = payload
            });

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Queue an outbound message containing one or more <typeparamref name="T"/> values.
        ///
        /// <para>
        ///     If we cannot fit the entire dataset into a single message, and
        ///     <paramref name="allowSplitMessages"/> is true then the payload will
        ///     be split into multiple messages, each with a distinct
        ///     <see cref="InteropMessageHeader.index"/> and <see cref="InteropMessageHeader.count"/>
        ///     range.
        /// </para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="target"></param>
        /// <param name="data"></param>
        /// <param name="allowSplitMessages"></param>
        public bool ReplaceOrQueueArray <T>(RpcRequest type, string target, T[] data, bool allowSplitMessages) where T : struct
        {
            var headerSize  = FastStructure.SizeOf <InteropMessageHeader>();
            var elementSize = FastStructure.SizeOf <T>();

            // TODO: Splitting. Right now assume fit or fail.
            if (headerSize + elementSize * data.Length > messageProducer.NodeBufferSize)
            {
                throw new Exception($"Cannot queue {data.Length} elements of {typeof(T)} - will not fit in a single message");
            }

            var header = new InteropMessageHeader {
                type  = type,
                index = 0,
                count = data.Length
            };

            // TODO: If the source array size changes - find queued won't be correct.

            // We assume ReplaceOrQueue because of the below TODO - multiple queued arrays
            // would be pointing to the same data anyway.

            // If it's already queued, we don't need to do anything.
            var queued = FindQueuedMessage(target, ref header);

            if (queued != null)
            {
                return(true);
            }

            outboundQueue.Enqueue(new InteropMessage
            {
                target   = target,
                header   = header,
                producer = (tar, hdr, ptr) => {
                    if (hdr.count < 1 || hdr.index + hdr.count > data.Length)
                    {
                        throw new Exception($"Producer out of range of dataset - {hdr.type} - {tar}");
                    }
                    // TODO: My concern here would be what happens if the buffer changes before this is sent?
                    // This would send the updated buffer - BUT that probably wouldn't be a problem because
                    // we're trying to send the most recent data at all times anyway, right?
                    // Even if it's sitting in queue for a while.

                    // Also seems like this should be an implicit QueueOrReplace - because if multiple
                    // queued messsages point to the same array - they're going to send the same array data.

                    // Could leave this up to the QueueArray caller - passing in this Func<...>
                    // and we're just responsible for adjusting the header to the ranges that fit.
                    FastStructure.WriteArray(ptr, data, hdr.index, hdr.count);
                    return(elementSize * hdr.count);
                }
            });

            return(false);
        }
예제 #4
0
        private InteropMessage FindQueuedMessage(string target, ref InteropMessageHeader header)
        {
            foreach (var message in outboundQueue)
            {
                if (message.target == target && message.header.Equals(header))
                {
                    return(message);
                }
            }

            return(null);
        }
예제 #5
0
        private void RemoveQueuedMessage(string target, ref InteropMessageHeader header)
        {
            var replacement = new Queue <InteropMessage>();

            foreach (var message in outboundQueue)
            {
                if (message.target != target || !message.header.Equals(header))
                {
                    replacement.Enqueue(message);
                }
            }

            outboundQueue = replacement;
        }
예제 #6
0
        public bool ReplaceOrQueue <T>(RpcRequest type, string target, ref T data) where T : struct
        {
            var header = new InteropMessageHeader {
                type   = type,
                index  = 0,
                length = 0,
                count  = 0
            };

            var payload = FastStructure.ToBytes(ref data);

            // If it's already queued, replace the payload

            /*var queued = FindQueuedMessage(target, ref header);
             * if (queued != null)
             * {
             *  queued.payload = payload;
             *  return true;
             * }*/

            // Remove the old one to then queue up one at the end
            // This ensures messages that are queued up together
            // remain in their queued order.
            RemoveQueuedMessage(target, ref header);


            InteropLogger.Debug($"    ROQ-> {target}:{header.type:F}");
            outboundQueue.Enqueue(new InteropMessage
            {
                target  = target,
                header  = header,
                payload = payload
            });

            return(false);
        }