Package org.apache.avro.ipc

Source Code of org.apache.avro.ipc.TestNettyServerConcurrentExecution

/**
* 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.avro.ipc;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;

import org.apache.avro.AvroRemoteException;
import org.apache.avro.ipc.specific.SpecificRequestor;
import org.apache.avro.ipc.specific.SpecificResponder;
import org.apache.avro.test.Simple;
import org.apache.avro.test.TestError;
import org.apache.avro.test.TestRecord;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;

/**
* Verifies that RPCs executed by different client threads using the same
* NettyTransceiver will execute concurrently.  The test follows these steps:
* 1. Execute the {@link #org.apache.avro.test.Simple.add(int, int)} RPC to
*    complete the Avro IPC handshake.
* 2a. In a background thread, wait for the waitLatch.
* 3a. In the main thread, invoke
*    {@link #org.apache.avro.test.Simple.hello(String)} with the argument
*    "wait".  This causes the ClientImpl running on the server to count down
*    the wait latch, which will unblock the background thread and allow it to
*    proceed.  After counting down the latch, this call blocks, waiting for
*    {@link #org.apache.avro.test.Simple.ack()} to be invoked.
* 2b. The background thread wakes up because the waitLatch has been counted
*     down.  Now we know that some thread is executing inside hello(String).
*     Next, execute {@link #org.apache.avro.test.Simple.ack()} in the
*     background thread, which will allow the thread executing hello(String)
*     to return.
* 3b. The thread executing hello(String) on the server unblocks (since ack()
*     has been called), allowing hello(String) to return.
* 4. If control returns to the main thread, we know that two RPCs
*    (hello(String) and ack()) were executing concurrently.
*/
public class TestNettyServerConcurrentExecution {
  private Server server;
  private Transceiver transceiver;
 
  @After
  public void cleanUpAfter() throws Exception {
    try {
      if (transceiver != null) {
        transceiver.close();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    try {
      if (server != null) {
        server.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
  @Test(timeout=30000)
  public void test() throws Exception {
    final CountDownLatch waitLatch = new CountDownLatch(1);
    server = new NettyServer(
        new SpecificResponder(Simple.class, new SimpleImpl(waitLatch)),
        new InetSocketAddress(0),
        new NioServerSocketChannelFactory
          (Executors.newCachedThreadPool(), Executors.newCachedThreadPool()),
        new ExecutionHandler(Executors.newCachedThreadPool()));
    server.start();
   
    transceiver = new NettyTransceiver(new InetSocketAddress(
        server.getPort()), TestNettyServer.CONNECT_TIMEOUT_MILLIS);
   
    // 1. Create the RPC proxy, and establish the handshake:
    final Simple.Callback simpleClient =
        SpecificRequestor.getClient(Simple.Callback.class, transceiver);
    SpecificRequestor.getRemote(simpleClient);    // force handshake
   
    /*
     * 2a. In a background thread, wait for the Client.hello("wait") call to be
     *    received by the server, then:
     * 2b. Execute the Client.ack() RPC, which will unblock the
     *     Client.hello("wait") call, allowing it to return to the main thread.
     */
    new Thread() {
      @Override
      public void run() {
        setName(TestNettyServerConcurrentExecution.class.getSimpleName() +
            "Ack Thread");
        try {
          // Step 2a:
          waitLatch.await();
         
          // Step 2b:
          simpleClient.ack();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }.start();
   
    /*
     * 3. Execute the Client.hello("wait") RPC, which will block until the
     *    Client.ack() call has completed in the background thread.
     */
    String response = simpleClient.hello("wait");
   
    // 4. If control reaches here, both RPCs have executed concurrently
    Assert.assertEquals("wait", response);
  }

  /**
   * Implementation of the Simple interface for use with this unit test.
   * If {@link #hello(String)} is called with "wait" as its argument, 
   * {@link #waitLatch} will be counted down, and {@link #hello(String)} will
   * block until {@link #ack()} has been invoked.
   */
  private static class SimpleImpl implements Simple {
    private final CountDownLatch waitLatch;
    private final CountDownLatch ackLatch = new CountDownLatch(1);
   
    /**
     * Creates a SimpleImpl that uses the given CountDownLatch.
     * @param waitLatch the CountDownLatch to use in {@link #hello(String)}.
     */
    public SimpleImpl(final CountDownLatch waitLatch) {
      this.waitLatch = waitLatch;
    }
   
    @Override
    public int add(int arg1, int arg2) throws AvroRemoteException {
      // Step 1:
      return arg1 + arg2;
    }
   
    @Override
    public String hello(String greeting) throws AvroRemoteException {
      if (greeting.equals("wait")) {
        try {
          // Step 3a:
          waitLatch.countDown();
         
          // Step 3b:
          ackLatch.await();
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          return e.toString();
        }
      }
      return greeting;
    }
   
    @Override
    public void ack() {
      // Step 2b:
      ackLatch.countDown();
    }
   
    // All RPCs below this line are irrelevant to this test:
   
    @Override
    public TestRecord echo(TestRecord record) throws AvroRemoteException {
      return record;
    }

    @Override
    public ByteBuffer echoBytes(ByteBuffer data) throws AvroRemoteException {
      return data;
    }

    @Override
    public Void error() throws AvroRemoteException, TestError {
      throw new TestError("TestError");
    }
  }
}
TOP

Related Classes of org.apache.avro.ipc.TestNettyServerConcurrentExecution

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.