Search in sources :

Example 1 with SubprocedureImpl

use of org.apache.hadoop.hbase.procedure.Subprocedure.SubprocedureImpl in project hbase by apache.

the class TestZKProcedure method runCommit.

private void runCommit(String... members) throws Exception {
    // make sure we just have an empty list
    if (members == null) {
        members = new String[0];
    }
    List<String> expected = Arrays.asList(members);
    // setup the constants
    ZKWatcher coordZkw = newZooKeeperWatcher();
    String opDescription = "coordination test - " + members.length + " cohort members";
    // start running the controller
    ZKProcedureCoordinator coordinatorComms = new ZKProcedureCoordinator(coordZkw, opDescription, COORDINATOR_NODE_NAME);
    ThreadPoolExecutor pool = ProcedureCoordinator.defaultPool(COORDINATOR_NODE_NAME, POOL_SIZE, KEEP_ALIVE);
    ProcedureCoordinator coordinator = new ProcedureCoordinator(coordinatorComms, pool) {

        @Override
        public Procedure createProcedure(ForeignExceptionDispatcher fed, String procName, byte[] procArgs, List<String> expectedMembers) {
            return Mockito.spy(super.createProcedure(fed, procName, procArgs, expectedMembers));
        }
    };
    // build and start members
    // NOTE: There is a single subprocedure builder for all members here.
    SubprocedureFactory subprocFactory = Mockito.mock(SubprocedureFactory.class);
    List<Pair<ProcedureMember, ZKProcedureMemberRpcs>> procMembers = new ArrayList<>(members.length);
    // start each member
    for (String member : members) {
        ZKWatcher watcher = newZooKeeperWatcher();
        ZKProcedureMemberRpcs comms = new ZKProcedureMemberRpcs(watcher, opDescription);
        ThreadPoolExecutor pool2 = ProcedureMember.defaultPool(member, 1, KEEP_ALIVE);
        ProcedureMember procMember = new ProcedureMember(comms, pool2, subprocFactory);
        procMembers.add(new Pair<>(procMember, comms));
        comms.start(member, procMember);
    }
    // setup mock member subprocedures
    final List<Subprocedure> subprocs = new ArrayList<>();
    for (int i = 0; i < procMembers.size(); i++) {
        ForeignExceptionDispatcher cohortMonitor = new ForeignExceptionDispatcher();
        Subprocedure commit = Mockito.spy(new SubprocedureImpl(procMembers.get(i).getFirst(), opName, cohortMonitor, WAKE_FREQUENCY, TIMEOUT));
        subprocs.add(commit);
    }
    // link subprocedure to buildNewOperation invocation.
    // NOTE: would be racy if not an AtomicInteger
    final AtomicInteger i = new AtomicInteger(0);
    Mockito.when(subprocFactory.buildSubprocedure(Mockito.eq(opName), (byte[]) Mockito.argThat(new ArrayEquals(data)))).thenAnswer(new Answer<Subprocedure>() {

        @Override
        public Subprocedure answer(InvocationOnMock invocation) throws Throwable {
            int index = i.getAndIncrement();
            LOG.debug("Task size:" + subprocs.size() + ", getting:" + index);
            Subprocedure commit = subprocs.get(index);
            return commit;
        }
    });
    // setup spying on the coordinator
    // Procedure proc = Mockito.spy(procBuilder.createProcedure(coordinator, opName, data, expected));
    // Mockito.when(procBuilder.build(coordinator, opName, data, expected)).thenReturn(proc);
    // start running the operation
    Procedure task = coordinator.startProcedure(new ForeignExceptionDispatcher(), opName, data, expected);
    // assertEquals("Didn't mock coordinator task", proc, task);
    // verify all things ran as expected
    // waitAndVerifyProc(proc, once, once, never(), once, false);
    waitAndVerifyProc(task, once, once, never(), once, false);
    verifyCohortSuccessful(expected, subprocFactory, subprocs, once, once, never(), once, false);
    // close all the things
    closeAll(coordinator, coordinatorComms, procMembers);
}
Also used : ArrayList(java.util.ArrayList) ArrayEquals(org.mockito.internal.matchers.ArrayEquals) SubprocedureImpl(org.apache.hadoop.hbase.procedure.Subprocedure.SubprocedureImpl) ZKWatcher(org.apache.hadoop.hbase.zookeeper.ZKWatcher) ArrayList(java.util.ArrayList) List(java.util.List) Pair(org.apache.hadoop.hbase.util.Pair) ForeignExceptionDispatcher(org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor)

Example 2 with SubprocedureImpl

use of org.apache.hadoop.hbase.procedure.Subprocedure.SubprocedureImpl in project hbase by apache.

the class TestZKProcedure method testMultiCohortWithMemberTimeoutDuringPrepare.

/**
 * Test a distributed commit with multiple cohort members, where one of the cohort members has a
 * timeout exception during the prepare stage.
 */
@Test
public void testMultiCohortWithMemberTimeoutDuringPrepare() throws Exception {
    String opDescription = "error injection coordination";
    String[] cohortMembers = new String[] { "one", "two", "three" };
    List<String> expected = Lists.newArrayList(cohortMembers);
    // error constants
    final int memberErrorIndex = 2;
    final CountDownLatch coordinatorReceivedErrorLatch = new CountDownLatch(1);
    // start running the coordinator and its controller
    ZKWatcher coordinatorWatcher = newZooKeeperWatcher();
    ZKProcedureCoordinator coordinatorController = new ZKProcedureCoordinator(coordinatorWatcher, opDescription, COORDINATOR_NODE_NAME);
    ThreadPoolExecutor pool = ProcedureCoordinator.defaultPool(COORDINATOR_NODE_NAME, POOL_SIZE, KEEP_ALIVE);
    ProcedureCoordinator coordinator = spy(new ProcedureCoordinator(coordinatorController, pool));
    // start a member for each node
    SubprocedureFactory subprocFactory = Mockito.mock(SubprocedureFactory.class);
    List<Pair<ProcedureMember, ZKProcedureMemberRpcs>> members = new ArrayList<>(expected.size());
    for (String member : expected) {
        ZKWatcher watcher = newZooKeeperWatcher();
        ZKProcedureMemberRpcs controller = new ZKProcedureMemberRpcs(watcher, opDescription);
        ThreadPoolExecutor pool2 = ProcedureMember.defaultPool(member, 1, KEEP_ALIVE);
        ProcedureMember mem = new ProcedureMember(controller, pool2, subprocFactory);
        members.add(new Pair<>(mem, controller));
        controller.start(member, mem);
    }
    // setup mock subprocedures
    final List<Subprocedure> cohortTasks = new ArrayList<>();
    final int[] elem = new int[1];
    for (int i = 0; i < members.size(); i++) {
        ForeignExceptionDispatcher cohortMonitor = new ForeignExceptionDispatcher();
        final ProcedureMember comms = members.get(i).getFirst();
        Subprocedure commit = Mockito.spy(new SubprocedureImpl(comms, opName, cohortMonitor, WAKE_FREQUENCY, TIMEOUT));
        // This nasty bit has one of the impls throw a TimeoutException
        Mockito.doAnswer(new Answer<Void>() {

            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                int index = elem[0];
                if (index == memberErrorIndex) {
                    LOG.debug("Sending error to coordinator");
                    ForeignException remoteCause = new ForeignException("TIMER", new TimeoutException("subprocTimeout", 1, 2, 0));
                    Subprocedure r = ((Subprocedure) invocation.getMock());
                    LOG.error("Remote commit failure, not propagating error:" + remoteCause);
                    comms.receiveAbortProcedure(r.getName(), remoteCause);
                    assertTrue(r.isComplete());
                    // notification (which ensures that we never progress past prepare)
                    try {
                        Procedure.waitForLatch(coordinatorReceivedErrorLatch, new ForeignExceptionDispatcher(), WAKE_FREQUENCY, "coordinator received error");
                    } catch (InterruptedException e) {
                        LOG.debug("Wait for latch interrupted, done:" + (coordinatorReceivedErrorLatch.getCount() == 0));
                        // reset the interrupt status on the thread
                        Thread.currentThread().interrupt();
                    }
                }
                elem[0] = ++index;
                return null;
            }
        }).when(commit).acquireBarrier();
        cohortTasks.add(commit);
    }
    // pass out a task per member
    final AtomicInteger taskIndex = new AtomicInteger();
    Mockito.when(subprocFactory.buildSubprocedure(Mockito.eq(opName), (byte[]) Mockito.argThat(new ArrayEquals(data)))).thenAnswer(new Answer<Subprocedure>() {

        @Override
        public Subprocedure answer(InvocationOnMock invocation) throws Throwable {
            int index = taskIndex.getAndIncrement();
            Subprocedure commit = cohortTasks.get(index);
            return commit;
        }
    });
    // setup spying on the coordinator
    ForeignExceptionDispatcher coordinatorTaskErrorMonitor = Mockito.spy(new ForeignExceptionDispatcher());
    Procedure coordinatorTask = Mockito.spy(new Procedure(coordinator, coordinatorTaskErrorMonitor, WAKE_FREQUENCY, TIMEOUT, opName, data, expected));
    when(coordinator.createProcedure(any(), eq(opName), eq(data), anyListOf(String.class))).thenReturn(coordinatorTask);
    // count down the error latch when we get the remote error
    Mockito.doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            // pass on the error to the master
            invocation.callRealMethod();
            // then count down the got error latch
            coordinatorReceivedErrorLatch.countDown();
            return null;
        }
    }).when(coordinatorTask).receive(Mockito.any());
    // ----------------------------
    // start running the operation
    // ----------------------------
    Procedure task = coordinator.startProcedure(coordinatorTaskErrorMonitor, opName, data, expected);
    assertEquals("Didn't mock coordinator task", coordinatorTask, task);
    // wait for the task to complete
    try {
        task.waitForCompleted();
    } catch (ForeignException fe) {
    // this may get caught or may not
    }
    // -------------
    // verification
    // -------------
    // always expect prepared, never committed, and possible to have cleanup and finish (racy since
    // error case)
    waitAndVerifyProc(coordinatorTask, once, never(), once, atMost(1), true);
    verifyCohortSuccessful(expected, subprocFactory, cohortTasks, once, never(), once, once, true);
    // close all the open things
    closeAll(coordinator, coordinatorController, members);
}
Also used : ArrayList(java.util.ArrayList) ArrayEquals(org.mockito.internal.matchers.ArrayEquals) SubprocedureImpl(org.apache.hadoop.hbase.procedure.Subprocedure.SubprocedureImpl) ZKWatcher(org.apache.hadoop.hbase.zookeeper.ZKWatcher) ForeignException(org.apache.hadoop.hbase.errorhandling.ForeignException) Pair(org.apache.hadoop.hbase.util.Pair) TimeoutException(org.apache.hadoop.hbase.errorhandling.TimeoutException) CountDownLatch(java.util.concurrent.CountDownLatch) ForeignExceptionDispatcher(org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) Test(org.junit.Test)

Aggregations

ArrayList (java.util.ArrayList)2 ThreadPoolExecutor (java.util.concurrent.ThreadPoolExecutor)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 ForeignExceptionDispatcher (org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher)2 SubprocedureImpl (org.apache.hadoop.hbase.procedure.Subprocedure.SubprocedureImpl)2 Pair (org.apache.hadoop.hbase.util.Pair)2 ZKWatcher (org.apache.hadoop.hbase.zookeeper.ZKWatcher)2 ArrayEquals (org.mockito.internal.matchers.ArrayEquals)2 InvocationOnMock (org.mockito.invocation.InvocationOnMock)2 List (java.util.List)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ForeignException (org.apache.hadoop.hbase.errorhandling.ForeignException)1 TimeoutException (org.apache.hadoop.hbase.errorhandling.TimeoutException)1 Test (org.junit.Test)1