From bd986b4300521eb829bbaac2a749423be157001e Mon Sep 17 00:00:00 2001 From: Gian Merlino Date: Mon, 29 Dec 2025 07:05:04 -0800 Subject: [PATCH 1/2] Add virtualStorageFabricEvictImmediately config. The purpose of this config is to enable using SegmentLocalCacheManager for loading segments on MSQ worker tasks, where segments are not assigned by load/drop rules, and where there is not generally a specific maxSize configured for the local cache. We need to evict segments immediately so local disks don't fill up. The main changes: 1) In StorageLocation, update the releaseHold runnable to check for evictImmediately. If it is set, unmount the cache entry if all holds have been released. 2) In SegmentLocalCacheManager, when evictImmediately is set, "mount" sets an onUnmount handler to delete the info file. --- .../segment/loading/SegmentLoaderConfig.java | 9 ++ .../loading/SegmentLocalCacheManager.java | 30 ++++-- .../segment/loading/StorageLocation.java | 91 +++++++++++++------ .../loading/SegmentLocalCacheManagerTest.java | 88 ++++++++++++++++++ 4 files changed, 185 insertions(+), 33 deletions(-) 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 e4822f0661b7..5a1689137823 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 @@ -77,6 +77,9 @@ public class SegmentLoaderConfig @JsonProperty("virtualStorageLoadThreads") private int virtualStorageLoadThreads = 2 * runtimeInfo.getAvailableProcessors(); + @JsonProperty("virtualStorageFabricEvictImmediately") + private boolean virtualStorageFabricEvictImmediately = false; + private long combinedMaxSize = 0; public List getLocations() @@ -154,6 +157,11 @@ public int getVirtualStorageLoadThreads() return virtualStorageLoadThreads; } + public boolean isVirtualStorageFabricEvictImmediately() + { + return virtualStorageFabricEvictImmediately; + } + public SegmentLoaderConfig withLocations(List locations) { SegmentLoaderConfig retVal = new SegmentLoaderConfig(); @@ -195,6 +203,7 @@ public String toString() ", statusQueueMaxSize=" + statusQueueMaxSize + ", useVirtualStorageFabric=" + virtualStorage + ", virtualStorageFabricLoadThreads=" + virtualStorageLoadThreads + + ", virtualStorageFabricEvictImmediately=" + virtualStorageFabricEvictImmediately + ", combinedMaxSize=" + combinedMaxSize + '}'; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java b/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java index a38e63450a37..2cb668dda8ab 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java +++ b/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java @@ -145,6 +145,11 @@ public SegmentLocalCacheManager( if (config.getNumThreadsToLoadSegmentsIntoPageCacheOnBootstrap() > 0) { throw DruidException.defensive("Invalid configuration: virtualStorage is incompatible with numThreadsToLoadSegmentsIntoPageCacheOnBootstrap"); } + if (config.isVirtualStorageFabricEvictImmediately()) { + for (StorageLocation location : locations) { + location.setEvictImmediately(true); + } + } virtualStorageLoadOnDemandExec = MoreExecutors.listeningDecorator( // probably replace this with virtual threads once minimum version is java 21 @@ -333,7 +338,6 @@ public void storeInfoFile(final DataSegment segment) throws IOException @Override public void removeInfoFile(final DataSegment segment) { - final Runnable delete = () -> deleteSegmentInfoFile(segment); final SegmentCacheEntryIdentifier entryId = new SegmentCacheEntryIdentifier(segment.getId()); boolean isCached = false; // defer deleting until the unmount operation of the cache entry, if possible, so that if the process stops before @@ -341,13 +345,13 @@ public void removeInfoFile(final DataSegment segment) for (StorageLocation location : locations) { final SegmentCacheEntry cacheEntry = location.getCacheEntry(entryId); if (cacheEntry != null) { - isCached = isCached || cacheEntry.setOnUnmount(delete); + isCached = isCached || cacheEntry.setDeleteInfoFileOnUnmount(); } } // otherwise we are probably deleting for cleanup reasons, so try it anyway if it wasn't present in any location if (!isCached) { - delete.run(); + deleteSegmentInfoFile(segment); } } @@ -430,7 +434,7 @@ public AcquireSegmentAction acquireSegment(final DataSegment dataSegment) throws jsonMapper.writeValue(out, dataSegment); return null; }); - hold.getEntry().setOnUnmount(() -> deleteSegmentInfoFile(dataSegment)); + hold.getEntry().setDeleteInfoFileOnUnmount(); } return new AcquireSegmentAction( @@ -492,6 +496,11 @@ private AcquireSegmentAction acquireExistingSegment(SegmentCacheEntryIdentifier public void load(final DataSegment dataSegment) throws SegmentLoadingException { if (config.isVirtualStorage()) { + if (config.isVirtualStorageFabricEvictImmediately()) { + throw DruidException.defensive( + "load() should not be called when virtualStorageFabricEvictImmediately is enabled" + ); + } // virtual storage doesn't do anything with loading immediately, but check to see if the segment is already cached // and if so, clear out the onUnmount action final ReferenceCountingLock lock = lock(dataSegment); @@ -533,6 +542,11 @@ public void bootstrap( ) throws SegmentLoadingException { if (config.isVirtualStorage()) { + if (config.isVirtualStorageFabricEvictImmediately()) { + throw DruidException.defensive( + "bootstrap() should not be called when virtualStorageFabricEvictImmediately is enabled" + ); + } // during bootstrap, check if the segment exists in a location and mount it, getCachedSegments already // did the reserving for us final SegmentCacheEntryIdentifier id = new SegmentCacheEntryIdentifier(dataSegment.getId()); @@ -1031,6 +1045,10 @@ public void mount(StorageLocation mountLocation) throws SegmentLoadingException ); unmount(); } + + if (config.isVirtualStorageFabricEvictImmediately()) { + setDeleteInfoFileOnUnmount(); + } } catch (SegmentLoadingException e) { try { @@ -1104,12 +1122,12 @@ public synchronized Optional acquireReference() return referenceProvider.acquireReference(); } - public synchronized boolean setOnUnmount(Runnable runnable) + public synchronized boolean setDeleteInfoFileOnUnmount() { if (location == null) { return false; } - onUnmount.set(runnable); + onUnmount.set(() -> deleteSegmentInfoFile(dataSegment)); return true; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java b/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java index ba0341e9d5bc..d239dc3c13ba 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java +++ b/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java @@ -106,9 +106,7 @@ public class StorageLocation @GuardedBy("lock") private WeakCacheEntry hand; - /** - * Current total size of files in bytes, including weak entries. - */ + private volatile boolean evictImmediately = false; /** * Current total size of files in bytes, including weak entries. @@ -171,6 +169,14 @@ public File getPath() return path; } + /** + * Sets whether weak cache entries should be immediately evicted once all holds are released. + */ + public void setEvictImmediately(final boolean evictImmediately) + { + this.evictImmediately = evictImmediately; + } + public T getStaticCacheEntry(CacheEntryIdentifier entryId) { lock.readLock().lock(); @@ -340,7 +346,10 @@ public ReservationHold addWeakReservationHoldIfExists( if (existingEntry != null && existingEntry.hold()) { existingEntry.visited = true; weakStats.getAndUpdate(WeakStats::hit); - return new ReservationHold<>((T) existingEntry.cacheEntry, existingEntry::release); + return new ReservationHold<>( + (T) existingEntry.cacheEntry, + createWeakEntryReleaseRunnable(existingEntry, false) + ); } return null; } @@ -374,7 +383,10 @@ public ReservationHold addWeakReservationHold( if (retryExistingEntry != null && retryExistingEntry.hold()) { retryExistingEntry.visited = true; weakStats.getAndUpdate(WeakStats::hit); - return new ReservationHold<>((T) retryExistingEntry.cacheEntry, retryExistingEntry::release); + return new ReservationHold<>( + (T) retryExistingEntry.cacheEntry, + createWeakEntryReleaseRunnable(retryExistingEntry, false) + ); } final CacheEntry newEntry = entrySupplier.get(); final ReclaimResult reclaimResult = canHandleWeak(newEntry); @@ -388,28 +400,7 @@ public ReservationHold addWeakReservationHold( weakStats.getAndUpdate(s -> s.load(newEntry.getSize())); hold = new ReservationHold<>( (T) newEntry, - () -> { - newWeakEntry.release(); - lock.writeLock().lock(); - try { - weakCacheEntries.computeIfPresent( - newEntry.getId(), - (cacheEntryIdentifier, weakCacheEntry) -> { - if (!weakCacheEntry.cacheEntry.isMounted()) { - // if we never successfully mounted, go ahead and remove so we don't have a dead entry - unlinkWeakEntry(weakCacheEntry); - // we call unmount anyway to terminate the phaser - weakCacheEntry.unmount(); - return null; - } - return weakCacheEntry; - } - ); - } - finally { - lock.writeLock().unlock(); - } - } + createWeakEntryReleaseRunnable(newWeakEntry, true) ); } else { weakStats.getAndUpdate(WeakStats::reject); @@ -444,6 +435,52 @@ public void release(CacheEntry entry) } } + /** + * Creates a release runnable for a {@link WeakCacheEntry} that handles immediate eviction when configured. + * If {@link #evictImmediately} is true and there are no more holds after releasing, the entry is immediately + * evicted from the cache. For new entries (isNewEntry=true), unmounted entries are also removed. + */ + private Runnable createWeakEntryReleaseRunnable( + final WeakCacheEntry weakEntry, + final boolean isNewEntry + ) + { + return () -> { + weakEntry.release(); + + if (!isNewEntry && !evictImmediately) { + // No need to consider removal from weakCacheEntries on hold release. + return; + } + + lock.writeLock().lock(); + try { + weakCacheEntries.computeIfPresent( + weakEntry.cacheEntry.getId(), + (cacheEntryIdentifier, weakCacheEntry) -> { + // If we never successfully mounted, go ahead and remove so we don't have a dead entry. + // Futhermore, if evictImmediately is set, evict on release if all holds are gone. + final boolean isMounted = weakCacheEntry.cacheEntry.isMounted(); + if ((isNewEntry && !isMounted) + || (evictImmediately && !weakCacheEntry.isHeld())) { + unlinkWeakEntry(weakCacheEntry); + weakCacheEntry.unmount(); // call even if never mounted, to terminate the phaser + if (isMounted) { + weakStats.getAndUpdate(s -> s.evict(weakCacheEntry.cacheEntry.getSize())); + } + return null; + } else { + return weakCacheEntry; + } + } + ); + } + finally { + lock.writeLock().unlock(); + } + }; + } + /** * Inserts a new {@link WeakCacheEntry}, inserting it as {@link #head} (or both {@link #head} and {@link #tail} if it * is the only entry), tracking size in {@link #currSizeBytes} and {@link #currWeakSizeBytes} diff --git a/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java b/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java index 2e7146b5f473..2d770f2bc1e3 100644 --- a/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java +++ b/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java @@ -1177,6 +1177,94 @@ public File getInfoDir() segmentActionAfterDrop.close(); } + @Test + public void testGetSegmentVirtualStorageFabricEvictImmediately() throws Exception + { + final StorageLocationConfig locationConfig = new StorageLocationConfig(localSegmentCacheDir, 10000L, null); + final File infoDir = tmpFolder.newFolder(); + final SegmentLoaderConfig loaderConfig = new SegmentLoaderConfig() + { + @Override + public List getLocations() + { + return ImmutableList.of(locationConfig); + } + + @Override + public boolean isVirtualStorage() + { + return true; + } + + @Override + public boolean isVirtualStorageFabricEvictImmediately() + { + return true; + } + + @Override + public File getInfoDir() + { + return infoDir; + } + }; + final List storageLocations = loaderConfig.toStorageLocations(); + final SegmentLocalCacheManager manager = new SegmentLocalCacheManager( + storageLocations, + loaderConfig, + new LeastBytesUsedStorageLocationSelectorStrategy(storageLocations), + TestHelper.getTestIndexIO(jsonMapper, ColumnConfig.DEFAULT), + jsonMapper + ); + + final DataSegment segmentToLoad = makeTestDataSegment(segmentDeepStorageDir); + createSegmentZipInLocation(segmentDeepStorageDir, TEST_DATA_RELATIVE_PATH); + + // Acquire the segment (load() is not allowed with evictImmediately) + AcquireSegmentAction segmentAction = manager.acquireSegment(segmentToLoad); + AcquireSegmentResult result = segmentAction.getSegmentFuture().get(); + Optional theSegment = result.getReferenceProvider().acquireReference(); + Assert.assertTrue(theSegment.isPresent()); + Assert.assertNotNull(manager.getSegmentFiles(segmentToLoad)); + Assert.assertEquals(segmentToLoad.getId(), theSegment.get().getId()); + + // Info file should exist + final File infoFile = new File(infoDir, segmentToLoad.getId().toString()); + Assert.assertTrue(infoFile.exists()); + + // Drop the segment while still holding + manager.drop(segmentToLoad); + + // Segment files and info file should still exist because we still have a hold + Assert.assertNotNull(manager.getSegmentFiles(segmentToLoad)); + Assert.assertTrue(infoFile.exists()); + + // Release the hold - with evictImmediately, the segment should be evicted immediately + theSegment.get().close(); + segmentAction.close(); + + // Both segment files and info file should be deleted + Assert.assertNull(manager.getSegmentFiles(segmentToLoad)); + Assert.assertFalse(infoFile.exists()); + + // Verify the segment can be loaded again if needed + AcquireSegmentAction segmentActionAfterEvict = manager.acquireSegment(segmentToLoad); + AcquireSegmentResult resultAfterEvict = segmentActionAfterEvict.getSegmentFuture().get(); + Optional theSegmentAfterEvict = resultAfterEvict.getReferenceProvider().acquireReference(); + Assert.assertTrue(theSegmentAfterEvict.isPresent()); + Assert.assertNotNull(manager.getSegmentFiles(segmentToLoad)); + Assert.assertEquals(segmentToLoad.getId(), theSegmentAfterEvict.get().getId()); + + // Info file should exist again + Assert.assertTrue(infoFile.exists()); + + theSegmentAfterEvict.get().close(); + segmentActionAfterEvict.close(); + + // After final release, info file should be deleted again + Assert.assertFalse(infoFile.exists()); + } + @Test public void testIfTombstoneIsLoaded() throws IOException, SegmentLoadingException { From b29d27f4009ea1f7874ce2b20df292ff44a691b0 Mon Sep 17 00:00:00 2001 From: Gian Merlino Date: Thu, 1 Jan 2026 17:59:01 -0800 Subject: [PATCH 2/2] Rename property to be more explicit. --- .../segment/loading/SegmentLoaderConfig.java | 28 +++++++++--- .../loading/SegmentLocalCacheManager.java | 14 +++--- .../segment/loading/StorageLocation.java | 12 +++--- .../loading/SegmentLoaderConfigTest.java | 43 +++++++++++++++++++ .../loading/SegmentLocalCacheManagerTest.java | 2 +- 5 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderConfigTest.java 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 5a1689137823..28570a0e7800 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 @@ -77,8 +77,13 @@ public class SegmentLoaderConfig @JsonProperty("virtualStorageLoadThreads") private int virtualStorageLoadThreads = 2 * runtimeInfo.getAvailableProcessors(); - @JsonProperty("virtualStorageFabricEvictImmediately") - private boolean virtualStorageFabricEvictImmediately = false; + /** + * When enabled, weakly-held cache entries are evicted immediately upon release of all holds, rather than + * waiting for space pressure to trigger eviction. This setting is not intended to be configured directly by + * administrators. Instead, it is expected to be set when appropriate via {@link #setVirtualStorage}. + */ + @JsonProperty("virtualStorageFabricEvictImmediatelyOnHoldRelease") + private boolean virtualStorageFabricEvictImmediatelyOnHoldRelease = false; private long combinedMaxSize = 0; @@ -157,9 +162,9 @@ public int getVirtualStorageLoadThreads() return virtualStorageLoadThreads; } - public boolean isVirtualStorageFabricEvictImmediately() + public boolean isVirtualStorageFabricEvictImmediatelyOnHoldRelease() { - return virtualStorageFabricEvictImmediately; + return virtualStorageFabricEvictImmediatelyOnHoldRelease; } public SegmentLoaderConfig withLocations(List locations) @@ -171,6 +176,19 @@ public SegmentLoaderConfig withLocations(List locations) return retVal; } + /** + * Sets {@link #virtualStorage} and {@link #virtualStorageFabricEvictImmediatelyOnHoldRelease}. + */ + public SegmentLoaderConfig setVirtualStorage( + boolean virtualStorage, + boolean virtualStorageFabricEvictImmediatelyOnHoldRelease + ) + { + this.virtualStorage = virtualStorage; + this.virtualStorageFabricEvictImmediatelyOnHoldRelease = virtualStorageFabricEvictImmediatelyOnHoldRelease; + return this; + } + /** * Convert a list of {@link StorageLocationConfig} objects to {@link StorageLocation} objects. *

@@ -203,7 +221,7 @@ public String toString() ", statusQueueMaxSize=" + statusQueueMaxSize + ", useVirtualStorageFabric=" + virtualStorage + ", virtualStorageFabricLoadThreads=" + virtualStorageLoadThreads + - ", virtualStorageFabricEvictImmediately=" + virtualStorageFabricEvictImmediately + + ", virtualStorageFabricEvictImmediatelyOnHoldRelease=" + virtualStorageFabricEvictImmediatelyOnHoldRelease + ", combinedMaxSize=" + combinedMaxSize + '}'; } diff --git a/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java b/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java index 2cb668dda8ab..2103cc0aade9 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java +++ b/server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java @@ -145,9 +145,9 @@ public SegmentLocalCacheManager( if (config.getNumThreadsToLoadSegmentsIntoPageCacheOnBootstrap() > 0) { throw DruidException.defensive("Invalid configuration: virtualStorage is incompatible with numThreadsToLoadSegmentsIntoPageCacheOnBootstrap"); } - if (config.isVirtualStorageFabricEvictImmediately()) { + if (config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()) { for (StorageLocation location : locations) { - location.setEvictImmediately(true); + location.setEvictImmediatelyOnHoldRelease(true); } } virtualStorageLoadOnDemandExec = @@ -496,9 +496,9 @@ private AcquireSegmentAction acquireExistingSegment(SegmentCacheEntryIdentifier public void load(final DataSegment dataSegment) throws SegmentLoadingException { if (config.isVirtualStorage()) { - if (config.isVirtualStorageFabricEvictImmediately()) { + if (config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()) { throw DruidException.defensive( - "load() should not be called when virtualStorageFabricEvictImmediately is enabled" + "load() should not be called when virtualStorageFabricEvictImmediatelyOnHoldRelease is enabled" ); } // virtual storage doesn't do anything with loading immediately, but check to see if the segment is already cached @@ -542,9 +542,9 @@ public void bootstrap( ) throws SegmentLoadingException { if (config.isVirtualStorage()) { - if (config.isVirtualStorageFabricEvictImmediately()) { + if (config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()) { throw DruidException.defensive( - "bootstrap() should not be called when virtualStorageFabricEvictImmediately is enabled" + "bootstrap() should not be called when virtualStorageFabricEvictImmediatelyOnHoldRelease is enabled" ); } // during bootstrap, check if the segment exists in a location and mount it, getCachedSegments already @@ -1046,7 +1046,7 @@ public void mount(StorageLocation mountLocation) throws SegmentLoadingException unmount(); } - if (config.isVirtualStorageFabricEvictImmediately()) { + if (config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()) { setDeleteInfoFileOnUnmount(); } } diff --git a/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java b/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java index d239dc3c13ba..06ce140dc564 100644 --- a/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java +++ b/server/src/main/java/org/apache/druid/segment/loading/StorageLocation.java @@ -106,7 +106,7 @@ public class StorageLocation @GuardedBy("lock") private WeakCacheEntry hand; - private volatile boolean evictImmediately = false; + private volatile boolean evictImmediatelyOnHoldRelease = false; /** * Current total size of files in bytes, including weak entries. @@ -172,9 +172,9 @@ public File getPath() /** * Sets whether weak cache entries should be immediately evicted once all holds are released. */ - public void setEvictImmediately(final boolean evictImmediately) + public void setEvictImmediatelyOnHoldRelease(final boolean evictImmediatelyOnHoldRelease) { - this.evictImmediately = evictImmediately; + this.evictImmediatelyOnHoldRelease = evictImmediatelyOnHoldRelease; } public T getStaticCacheEntry(CacheEntryIdentifier entryId) @@ -448,7 +448,7 @@ private Runnable createWeakEntryReleaseRunnable( return () -> { weakEntry.release(); - if (!isNewEntry && !evictImmediately) { + if (!isNewEntry && !evictImmediatelyOnHoldRelease) { // No need to consider removal from weakCacheEntries on hold release. return; } @@ -459,10 +459,10 @@ private Runnable createWeakEntryReleaseRunnable( weakEntry.cacheEntry.getId(), (cacheEntryIdentifier, weakCacheEntry) -> { // If we never successfully mounted, go ahead and remove so we don't have a dead entry. - // Futhermore, if evictImmediately is set, evict on release if all holds are gone. + // Furthermore, if evictImmediatelyOnHoldRelease is set, evict on release if all holds are gone. final boolean isMounted = weakCacheEntry.cacheEntry.isMounted(); if ((isNewEntry && !isMounted) - || (evictImmediately && !weakCacheEntry.isHeld())) { + || (evictImmediatelyOnHoldRelease && !weakCacheEntry.isHeld())) { unlinkWeakEntry(weakCacheEntry); weakCacheEntry.unmount(); // call even if never mounted, to terminate the phaser if (isMounted) { diff --git a/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderConfigTest.java b/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderConfigTest.java new file mode 100644 index 000000000000..d0d51a6d3b0a --- /dev/null +++ b/server/src/test/java/org/apache/druid/segment/loading/SegmentLoaderConfigTest.java @@ -0,0 +1,43 @@ +/* + * 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 org.junit.Assert; +import org.junit.Test; + +public class SegmentLoaderConfigTest +{ + @Test + public void testSetVirtualStorage() + { + final SegmentLoaderConfig config = new SegmentLoaderConfig(); + + // Verify default values + Assert.assertFalse(config.isVirtualStorage()); + Assert.assertFalse(config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()); + + // Set both to true + config.setVirtualStorage(true, true); + + // Verify both fields are set + Assert.assertTrue(config.isVirtualStorage()); + Assert.assertTrue(config.isVirtualStorageFabricEvictImmediatelyOnHoldRelease()); + } +} diff --git a/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java b/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java index 2d770f2bc1e3..0af544e59a4d 100644 --- a/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java +++ b/server/src/test/java/org/apache/druid/segment/loading/SegmentLocalCacheManagerTest.java @@ -1197,7 +1197,7 @@ public boolean isVirtualStorage() } @Override - public boolean isVirtualStorageFabricEvictImmediately() + public boolean isVirtualStorageFabricEvictImmediatelyOnHoldRelease() { return true; }