Example #1
0
        /// <summary>
        /// Serialize the first object in the queue to the a memory stream which will be copied into shared memory.
        /// The write stream which is being written to is not the shared memory itself, it is a memory stream from which
        /// bytes will be copied and placed in the shared memory in the write method.
        /// </summary>
        private void SerializeCallDescriptorToStream(DualQueue <LocalCallDescriptor> objectsToWrite)
        {
            // Get the object by peeking at the queue rather than dequeueing the object. This is done
            // because we only want to dequeue the object when it has completely been put in shared memory.
            // This may be done right away if the object is small enough to fit in the shared memory or
            // may happen after a the object is sent as a number of smaller chunks.
            object objectToWrite = objectsToWrite.Peek();

            Debug.Assert(objectToWrite != null, "Expect to get a non-null object from the queue");
            if (objectToWrite is LocalCallDescriptorForPostBuildResult)
            {
                writeStream.WriteByte((byte)ObjectType.PostBuildResult);
                ((LocalCallDescriptorForPostBuildResult)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForPostBuildRequests)
            {
                writeStream.WriteByte((byte)ObjectType.PostBuildRequests);
                ((LocalCallDescriptorForPostBuildRequests)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForPostLoggingMessagesToHost)
            {
                writeStream.WriteByte((byte)ObjectType.PostLoggingMessagesToHost);
                ((LocalCallDescriptorForPostLoggingMessagesToHost)objectToWrite).WriteToStream(binaryWriter, loggingTypeCache);
            }
            else if (objectToWrite is LocalCallDescriptorForInitializeNode)
            {
                writeStream.WriteByte((byte)ObjectType.InitializeNode);
                ((LocalCallDescriptorForInitializeNode)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForInitializationComplete)
            {
                writeStream.WriteByte((byte)ObjectType.InitializationComplete);
                ((LocalCallDescriptorForInitializationComplete)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForUpdateNodeSettings)
            {
                writeStream.WriteByte((byte)ObjectType.UpdateNodeSettings);
                ((LocalCallDescriptorForUpdateNodeSettings)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForRequestStatus)
            {
                writeStream.WriteByte((byte)ObjectType.RequestStatus);
                ((LocalCallDescriptorForRequestStatus)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForPostingCacheEntriesToHost)
            {
                writeStream.WriteByte((byte)ObjectType.PostCacheEntriesToHost);
                ((LocalCallDescriptorForPostingCacheEntriesToHost)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForGettingCacheEntriesFromHost)
            {
                writeStream.WriteByte((byte)ObjectType.GetCacheEntriesFromHost);
                ((LocalCallDescriptorForGettingCacheEntriesFromHost)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForShutdownComplete)
            {
                writeStream.WriteByte((byte)ObjectType.ShutdownComplete);
                ((LocalCallDescriptorForShutdownComplete)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForShutdownNode)
            {
                writeStream.WriteByte((byte)ObjectType.ShutdownNode);
                ((LocalCallDescriptorForShutdownNode)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForPostIntrospectorCommand)
            {
                writeStream.WriteByte((byte)ObjectType.PostIntrospectorCommand);
                ((LocalCallDescriptorForPostIntrospectorCommand)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalReplyCallDescriptor)
            {
                writeStream.WriteByte((byte)ObjectType.GenericSingleObjectReply);
                ((LocalReplyCallDescriptor)objectToWrite).WriteToStream(binaryWriter);
            }
            else if (objectToWrite is LocalCallDescriptorForPostStatus)
            {
                writeStream.WriteByte((byte)ObjectType.PostStatus);
                ((LocalCallDescriptorForPostStatus)objectToWrite).WriteToStream(binaryWriter);
            }
            else
            {
                // If the object is not one of the well known local descriptors, use .net Serialization to serialize the object
                writeStream.WriteByte((byte)ObjectType.NetSerialization);
                binaryFormatter.Serialize(writeStream, objectToWrite);
            }
        }
Example #2
0
        /// <summary>
        /// This function write out a set of objects into the shared buffer.
        /// In normal operation all the objects in the queue are serialized into
        /// the buffer followed by an end marker class. If the buffer is not big
        /// enough to contain a single object the object is broken into
        /// multiple buffers as follows - first a frame marker is sent containing
        /// the size of the serialized object + size of end marker. The reader makes
        /// sure upon receiving the frame marker that its buffer is large enough
        /// to contain the object about to be sent. After the frame marker the object
        /// is sent as a series of buffers until all of it is written out.
        /// </summary>
        /// <param name="objectsToWrite"> Queue of objects to be sent (mostly logging messages)</param>
        /// <param name="objectsToWriteHiPriority">Queue of high priority objects (these are commands and statuses) </param>
        /// <param name="blockUntilDone"> If true the function will block until both queues are empty</param>
        internal void Write(DualQueue <LocalCallDescriptor> objectsToWrite, DualQueue <LocalCallDescriptor> objectsToWriteHiPriority, bool blockUntilDone)
        {
            Debug.Assert(type == SharedMemoryType.WriteOnly, "Should only be calling Write from a writeonly shared memory object");

            lock (writeLock)
            {
                // Loop as long as there are objects availiable and room in the shared memory.
                // If blockUntilDone is set continue to loop until all of the objects in both queues are sent.
                while ((objectsToWrite.Count > 0 || objectsToWriteHiPriority.Count > 0) &&
                       ((blockUntilDone && notFullFlag.WaitOne()) || !IsFull))
                {
                    bool isFull             = false;
                    long writeStartPosition = writeStream.Position;
                    bool writeEndMarker     = false;

                    // Put as many LocalCallDescriptor objects as possible into the shared memory
                    while (!isFull && (objectsToWrite.Count > 0 || objectsToWriteHiPriority.Count > 0))
                    {
                        long writeResetPosition = writeStream.Position;

                        DualQueue <LocalCallDescriptor> currentQueue = objectsToWriteHiPriority.Count > 0 ? objectsToWriteHiPriority : objectsToWrite;

                        // writeBytesRemaining == 0 is when we are currently not sending a multi part object through
                        // the shared memory
                        if (writeBytesRemaining == 0)
                        {
                            // Serialize the object to the memory stream
                            SerializeCallDescriptorToStream(currentQueue);

                            // If the size of the serialized object plus the end marker fits within the shared memory
                            // dequeue the object as it is going to be sent.
                            if ((writeStream.Position + sizeof(byte)) <= size)
                            {
                                currentQueue.Dequeue();
                                writeEndMarker = true;
                            }
                            else
                            {
                                // The serialized object plus the end marker is larger than the shared memory buffer
                                // Check if it necessary break down the object into multiple buffers
                                // If the memoryStream was empty before trying to serialize the object
                                // create a frame marker with the size of the object and send through the shared memory
                                if (writeResetPosition == 0)
                                {
                                    // We don't want to switch from low priority to high priority queue in the middle of sending a large object
                                    // so we make a record of which queue contains the large object
                                    largeObjectsQueue = currentQueue;
                                    // Calculate the total number of bytes that needs to be sent
                                    writeBytesRemaining = (int)(writeStream.Position + sizeof(byte));
                                    // Send a frame marker out to the reader containing the size of the object
                                    writeStream.Position = 0;

                                    // Write the frameMarkerId byte and then the amount of bytes for the large object
                                    writeStream.WriteByte((byte)ObjectType.FrameMarker);
                                    binaryWriter.Write((Int32)writeBytesRemaining);
                                    writeEndMarker = true;
                                }
                                else
                                {
                                    // Some items were placed in the shared Memory buffer, erase the last one which was too large
                                    // and say the buffer is full so it can be sent
                                    writeStream.Position = writeResetPosition;
                                }
                                isFull = true;
                            }
                        }
                        else
                        {
                            if (writeStream.Position == 0)
                            {
                                // Serialize the object which will be split across multiple buffers
                                SerializeCallDescriptorToStream(largeObjectsQueue);
                                writeStream.WriteByte((byte)ObjectType.EndMarker);
                            }
                            break;
                        }
                    }

                    // If a multi-buffer object is being sent and the large object is still larger or equal to the shard memory buffer - send the next chunk of the object
                    if (writeBytesRemaining != 0 && writeStream.Position >= size)
                    {
                        // Set write Length to an entire buffer length  or just the remaining portion
                        int writeLength = writeBytesRemaining > size ? size : writeBytesRemaining;

                        //Write the length of the buffer to the memory file
                        Marshal.WriteInt32((IntPtr)pageFileView, (int)writeLength);
                        Marshal.Copy
                        (
                            writeStream.GetBuffer(),                           // Source Buffer
                            (int)(writeStream.Position - writeBytesRemaining), // Start index
                            (IntPtr)((int)pageFileView + 4),                   //Destination (+4 because of the int written to the memory file with the write length)
                            (int)writeLength                                   // Length of bytes to write
                        );

                        writeBytesRemaining -= writeLength;
                        IncrementUnreadBatchCounter();

                        // Once the object is fully sent - remove it from the queue
                        if (writeBytesRemaining == 0)
                        {
                            largeObjectsQueue.Dequeue();
                        }

                        isFull = true;
                    }

                    if (writeEndMarker)
                    {
                        writeStream.WriteByte((byte)ObjectType.EndMarker);
                        // Need to verify the WriteInt32 and ReadInt32 are always atomic operations
                        //writeSizeMutex.WaitOne();
                        // Write the size of the buffer to send to the memory stream
                        Marshal.WriteInt32((IntPtr)pageFileView, (int)writeStream.Position);
                        //writeSizeMutex.ReleaseMutex();

                        Marshal.Copy
                        (
                            writeStream.GetBuffer(),                              // Buffer
                            (int)writeStartPosition,                              // Start Position
                            (IntPtr)((int)pageFileView + writeStartPosition + 4), // Destination + 4 for the int indicating the size of the data to be copied to the memory file
                            (int)(writeStream.Position - writeStartPosition)      // Length of data to copy to memory file
                        );

                        IncrementUnreadBatchCounter();
                    }

                    if (isFull)
                    {
                        MarkAsFull();
                        writeStream.SetLength(0);
                    }
                }
            }
        }