/*
 * Copyright 2015 - 2016 Real Logic Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.aeron.logbuffer;

import org.agrona.concurrent.UnsafeBuffer;

import java.nio.ByteOrder;

import static java.lang.Integer.reverseBytes;
import static java.nio.ByteOrder.LITTLE_ENDIAN;
import static io.aeron.protocol.DataHeaderFlyweight.SESSION_ID_FIELD_OFFSET;
import static io.aeron.protocol.DataHeaderFlyweight.STREAM_ID_FIELD_OFFSET;
import static io.aeron.protocol.DataHeaderFlyweight.TERM_OFFSET_FIELD_OFFSET;
import static io.aeron.protocol.HeaderFlyweight.FRAME_LENGTH_FIELD_OFFSET;
import static io.aeron.protocol.HeaderFlyweight.VERSION_FIELD_OFFSET;

/**
 * Utility for applying a header to a message in a term buffer.
 *
 * This class is designed to be thread safe to be used across multiple producers and makes the header
 * visible in the correct order for consumers.
 */
public class HeaderWriter
{
    private final long versionFlagsType;
    private final long sessionId;
    private final long streamId;

    public HeaderWriter(final UnsafeBuffer defaultHeader)
    {
        if (ByteOrder.nativeOrder() == LITTLE_ENDIAN)
        {
            versionFlagsType = ((long)defaultHeader.getInt(VERSION_FIELD_OFFSET)) << 32;
            sessionId = ((long)defaultHeader.getInt(SESSION_ID_FIELD_OFFSET)) << 32;
            streamId = defaultHeader.getInt(STREAM_ID_FIELD_OFFSET) & 0xFFFF_FFFFL;
        }
        else
        {
            versionFlagsType = defaultHeader.getInt(VERSION_FIELD_OFFSET) & 0xFFFF_FFFFL;
            sessionId = defaultHeader.getInt(SESSION_ID_FIELD_OFFSET) & 0xFFFF_FFFFL;
            streamId = ((long)defaultHeader.getInt(STREAM_ID_FIELD_OFFSET)) << 32;
        }
    }

    /**
     * Write a header to the term buffer in {@link ByteOrder#LITTLE_ENDIAN} format using the minimum instructions.
     *
     * @param termBuffer to be written to.
     * @param offset     at which the header should be written.
     * @param length     of the fragment including the header.
     * @param termId     of the current term buffer.
     */
    public void write(final UnsafeBuffer termBuffer, final int offset, final int length, final int termId)
    {
        final long lengthVersionFlagsType;
        final long termOffsetSessionId;
        final long streamAndTermIds;

        if (ByteOrder.nativeOrder() == LITTLE_ENDIAN)
        {
            lengthVersionFlagsType = versionFlagsType | ((-length) & 0xFFFF_FFFFL);
            termOffsetSessionId = sessionId | offset;
            streamAndTermIds = streamId | (((long)termId) << 32);
        }
        else
        {
            lengthVersionFlagsType = versionFlagsType | ((((long)reverseBytes(-length))) << 32);
            termOffsetSessionId = sessionId | ((((long)reverseBytes(offset))) << 32);
            streamAndTermIds = streamId | (reverseBytes(termId) & 0xFFFF_FFFFL);
        }

        termBuffer.putLong(offset + FRAME_LENGTH_FIELD_OFFSET, lengthVersionFlagsType);
        termBuffer.putLong(offset + TERM_OFFSET_FIELD_OFFSET, termOffsetSessionId);
        termBuffer.putLong(offset + STREAM_ID_FIELD_OFFSET, streamAndTermIds);
    }
}

@@ -620,24 +620,56 @@
 logbuffer;%0A%0A
+import org.agrona.UnsafeAccess;%0A
 import org.a
@@ -3444,32 +3444,39 @@
 rmBuffer.putLong
+Ordered
 (offset + FRAME_
@@ -3521,16 +3521,59 @@
 sType);%0A
+        UnsafeAccess.UNSAFE.storeFence();%0A%0A
         

Revert last change.