blob: a2bfb5b4f86cb12ca8ec83fa811d30fdcf9ee089 [file] [log] [blame]
/*
* 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.druid.segment.loading;
import com.fasterxml.jackson.module.guice.ObjectMapperModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;
import org.apache.druid.guice.DruidGuiceExtensions;
import org.apache.druid.guice.JsonConfigProvider;
import org.apache.druid.guice.JsonConfigurator;
import org.apache.druid.guice.LazySingleton;
import org.apache.druid.guice.StorageNodeModule;
import org.apache.druid.jackson.DefaultObjectMapper;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import javax.validation.Validation;
import javax.validation.Validator;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
public class StorageLocationSelectorStrategyTest
{
@Rule
public final TemporaryFolder tmpFolder = new TemporaryFolder();
@Test
public void testLeastBytesUsedLocationSelectorStrategy() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
final File localStorageFolder2 = tmpFolder.newFolder("local_storage_folder_2");
final File localStorageFolder3 = tmpFolder.newFolder("local_storage_folder_3");
StorageLocation storageLocation1 = new StorageLocation(localStorageFolder1, 10000000000L,
null);
storageLocations.add(storageLocation1);
storageLocations.add(new StorageLocation(localStorageFolder2, 10000000000L, null));
storageLocations.add(new StorageLocation(localStorageFolder3, 10000000000L, null));
StorageLocationSelectorStrategy leastBytesUsedStrategy =
new LeastBytesUsedStorageLocationSelectorStrategy(storageLocations);
storageLocation1.reserve("tmp_loc1", "__seg1", 1024L);
Iterator<StorageLocation> locations = leastBytesUsedStrategy.getLocations();
StorageLocation loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc1.getPath());
StorageLocation loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc2.getPath());
StorageLocation loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc3.getPath());
}
@Test
public void testRoundRobinLocationSelectorStrategySingleLocation() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
storageLocations.add(new StorageLocation(localStorageFolder1, 10000000000L, null));
StorageLocationSelectorStrategy roundRobinStrategy =
new RoundRobinStorageLocationSelectorStrategy(storageLocations);
Iterator<StorageLocation> locations = roundRobinStrategy.getLocations();
StorageLocation loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc1.getPath());
locations = roundRobinStrategy.getLocations();
StorageLocation loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc2.getPath());
}
@Test
public void testRoundRobinLocationSelectorStrategy() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
final File localStorageFolder2 = tmpFolder.newFolder("local_storage_folder_2");
final File localStorageFolder3 = tmpFolder.newFolder("local_storage_folder_3");
storageLocations.add(new StorageLocation(localStorageFolder1, 10000000000L, null));
storageLocations.add(new StorageLocation(localStorageFolder2, 10000000000L, null));
storageLocations.add(new StorageLocation(localStorageFolder3, 10000000000L, null));
StorageLocationSelectorStrategy roundRobinStrategy = new RoundRobinStorageLocationSelectorStrategy(storageLocations);
// First call to getLocations()
Iterator<StorageLocation> locations = roundRobinStrategy.getLocations();
StorageLocation loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc1.getPath());
StorageLocation loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc2.getPath());
StorageLocation loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc3.getPath());
// Second call to getLocations()
locations = roundRobinStrategy.getLocations();
loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc2.getPath());
loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc3.getPath());
loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc1.getPath());
}
@Test
public void testRoundRobinLocationSelectorStrategyMultipleCallsToGetLocations() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
final File localStorageFolder2 = tmpFolder.newFolder("local_storage_folder_2");
final File localStorageFolder3 = tmpFolder.newFolder("local_storage_folder_3");
storageLocations.add(new StorageLocation(localStorageFolder1, 10000000000L, null));
storageLocations.add(new StorageLocation(localStorageFolder2, 10000000000L, null));
storageLocations.add(new StorageLocation(localStorageFolder3, 10000000000L, null));
StorageLocationSelectorStrategy roundRobinStrategy = new RoundRobinStorageLocationSelectorStrategy(storageLocations);
Iterator<StorageLocation> locations = roundRobinStrategy.getLocations();
StorageLocation loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc1.getPath());
locations = roundRobinStrategy.getLocations();
StorageLocation loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc2.getPath());
locations = roundRobinStrategy.getLocations();
StorageLocation loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc3.getPath());
loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc1.getPath());
}
@Test
public void testRandomLocationSelectorStrategy() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
final File localStorageFolder2 = tmpFolder.newFolder("local_storage_folder_2");
final File localStorageFolder3 = tmpFolder.newFolder("local_storage_folder_3");
storageLocations.add(new StorageLocation(localStorageFolder1, 3000L, null));
storageLocations.add(new StorageLocation(localStorageFolder2, 2000L, null));
storageLocations.add(new StorageLocation(localStorageFolder3, 1000L, null));
StorageLocationSelectorStrategy leastBytesUsedStrategy =
new RandomStorageLocationSelectorStrategy(storageLocations);
Iterator<StorageLocation> locations = leastBytesUsedStrategy.getLocations();
StorageLocation loc1 = locations.next();
StorageLocation loc2 = locations.next();
StorageLocation loc3 = locations.next();
File[] result = new File[]{loc1.getPath(), loc2.getPath(), loc3.getPath()};
Arrays.sort(result);
Assert.assertArrayEquals(new File[]{localStorageFolder1, localStorageFolder2, localStorageFolder3}, result);
}
@Test
public void testMostAvailableSizeLocationSelectorStrategy() throws Exception
{
List<StorageLocation> storageLocations = new ArrayList<>();
final File localStorageFolder1 = tmpFolder.newFolder("local_storage_folder_1");
final File localStorageFolder2 = tmpFolder.newFolder("local_storage_folder_2");
final File localStorageFolder3 = tmpFolder.newFolder("local_storage_folder_3");
StorageLocation storageLocation1 = new StorageLocation(localStorageFolder1, 10000000000L, null);
storageLocations.add(storageLocation1);
StorageLocation storageLocation2 = new StorageLocation(localStorageFolder2, 20000000000L, null);
storageLocations.add(storageLocation2);
StorageLocation storageLocation3 = new StorageLocation(localStorageFolder3, 15000000000L, null);
storageLocations.add(storageLocation3);
StorageLocationSelectorStrategy mostAvailableStrategy = new MostAvailableSizeStorageLocationSelectorStrategy(storageLocations);
Iterator<StorageLocation> locations = mostAvailableStrategy.getLocations();
StorageLocation loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc1.getPath());
StorageLocation loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc2.getPath());
StorageLocation loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc3.getPath());
storageLocation2.reserve("tmp_loc2", "__seg2", 6000000000L);
locations = mostAvailableStrategy.getLocations();
loc1 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_3",
localStorageFolder3, loc1.getPath());
loc2 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_2",
localStorageFolder2, loc2.getPath());
loc3 = locations.next();
Assert.assertEquals("The next element of the iterator should point to path local_storage_folder_1",
localStorageFolder1, loc3.getPath());
}
@Test
public void testDefaultSelectorStrategyConfig()
{
//no druid.segmentCache.locationSelector.strategy specified, the default will be used
final Properties props = new Properties();
props.setProperty("druid.segmentCache.locations", "[{\"path\": \"/tmp/druid/indexCache\"}]");
StorageLocationSelectorStrategy strategy = makeInjectorWithProperties(props).getInstance(StorageLocationSelectorStrategy.class);
Assert.assertEquals(LeastBytesUsedStorageLocationSelectorStrategy.class,
strategy.getClass());
Assert.assertEquals("/tmp/druid/indexCache", strategy.getLocations().next().getPath().getAbsolutePath());
}
@Test
public void testRoundRobinSelectorStrategyConfig()
{
final Properties props = new Properties();
props.setProperty("druid.segmentCache.locations", "[{\"path\": \"/tmp/druid/indexCache\"}]");
props.setProperty("druid.segmentCache.locationSelector.strategy", "roundRobin");
Injector injector = makeInjectorWithProperties(props);
StorageLocationSelectorStrategy strategy = injector.getInstance(StorageLocationSelectorStrategy.class);
Assert.assertEquals(RoundRobinStorageLocationSelectorStrategy.class,
strategy.getClass());
Assert.assertEquals("/tmp/druid/indexCache", strategy.getLocations().next().getPath().getAbsolutePath());
}
@Test
public void testLeastBytesUsedSelectorStrategyConfig()
{
final Properties props = new Properties();
props.setProperty("druid.segmentCache.locations", "[{\"path\": \"/tmp/druid/indexCache\"}]");
props.setProperty("druid.segmentCache.locationSelector.strategy", "leastBytesUsed");
Injector injector = makeInjectorWithProperties(props);
StorageLocationSelectorStrategy strategy = injector.getInstance(StorageLocationSelectorStrategy.class);
Assert.assertEquals(LeastBytesUsedStorageLocationSelectorStrategy.class,
strategy.getClass());
Assert.assertEquals("/tmp/druid/indexCache", strategy.getLocations().next().getPath().getAbsolutePath());
}
@Test
public void testRandomSelectorStrategyConfig()
{
final Properties props = new Properties();
props.setProperty("druid.segmentCache.locations", "[{\"path\": \"/tmp/druid/indexCache\"}]");
props.setProperty("druid.segmentCache.locationSelector.strategy", "random");
Injector injector = makeInjectorWithProperties(props);
StorageLocationSelectorStrategy strategy = injector.getInstance(StorageLocationSelectorStrategy.class);
Assert.assertEquals(RandomStorageLocationSelectorStrategy.class,
strategy.getClass());
Assert.assertEquals("/tmp/druid/indexCache", strategy.getLocations().next().getPath().getAbsolutePath());
}
@Test
public void testMostAvailableSizeSelectorStrategyConfig()
{
final Properties props = new Properties();
props.setProperty("druid.segmentCache.locationSelector.strategy", "mostAvailableSize");
props.setProperty("druid.segmentCache.locations", "[{\"path\": \"/tmp/druid/indexCache\"}]");
Injector injector = makeInjectorWithProperties(props);
StorageLocationSelectorStrategy strategy = injector.getInstance(StorageLocationSelectorStrategy.class);
Assert.assertEquals(MostAvailableSizeStorageLocationSelectorStrategy.class,
strategy.getClass());
Assert.assertEquals("/tmp/druid/indexCache", strategy.getLocations().next().getPath().getAbsolutePath());
}
private Injector makeInjectorWithProperties(final Properties props)
{
return Guice.createInjector(
new Module()
{
@Override
public void configure(Binder binder)
{
//ObjectMapperModule introduce Guice injector for jackson
binder.install(new ObjectMapperModule()
.withObjectMapper(new DefaultObjectMapper()));
binder.install(new DruidGuiceExtensions());
binder.bind(Validator.class).toInstance(Validation.buildDefaultValidatorFactory().getValidator());
binder.bind(JsonConfigurator.class).in(LazySingleton.class);
binder.bind(Properties.class).toInstance(props);
JsonConfigProvider.bind(binder, "druid.segmentCache", SegmentLoaderConfig.class);
StorageNodeModule.bindLocationSelectorStrategy(binder);
}
@Provides
public List provideStorageLocation(SegmentLoaderConfig segmentLoader)
{
return segmentLoader.toStorageLocations();
}
}
);
}
}