diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 0755520907a8..640ab0c63b90 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -1409,7 +1409,7 @@ These Historical configurations can be defined in the `historical/runtime.proper |Property|Description|Default| |--------|-----------|-------| |`druid.segmentCache.locations`|Segments assigned to a Historical process are first stored on the local file system (in a disk cache) and then served by the Historical process. These locations define where that local cache resides. This value cannot be NULL or EMPTY. Here is an example `druid.segmentCache.locations=[{"path": "/mnt/druidSegments", "maxSize": "10k", "freeSpacePercent": 1.0}]`. "freeSpacePercent" is optional, if provided then enforces that much of free disk partition space while storing segments. But, it depends on File.getTotalSpace() and File.getFreeSpace() methods, so enable if only if they work for your File System.| none | -|`druid.segmentCache.locationSelectorStrategy`|The strategy used to select a location from the configured `druid.segmentCache.locations` for segment distribution. Possible values are `leastBytesUsed`, `roundRobin`, `random`, or `mostAvailableSize`. |leastBytesUsed| +|`druid.segmentCache.locationSelector.strategy`|The strategy used to select a location from the configured `druid.segmentCache.locations` for segment distribution. Possible values are `leastBytesUsed`, `roundRobin`, `random`, or `mostAvailableSize`. |leastBytesUsed| |`druid.segmentCache.deleteOnRemove`|Delete segment files from cache once a process is no longer serving a segment.|true| |`druid.segmentCache.dropSegmentDelayMillis`|How long a process delays before completely dropping segment.|30000 (30 seconds)| |`druid.segmentCache.infoDir`|Historical processes keep track of the segments they are serving so that when the process is restarted they can reload the same segments without waiting for the Coordinator to reassign. This path defines where this metadata is kept. Directory will be created if needed.|${first_location}/info_dir| @@ -1421,7 +1421,7 @@ These Historical configurations can be defined in the `historical/runtime.proper In `druid.segmentCache.locations`, *freeSpacePercent* was added because *maxSize* setting is only a theoretical limit and assumes that much space will always be available for storing segments. In case of any druid bug leading to unaccounted segment files left alone on disk or some other process writing stuff to disk, This check can start failing segment loading early before filling up the disk completely and leaving the host usable otherwise. -In `druid.segmentCache.locationSelectorStrategy`, one of leastBytesUsed, roundRobin, random, or mostAvailableSize could be specified to represent the strategy to distribute segments across multiple segment cache locations. +In `druid.segmentCache.locationSelector.strategy`, one of `leastBytesUsed`, `roundRobin`, `random`, or `mostAvailableSize` could be specified to represent the strategy to distribute segments across multiple segment cache locations. |Strategy|Description| |--------|-----------| diff --git a/licenses.yaml b/licenses.yaml index e14f54abe909..4d58f08a9d06 100644 --- a/licenses.yaml +++ b/licenses.yaml @@ -231,6 +231,7 @@ libraries: - com.fasterxml.jackson.jaxrs: jackson-jaxrs-json-provider - com.fasterxml.jackson.jaxrs: jackson-jaxrs-smile-provider - com.fasterxml.jackson.module: jackson-module-jaxb-annotations + - com.fasterxml.jackson.module: jackson-module-guice notice: | # Jackson JSON processor @@ -4126,16 +4127,6 @@ libraries: --- -name: "Jackson Module: Guice" -license_category: binary -module: java-core -license_name: Apache License version 2.0 -version: 2.6.7 -libraries: - - com.fasterxml.jackson.module: jackson-module-guice - ---- - name: Google APIs Client Library For Java license_category: binary module: java-core diff --git a/server/pom.xml b/server/pom.xml index caddf483bdc5..01b0d034d251 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -315,6 +315,10 @@ io.timeandspace cron-scheduler + + com.fasterxml.jackson.module + jackson-module-guice + diff --git a/server/src/main/java/org/apache/druid/guice/StorageNodeModule.java b/server/src/main/java/org/apache/druid/guice/StorageNodeModule.java index d3750a735a09..a232f6d01aac 100644 --- a/server/src/main/java/org/apache/druid/guice/StorageNodeModule.java +++ b/server/src/main/java/org/apache/druid/guice/StorageNodeModule.java @@ -33,11 +33,14 @@ import org.apache.druid.query.DruidProcessingConfig; import org.apache.druid.segment.column.ColumnConfig; import org.apache.druid.segment.loading.SegmentLoaderConfig; +import org.apache.druid.segment.loading.StorageLocation; +import org.apache.druid.segment.loading.StorageLocationSelectorStrategy; import org.apache.druid.server.DruidNode; import org.apache.druid.server.coordination.DruidServerMetadata; import org.apache.druid.server.coordination.ServerType; import javax.annotation.Nullable; +import java.util.List; /** */ @@ -52,6 +55,7 @@ public void configure(Binder binder) { JsonConfigProvider.bind(binder, "druid.server", DruidServerConfig.class); JsonConfigProvider.bind(binder, "druid.segmentCache", SegmentLoaderConfig.class); + bindLocationSelectorStrategy(binder); binder.bind(ServerTypeConfig.class).toProvider(Providers.of(null)); binder.bind(ColumnConfig.class).to(DruidProcessingConfig.class); @@ -117,4 +121,23 @@ public Boolean isSegmentCacheConfigured(SegmentLoaderConfig segmentLoaderConfig) { return !segmentLoaderConfig.getLocations().isEmpty(); } + + /** + * provide a list of StorageLocation + * so that it can be injected into objects such as implementations of {@link StorageLocationSelectorStrategy} + */ + @Provides + @LazySingleton + public List provideStorageLocation(SegmentLoaderConfig config) + { + return config.toStorageLocations(); + } + + /** + * a helper method for both storage module and independent unit test cases + */ + public static void bindLocationSelectorStrategy(Binder binder) + { + JsonConfigProvider.bind(binder, "druid.segmentCache.locationSelector", StorageLocationSelectorStrategy.class); + } } diff --git a/server/src/main/java/org/apache/druid/segment/loading/LeastBytesUsedStorageLocationSelectorStrategy.java b/server/src/main/java/org/apache/druid/segment/loading/LeastBytesUsedStorageLocationSelectorStrategy.java index e1e94185c50a..bcc37e3eed68 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/LeastBytesUsedStorageLocationSelectorStrategy.java +++ b/server/src/main/java/org/apache/druid/segment/loading/LeastBytesUsedStorageLocationSelectorStrategy.java @@ -19,6 +19,8 @@ package org.apache.druid.segment.loading; +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; import com.google.common.collect.Ordering; import java.util.Comparator; @@ -34,9 +36,10 @@ public class LeastBytesUsedStorageLocationSelectorStrategy implements StorageLoc private static final Ordering ORDERING = Ordering.from(Comparator .comparingLong(StorageLocation::currSizeBytes)); - private List storageLocations; + private final List storageLocations; - public LeastBytesUsedStorageLocationSelectorStrategy(List storageLocations) + @JsonCreator + public LeastBytesUsedStorageLocationSelectorStrategy(@JacksonInject final List storageLocations) { this.storageLocations = storageLocations; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/MostAvailableSizeStorageLocationSelectorStrategy.java b/server/src/main/java/org/apache/druid/segment/loading/MostAvailableSizeStorageLocationSelectorStrategy.java index 4790f90a33e3..4e4a84c42621 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/MostAvailableSizeStorageLocationSelectorStrategy.java +++ b/server/src/main/java/org/apache/druid/segment/loading/MostAvailableSizeStorageLocationSelectorStrategy.java @@ -19,6 +19,8 @@ package org.apache.druid.segment.loading; +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; import com.google.common.collect.Ordering; import java.util.Comparator; @@ -35,9 +37,10 @@ public class MostAvailableSizeStorageLocationSelectorStrategy implements Storage .comparingLong(StorageLocation::availableSizeBytes) .reversed()); - private List storageLocations; + private final List storageLocations; - public MostAvailableSizeStorageLocationSelectorStrategy(List storageLocations) + @JsonCreator + public MostAvailableSizeStorageLocationSelectorStrategy(@JacksonInject final List storageLocations) { this.storageLocations = storageLocations; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/RandomStorageLocationSelectorStrategy.java b/server/src/main/java/org/apache/druid/segment/loading/RandomStorageLocationSelectorStrategy.java index 85df8601088a..ed0114aa8463 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/RandomStorageLocationSelectorStrategy.java +++ b/server/src/main/java/org/apache/druid/segment/loading/RandomStorageLocationSelectorStrategy.java @@ -19,6 +19,9 @@ package org.apache.druid.segment.loading; +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; + import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -33,7 +36,8 @@ public class RandomStorageLocationSelectorStrategy implements StorageLocationSel private final List storageLocations; - public RandomStorageLocationSelectorStrategy(List storageLocations) + @JsonCreator + public RandomStorageLocationSelectorStrategy(@JacksonInject final List storageLocations) { this.storageLocations = storageLocations; } @@ -45,5 +49,4 @@ public Iterator getLocations() Collections.shuffle(copyLocation); return copyLocation.iterator(); } - } diff --git a/server/src/main/java/org/apache/druid/segment/loading/RoundRobinStorageLocationSelectorStrategy.java b/server/src/main/java/org/apache/druid/segment/loading/RoundRobinStorageLocationSelectorStrategy.java index 5e702c936ce8..95e57f5130e4 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/RoundRobinStorageLocationSelectorStrategy.java +++ b/server/src/main/java/org/apache/druid/segment/loading/RoundRobinStorageLocationSelectorStrategy.java @@ -19,6 +19,9 @@ package org.apache.druid.segment.loading; +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; + import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -32,11 +35,11 @@ */ public class RoundRobinStorageLocationSelectorStrategy implements StorageLocationSelectorStrategy { - private final List storageLocations; private final AtomicInteger startIndex = new AtomicInteger(0); - public RoundRobinStorageLocationSelectorStrategy(List storageLocations) + @JsonCreator + public RoundRobinStorageLocationSelectorStrategy(@JacksonInject List storageLocations) { this.storageLocations = storageLocations; } @@ -44,7 +47,8 @@ public RoundRobinStorageLocationSelectorStrategy(List storageLo @Override public Iterator getLocations() { - return new Iterator() { + return new Iterator() + { private final int numStorageLocations = storageLocations.size(); private int remainingIterations = numStorageLocations; @@ -73,5 +77,4 @@ public StorageLocation next() } }; } - } diff --git a/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderConfig.java b/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderConfig.java index edd2c0ddb6aa..b2cf07580cfe 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderConfig.java +++ b/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderConfig.java @@ -20,7 +20,6 @@ package org.apache.druid.segment.loading; import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import org.apache.druid.utils.JvmUtils; @@ -28,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * @@ -55,9 +55,6 @@ public class SegmentLoaderConfig @JsonProperty("numBootstrapThreads") private Integer numBootstrapThreads = null; - @JsonProperty("locationSelectorStrategy") - private StorageLocationSelectorStrategy locationSelectorStrategy; - @JsonProperty private File infoDir = null; @@ -101,15 +98,6 @@ public int getNumBootstrapThreads() return numBootstrapThreads == null ? numLoadingThreads : numBootstrapThreads; } - public StorageLocationSelectorStrategy getStorageLocationSelectorStrategy(List storageLocations) - { - if (locationSelectorStrategy == null) { - // default strategy if no strategy is specified in the config - locationSelectorStrategy = new LeastBytesUsedStorageLocationSelectorStrategy(storageLocations); - } - return locationSelectorStrategy; - } - public File getInfoDir() { if (infoDir == null) { @@ -140,11 +128,19 @@ public SegmentLoaderConfig withLocations(List locations) return retVal; } - @VisibleForTesting - SegmentLoaderConfig withStorageLocationSelectorStrategy(StorageLocationSelectorStrategy strategy) + /** + * Convert StorageLocationConfig objects to StorageLocation objects + * + * Note: {@link #getLocations} is called instead of variable access because some testcases overrides this method + */ + public List toStorageLocations() { - this.locationSelectorStrategy = strategy; - return this; + return this.getLocations() + .stream() + .map(locationConfig -> new StorageLocation(locationConfig.getPath(), + locationConfig.getMaxSize(), + locationConfig.getFreeSpacePercent())) + .collect(Collectors.toList()); } @Override @@ -154,7 +150,6 @@ public String toString() "locations=" + locations + ", deleteOnRemove=" + deleteOnRemove + ", dropSegmentDelayMillis=" + dropSegmentDelayMillis + - ", locationSelectorStrategy=" + locationSelectorStrategy + ", infoDir=" + infoDir + '}'; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManager.java b/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManager.java index 80e8dc6015f2..2aa203824883 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManager.java +++ b/server/src/main/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManager.java @@ -30,9 +30,9 @@ import org.apache.druid.segment.Segment; import org.apache.druid.timeline.DataSegment; +import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -82,24 +82,48 @@ public class SegmentLoaderLocalCacheManager implements SegmentLoader @Inject public SegmentLoaderLocalCacheManager( IndexIO indexIO, + List locations, SegmentLoaderConfig config, + @Nonnull StorageLocationSelectorStrategy strategy, @Json ObjectMapper mapper ) { this.indexIO = indexIO; this.config = config; this.jsonMapper = mapper; - this.locations = new ArrayList<>(); - for (StorageLocationConfig locationConfig : config.getLocations()) { - locations.add( - new StorageLocation( - locationConfig.getPath(), - locationConfig.getMaxSize(), - locationConfig.getFreeSpacePercent() - ) - ); - } - this.strategy = config.getStorageLocationSelectorStrategy(locations); + this.locations = locations; + this.strategy = strategy; + log.info("Using storage location strategy: [%s]", this.strategy.getClass().getSimpleName()); + } + + @VisibleForTesting + SegmentLoaderLocalCacheManager( + IndexIO indexIO, + SegmentLoaderConfig config, + @Nonnull StorageLocationSelectorStrategy strategy, + @Json ObjectMapper mapper + ) + { + this(indexIO, config.toStorageLocations(), config, strategy, mapper); + } + + /** + * creates instance with default storage location selector strategy + * + * This ctor is mainly for test cases, including test cases in other modules + */ + public SegmentLoaderLocalCacheManager( + IndexIO indexIO, + SegmentLoaderConfig config, + @Json ObjectMapper mapper + ) + { + this.indexIO = indexIO; + this.config = config; + this.jsonMapper = mapper; + this.locations = config.toStorageLocations(); + this.strategy = new LeastBytesUsedStorageLocationSelectorStrategy(locations); + log.info("Using storage location strategy: [%s]", this.strategy.getClass().getSimpleName()); } @Override diff --git a/server/src/main/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategy.java b/server/src/main/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategy.java index adc73887b878..57977d6cf9b8 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategy.java +++ b/server/src/main/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategy.java @@ -34,7 +34,7 @@ * https://github.com/apache/druid/pull/8038#discussion_r325520829 of PR https://github * .com/apache/druid/pull/8038 for more details. */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "strategy", defaultImpl = LeastBytesUsedStorageLocationSelectorStrategy.class) @JsonSubTypes(value = { @JsonSubTypes.Type(name = "leastBytesUsed", value = LeastBytesUsedStorageLocationSelectorStrategy.class), diff --git a/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManagerTest.java b/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManagerTest.java index 3130696a1d47..a01aef455406 100644 --- a/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManagerTest.java +++ b/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderLocalCacheManagerTest.java @@ -422,9 +422,8 @@ public void testSegmentDistributionUsingRoundRobinStrategy() throws Exception manager = new SegmentLoaderLocalCacheManager( TestHelper.getTestIndexIO(), - new SegmentLoaderConfig().withLocations(locationConfigs).withStorageLocationSelectorStrategy( - new RoundRobinStorageLocationSelectorStrategy(locations) - ), + new SegmentLoaderConfig().withLocations(locationConfigs), + new RoundRobinStorageLocationSelectorStrategy(locations), jsonMapper ); final File segmentSrcFolder = tmpFolder.newFolder("segmentSrcFolder"); @@ -669,21 +668,12 @@ public void testSegmentDistributionUsingRandomStrategy() throws Exception locationConfigs.add(locationConfig2); locationConfigs.add(locationConfig3); - List locations = new ArrayList<>(); - for (StorageLocationConfig locConfig : locationConfigs) { - locations.add( - new StorageLocation( - locConfig.getPath(), - locConfig.getMaxSize(), - null - ) - ); - } + SegmentLoaderConfig segmentLoaderConfig = new SegmentLoaderConfig().withLocations(locationConfigs); + manager = new SegmentLoaderLocalCacheManager( TestHelper.getTestIndexIO(), - new SegmentLoaderConfig().withLocations(locationConfigs).withStorageLocationSelectorStrategy( - new RandomStorageLocationSelectorStrategy(locations) - ), + new SegmentLoaderConfig().withLocations(locationConfigs), + new RandomStorageLocationSelectorStrategy(segmentLoaderConfig.toStorageLocations()), jsonMapper ); diff --git a/server/src/test/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategyTest.java b/server/src/test/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategyTest.java index 82cbe7025973..a2bfb5b4f86c 100644 --- a/server/src/test/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategyTest.java +++ b/server/src/test/java/org/apache/druid/segment/loading/StorageLocationSelectorStrategyTest.java @@ -19,16 +19,31 @@ 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 { @@ -256,4 +271,107 @@ public void testMostAvailableSizeLocationSelectorStrategy() throws Exception 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(); + } + } + ); + } }