/** * 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 com.twitter.distributedlog.service.balancer; import com.google.common.base.Optional; import com.google.common.util.concurrent.RateLimiter; import com.twitter.distributedlog.service.DistributedLogClient; import com.twitter.distributedlog.service.DistributedLogCluster.DLServer; import com.twitter.distributedlog.service.DistributedLogServerTestCase; import com.twitter.util.Await; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.util.Set; import static com.google.common.base.Charsets.*; import static org.junit.Assert.*; public class TestSimpleBalancer extends DistributedLogServerTestCase { static final Logger logger = LoggerFactory.getLogger(TestSimpleBalancer.class); DLClient targetClient; DLServer targetServer; @Before @Override public void setup() throws Exception { super.setup(); targetServer = createDistributedLogServer(7003); targetClient = createDistributedLogClient("target"); } @After @Override public void teardown() throws Exception { super.teardown(); if (null != targetClient) { targetClient.shutdown(); } if (null != targetServer) { targetServer.shutdown(); } } @Test(timeout = 60000) public void testBalanceAll() throws Exception { String namePrefix = "simplebalancer-balance-all-"; int numStreams = 10; for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; // src client dlClient.routingService.addHost(name, dlServer.getAddress()); // target client targetClient.routingService.addHost(name, targetServer.getAddress()); } // write to multiple streams for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; Await.result(((DistributedLogClient) dlClient.dlClient).write(name, ByteBuffer.wrap(("" + i).getBytes(UTF_8)))); } // validation for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; checkStream(name, dlClient, dlServer, 1, numStreams, numStreams, true, true); checkStream(name, targetClient, targetServer, 0, 0, 0, false, false); } Optional<RateLimiter> rateLimiter = Optional.absent(); Balancer balancer = new SimpleBalancer("source", dlClient.dlClient, dlClient.dlClient, "target", targetClient.dlClient, targetClient.dlClient); logger.info("Rebalancing from 'unknown' target"); try { balancer.balanceAll("unknown", 10, rateLimiter); fail("Should fail on balanceAll from 'unknown' target."); } catch (IllegalArgumentException iae) { // expected } // nothing to balance from 'target' logger.info("Rebalancing from 'target' target"); balancer.balanceAll("target", 1, rateLimiter); for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; checkStream(name, dlClient, dlServer, 1, numStreams, numStreams, true, true); checkStream(name, targetClient, targetServer, 0, 0, 0, false, false); } // balance all streams from 'source' logger.info("Rebalancing from 'source' target"); balancer.balanceAll("source", 10, rateLimiter); for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; checkStream(name, targetClient, targetServer, 1, numStreams, numStreams, true, true); checkStream(name, dlClient, dlServer, 0, 0, 0, false, false); } } @Test(timeout = 60000) public void testBalanceStreams() throws Exception { String namePrefix = "simplebalancer-balance-streams-"; int numStreams = 10; for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; // src client dlClient.routingService.addHost(name, dlServer.getAddress()); // target client targetClient.routingService.addHost(name, targetServer.getAddress()); } // write to multiple streams for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; Await.result(((DistributedLogClient) dlClient.dlClient).write(name, ByteBuffer.wrap(("" + i).getBytes(UTF_8)))); } // validation for (int i = 0; i < numStreams; i++) { String name = namePrefix + i; checkStream(name, dlClient, dlServer, 1, numStreams, numStreams, true, true); checkStream(name, targetClient, targetServer, 0, 0, 0, false, false); } Optional<RateLimiter> rateLimiter = Optional.absent(); Balancer balancer = new SimpleBalancer("source", dlClient.dlClient, dlClient.dlClient, "target", targetClient.dlClient, targetClient.dlClient); // balance all streams from 'source' logger.info("Rebalancing streams between targets"); balancer.balance(0, 0, 10, rateLimiter); Set<String> sourceStreams = getAllStreamsFromDistribution(getStreamOwnershipDistribution(dlClient)); Set<String> targetStreams = getAllStreamsFromDistribution(getStreamOwnershipDistribution(targetClient)); assertEquals(numStreams / 2, sourceStreams.size()); assertEquals(numStreams / 2, targetStreams.size()); for (String name : sourceStreams) { checkStream(name, dlClient, dlServer, 1, numStreams / 2, numStreams / 2, true, true); checkStream(name, targetClient, targetServer, 1, numStreams / 2, numStreams / 2, false, false); } for (String name : targetStreams) { checkStream(name, targetClient, targetServer, 1, numStreams / 2, numStreams / 2, true, true); checkStream(name, dlClient, dlServer, 1, numStreams / 2, numStreams / 2, false, false); } } }