All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.aeron.GapFillLossTest Maven / Gradle / Ivy

/*
 * Copyright 2017 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;

import io.aeron.driver.*;
import io.aeron.driver.ext.*;
import io.aeron.driver.reports.LossReport;
import io.aeron.logbuffer.*;
import org.agrona.DirectBuffer;
import org.agrona.concurrent.*;
import org.junit.Test;

import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;

import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class GapFillLossTest
{
    private static final String CHANNEL = "aeron:udp?endpoint=localhost:54325";
    private static final String UNRELIABLE_CHANNEL =
        CHANNEL + "|" + CommonContext.RELIABLE_STREAM_PARAM_NAME + "=false";

    private static final int STREAM_ID = 1;
    private static final int FRAGMENT_COUNT_LIMIT = 10;
    private static final int MSG_LENGTH = 1024;
    private static final int TERM_BUFFER_LENGTH = 1024 * 64;
    private static final int NUM_MESSAGES = 10_000;

    private static final AtomicLong FINAL_POSITION = new AtomicLong(Long.MAX_VALUE);

    @Test(timeout = 10000)
    public void shouldGapFillWhenLossOccurs() throws Exception
    {
        final UnsafeBuffer srcBuffer = new UnsafeBuffer(ByteBuffer.allocateDirect(MSG_LENGTH));
        srcBuffer.setMemory(0, MSG_LENGTH, (byte)7);

        final MediaDriver.Context ctx = new MediaDriver.Context()
            .threadingMode(ThreadingMode.SHARED)
            .publicationTermBufferLength(TERM_BUFFER_LENGTH);

        final LossReport lossReport = mock(LossReport.class);
        ctx.lossReport(lossReport);

        final LossGenerator dataLossGenerator =
            DebugChannelEndpointConfiguration.lossGeneratorSupplier(0.20, 0xcafebabeL);
        final LossGenerator noLossGenerator =
            DebugChannelEndpointConfiguration.lossGeneratorSupplier(0, 0);

        ctx.sendChannelEndpointSupplier(
            (udpChannel, statusIndicator, context) -> new DebugSendChannelEndpoint(
                udpChannel, statusIndicator, context, noLossGenerator, noLossGenerator));

        ctx.receiveChannelEndpointSupplier(
            (udpChannel, dispatcher, statusIndicator, context) -> new DebugReceiveChannelEndpoint(
                udpChannel, dispatcher, statusIndicator, context, dataLossGenerator, noLossGenerator));

        try (MediaDriver ignore = MediaDriver.launch(ctx);
             Aeron aeron = Aeron.connect();
             Publication publication = aeron.addPublication(CHANNEL, STREAM_ID);
             Subscription subscription = aeron.addSubscription(UNRELIABLE_CHANNEL, STREAM_ID))
        {
            final IdleStrategy idleStrategy = new YieldingIdleStrategy();

            final Subscriber subscriber = new Subscriber(subscription);
            final Thread subscriberThread = new Thread(subscriber);
            subscriberThread.start();

            long position = 0;
            for (int i = 0; i < NUM_MESSAGES; i++)
            {
                srcBuffer.putLong(0, i);

                while ((position = publication.offer(srcBuffer)) < 0L)
                {
                    idleStrategy.idle();
                }
            }

            FINAL_POSITION.set(position);
            subscriberThread.join();

            assertThat(subscriber.messageCount, lessThan(NUM_MESSAGES));
            verify(lossReport).createEntry(anyLong(), anyLong(), anyInt(), eq(STREAM_ID), anyString(), anyString());
        }
        finally
        {
            ctx.deleteAeronDirectory();
        }
    }

    static class Subscriber implements Runnable, FragmentHandler
    {
        private final Subscription subscription;
        int messageCount = 0;

        Subscriber(final Subscription subscription)
        {
            this.subscription = subscription;
        }

        public void run()
        {
            final IdleStrategy idleStrategy = new YieldingIdleStrategy();

            while (subscription.hasNoImages())
            {
                idleStrategy.idle();
            }

            final Image image = subscription.getImage(0);

            while (image.position() < FINAL_POSITION.get())
            {
                idleStrategy.idle(subscription.poll(this, FRAGMENT_COUNT_LIMIT));
            }
        }

        public void onFragment(final DirectBuffer buffer, final int offset, final int length, final Header header)
        {
            messageCount++;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy