/// <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); } }); }
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); }
/// <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); }
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); }
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; }
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); }