Package org.apache.hedwig.server.delivery

Source Code of org.apache.hedwig.server.delivery.TestFIFODeliveryManager$ExecutorDeliveryEndPoint

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.hedwig.server.delivery;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.hedwig.exceptions.PubSubException;
import org.apache.hedwig.filter.PipelineFilter;
import org.apache.hedwig.protocol.PubSubProtocol.Message;
import org.apache.hedwig.protocol.PubSubProtocol.MessageSeqId;
import org.apache.hedwig.protocol.PubSubProtocol.PubSubResponse;
import org.apache.hedwig.protocol.PubSubProtocol.SubscriptionPreferences;
import org.apache.hedwig.server.common.ServerConfiguration;
import org.apache.hedwig.server.persistence.PersistRequest;
import org.apache.hedwig.server.persistence.PersistenceManager;
import org.apache.hedwig.server.persistence.StubPersistenceManager;
import org.apache.hedwig.server.subscriptions.AllToAllTopologyFilter;
import org.apache.hedwig.util.Callback;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.protobuf.ByteString;

public class TestFIFODeliveryManager {
    static Logger logger = LoggerFactory.getLogger(TestFIFODeliveryManager.class);

    static class TestCallback implements Callback<MessageSeqId> {
        AtomicBoolean success = new AtomicBoolean(false);
        final CountDownLatch latch;
        MessageSeqId msgid = null;

        TestCallback(CountDownLatch l) {
            this.latch = l;
        }
        public void operationFailed(Object ctx, PubSubException exception) {
            logger.error("Persist operation failed", exception);
            latch.countDown();
        }

        public void operationFinished(Object ctx, MessageSeqId resultOfOperation) {
            msgid = resultOfOperation;
            success.set(true);
            latch.countDown();
        }

        MessageSeqId getId() {
            assertTrue("Persist operation failed", success.get());
            return msgid;
        }
    }

    /**
     * Delivery endpoint which puts all responses on a queue
     */
    static class ExecutorDeliveryEndPointWithQueue implements DeliveryEndPoint {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        AtomicInteger numResponses = new AtomicInteger(0);
        ConcurrentLinkedQueue<PubSubResponse> queue = new ConcurrentLinkedQueue<PubSubResponse>();

        public void send(final PubSubResponse response, final DeliveryCallback callback) {
            logger.info("Received response {}", response);
            queue.add(response);
            numResponses.incrementAndGet();
            executor.submit(new Runnable() {
                    public void run() {
                        callback.sendingFinished();
                    }
                });
        }

        public void close() {
            executor.shutdown();
        }

        PubSubResponse getNextResponse() {
            return queue.poll();
        }

        int getNumResponses() {
            return numResponses.get();
        }
    }

    /**
     * Test that the FIFO delivery manager executes stopServing and startServing
     * in the correct order
     * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-539}
     */
    @Test
    public void testFIFODeliverySubCloseSubRace() throws Exception {
        ServerConfiguration conf = new ServerConfiguration();
        ByteString topic = ByteString.copyFromUtf8("subRaceTopic");
        ByteString subscriber = ByteString.copyFromUtf8("subRaceSubscriber");

        PersistenceManager pm = new StubPersistenceManager();
        FIFODeliveryManager fdm = new FIFODeliveryManager(pm, conf);
        ExecutorDeliveryEndPointWithQueue dep = new ExecutorDeliveryEndPointWithQueue();
        SubscriptionPreferences prefs = SubscriptionPreferences.newBuilder().build();

        PipelineFilter filter = new PipelineFilter();
        filter.addLast(new AllToAllTopologyFilter());
        filter.initialize(conf.getConf());
        filter.setSubscriptionPreferences(topic, subscriber, prefs);
        MessageSeqId startId = MessageSeqId.newBuilder().setLocalComponent(1).build();

        CountDownLatch l = new CountDownLatch(1);
        Message m = Message.newBuilder().setBody(ByteString.copyFromUtf8(String.valueOf(1))).build();
        TestCallback cb = new TestCallback(l);
        pm.persistMessage(new PersistRequest(topic, m, cb, null));
        assertTrue("Persistence never finished", l.await(10, TimeUnit.SECONDS));

        final CountDownLatch oplatch = new CountDownLatch(3);
        fdm.start();
        fdm.startServingSubscription(topic, subscriber, prefs, startId, dep, filter,
                new Callback<Void>() {
                     @Override
                     public void operationFinished(Object ctx, Void result) {
                         oplatch.countDown();
                     }
                     @Override
                     public void operationFailed(Object ctx, PubSubException exception) {
                         oplatch.countDown();
                     }
                }, null);
        fdm.stopServingSubscriber(topic, subscriber, null,
                new Callback<Void>() {
                     @Override
                     public void operationFinished(Object ctx, Void result) {
                         oplatch.countDown();
                     }
                     @Override
                     public void operationFailed(Object ctx, PubSubException exception) {
                         oplatch.countDown();
                     }
                }, null);
        fdm.startServingSubscription(topic, subscriber, prefs, startId, dep, filter,
                new Callback<Void>() {
                     @Override
                     public void operationFinished(Object ctx, Void result) {
                         oplatch.countDown();
                     }
                     @Override
                     public void operationFailed(Object ctx, PubSubException exception) {
                         oplatch.countDown();
                     }
                }, null);

        assertTrue("Ops never finished", oplatch.await(10, TimeUnit.SECONDS));
        int seconds = 5;
        while (dep.getNumResponses() < 2) {
            if (seconds-- == 0) {
                break;
            }
            Thread.sleep(1000);
        }
        PubSubResponse r = dep.getNextResponse();
        assertNotNull("There should be a response", r);
        assertTrue("Response should contain a message", r.hasMessage());
        r = dep.getNextResponse();
        assertNotNull("There should be a response", r);
        assertTrue("Response should contain a message", r.hasMessage());
        r = dep.getNextResponse();
        assertNull("There should only be 2 responses", r);
    }

    static class ExecutorDeliveryEndPoint implements DeliveryEndPoint {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        AtomicInteger numDelivered = new AtomicInteger();
        final DeliveryManager dm;

        ExecutorDeliveryEndPoint(DeliveryManager dm) {
            this.dm = dm;
        }

        public void send(final PubSubResponse response, final DeliveryCallback callback) {
            executor.submit(new Runnable() {
                    public void run() {
                        if (response.hasMessage()) {
                            MessageSeqId msgid = response.getMessage().getMsgId();
                            if ((msgid.getLocalComponent() % 2) == 1) {
                                dm.messageConsumed(response.getTopic(),
                                        response.getSubscriberId(),
                                        response.getMessage().getMsgId());
                            } else {
                                executor.schedule(new Runnable() {
                                        public void run() {
                                            dm.messageConsumed(response.getTopic(),
                                                    response.getSubscriberId(),
                                                    response.getMessage().getMsgId());
                                        }
                                    }, 1, TimeUnit.SECONDS);
                            }
                        }
                        numDelivered.incrementAndGet();
                        callback.sendingFinished();
                    }
                });
        }

        public void close() {
            executor.shutdown();
        }

        int getNumDelivered() {
            return numDelivered.get();
        }
    }

    /**
     * Test throttle race issue cause by messageConsumed and doDeliverNextMessage
     * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-503}
     */
    @Test
    public void testFIFODeliveryThrottlingRace() throws Exception {
        final int numMessages = 20;
        final int throttleSize = 10;
        ServerConfiguration conf = new ServerConfiguration() {
                @Override
                public int getDefaultMessageWindowSize() {
                    return throttleSize;
                }
            };
        ByteString topic = ByteString.copyFromUtf8("throttlingRaceTopic");
        ByteString subscriber = ByteString.copyFromUtf8("throttlingRaceSubscriber");

        PersistenceManager pm = new StubPersistenceManager();
        FIFODeliveryManager fdm = new FIFODeliveryManager(pm, conf);
        ExecutorDeliveryEndPoint dep = new ExecutorDeliveryEndPoint(fdm);
        SubscriptionPreferences prefs = SubscriptionPreferences.newBuilder().build();

        PipelineFilter filter = new PipelineFilter();
        filter.addLast(new AllToAllTopologyFilter());
        filter.initialize(conf.getConf());
        filter.setSubscriptionPreferences(topic, subscriber, prefs);

        CountDownLatch l = new CountDownLatch(numMessages);

        TestCallback firstCallback = null;
        for (int i = 0; i < numMessages; i++) {
            Message m = Message.newBuilder().setBody(ByteString.copyFromUtf8(String.valueOf(i))).build();
            TestCallback cb = new TestCallback(l);
            if (firstCallback == null) {
                firstCallback = cb;
            }
            pm.persistMessage(new PersistRequest(topic, m, cb, null));
        }
        fdm.start();
        assertTrue("Persistence never finished", l.await(10, TimeUnit.SECONDS));
        fdm.startServingSubscription(topic, subscriber, prefs, firstCallback.getId(), dep, filter,
                new Callback<Void>() {
                     @Override
                     public void operationFinished(Object ctx, Void result) {
                     }
                     @Override
                     public void operationFailed(Object ctx, PubSubException exception) {
                         // would not happened
                     }
                }, null);

        int count = 30; // wait for 30 seconds maximum
        while (dep.getNumDelivered() < numMessages) {
            Thread.sleep(1000);
            if (count-- == 0) {
                break;
            }
        }
        assertEquals("Should have delivered " + numMessages, numMessages, dep.getNumDelivered());
    }

}
TOP

Related Classes of org.apache.hedwig.server.delivery.TestFIFODeliveryManager$ExecutorDeliveryEndPoint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.