From af68d6a010fd534b85f721d3559ff8c5df970501 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Wed, 9 Dec 2020 17:42:53 -0300 Subject: [PATCH 1/3] added splitCache and splitFetcher refactor --- .../io/split/client/SplitFactoryImpl.java | 5 +- .../split/engine/cache/InMemoryCacheImp.java | 92 +++++++++++++++++++ .../io/split/engine/cache/SplitCache.java | 20 ++++ .../experiments/RefreshableSplitFetcher.java | 86 ++++++----------- .../RefreshableSplitFetcherProvider.java | 24 ++--- .../RefreshableSplitFetcherTest.java | 27 +++--- 6 files changed, 172 insertions(+), 82 deletions(-) create mode 100644 client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java create mode 100644 client/src/main/java/io/split/engine/cache/SplitCache.java diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 7a3bfb43f..15cbb09e8 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -11,6 +11,8 @@ import io.split.client.metrics.CachedMetrics; import io.split.client.metrics.FireAndForgetMetrics; import io.split.client.metrics.HttpMetrics; +import io.split.engine.cache.InMemoryCacheImp; +import io.split.engine.cache.SplitCache; import io.split.engine.evaluator.Evaluator; import io.split.engine.evaluator.EvaluatorImp; import io.split.engine.SDKReadinessGates; @@ -200,7 +202,8 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn // Feature Changes SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(httpclient, rootTarget, uncachedFireAndForget); - final RefreshableSplitFetcherProvider splitFetcherProvider = new RefreshableSplitFetcherProvider(splitChangeFetcher, splitParser, findPollingPeriod(RANDOM, config.featuresRefreshRate()), gates); + final SplitCache cache = new InMemoryCacheImp(-1); + final RefreshableSplitFetcherProvider splitFetcherProvider = new RefreshableSplitFetcherProvider(splitChangeFetcher, splitParser, findPollingPeriod(RANDOM, config.featuresRefreshRate()), gates, cache); List impressionListeners = new ArrayList<>(); diff --git a/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java b/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java new file mode 100644 index 000000000..51a7075f4 --- /dev/null +++ b/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java @@ -0,0 +1,92 @@ +package io.split.engine.cache; + +import com.google.common.collect.Maps; +import io.split.engine.experiments.ParsedSplit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +public class InMemoryCacheImp implements SplitCache { + + private static final Logger _log = LoggerFactory.getLogger(InMemoryCacheImp.class); + + private final ConcurrentMap _concurrentMap; + private AtomicLong _changeNumber; + + public InMemoryCacheImp(long startingChangeNumber) { + _concurrentMap = Maps.newConcurrentMap(); + _changeNumber = new AtomicLong(startingChangeNumber); + } + + @Override + public void put(ParsedSplit split) { + _concurrentMap.put(split.feature(), split); + } + + @Override + public void putAll(Map splits) { + _concurrentMap.putAll(splits); + } + + @Override + public boolean remove(String name) { + ParsedSplit removed = _concurrentMap.remove(name); + + return removed != null; + } + + @Override + public ParsedSplit get(String name) { + return _concurrentMap.get(name); + } + + @Override + public Collection getAll() { + return _concurrentMap.values(); + } + + @Override + public Collection getMany(List names) { + List splits = new ArrayList<>(); + + for (String name : names) { + ParsedSplit split = _concurrentMap.get(name); + + if (split != null) { + splits.add(split); + } + } + + return splits; + } + + @Override + public long getChangeNumber() { + return _changeNumber.get(); + } + + @Override + public void setChangeNumber(long changeNumber) { + if (changeNumber < _changeNumber.get()) { + _log.error("ChangeNumber for splits cache is less than previous"); + } + + _changeNumber.set(changeNumber); + } + + @Override + public boolean trafficTypeExists(String trafficType) { + return false; + } + + @Override + public void clear() { + _concurrentMap.clear(); + } +} diff --git a/client/src/main/java/io/split/engine/cache/SplitCache.java b/client/src/main/java/io/split/engine/cache/SplitCache.java new file mode 100644 index 000000000..dae418bd5 --- /dev/null +++ b/client/src/main/java/io/split/engine/cache/SplitCache.java @@ -0,0 +1,20 @@ +package io.split.engine.cache; + +import io.split.engine.experiments.ParsedSplit; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public interface SplitCache { + void put(ParsedSplit split); + void putAll(Map splits); + boolean remove(String name); + ParsedSplit get(String name); + Collection getAll(); + Collection getMany(List names); + long getChangeNumber(); + void setChangeNumber(long changeNumber); + boolean trafficTypeExists(String trafficType); + void clear(); +} diff --git a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java index 4ef49750f..3aa689774 100644 --- a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java +++ b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java @@ -6,13 +6,11 @@ import com.google.common.collect.Multiset; import com.google.common.collect.Multisets; import com.google.common.collect.Sets; -import io.split.client.dtos.Condition; -import io.split.client.dtos.Matcher; -import io.split.client.dtos.MatcherType; import io.split.client.dtos.Split; import io.split.client.dtos.SplitChange; import io.split.client.dtos.Status; import io.split.engine.SDKReadinessGates; +import io.split.engine.cache.SplitCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +18,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; import static com.google.common.base.Preconditions.checkNotNull; @@ -35,9 +32,9 @@ public class RefreshableSplitFetcher implements SplitFetcher, Runnable { private final SplitParser _parser; private final SplitChangeFetcher _splitChangeFetcher; - private final AtomicLong _changeNumber; - - private Map _concurrentMap = Maps.newConcurrentMap(); + private final SplitCache _splitCache; + private final SDKReadinessGates _gates; + private final Object _lock = new Object(); /** * Contains all the traffic types that are currently being used by the splits and also the count @@ -49,35 +46,12 @@ public class RefreshableSplitFetcher implements SplitFetcher, Runnable { * an ARCHIVED split is received, we know if we need to remove a traffic type from the multiset. */ Multiset _concurrentTrafficTypeNameSet = ConcurrentHashMultiset.create(); - private final SDKReadinessGates _gates; - - private final Object _lock = new Object(); - - public RefreshableSplitFetcher(SplitChangeFetcher splitChangeFetcher, SplitParser parser, SDKReadinessGates gates) { - this(splitChangeFetcher, parser, gates, -1); - } - - /** - * This constructor is package private because it is meant primarily for unit tests - * where we want to set the starting change number. All regular clients should use - * the public constructor. - * - * @param splitChangeFetcher MUST NOT be null - * @param parser MUST NOT be null - * @param startingChangeNumber - */ - /*package private*/ RefreshableSplitFetcher(SplitChangeFetcher splitChangeFetcher, - SplitParser parser, - SDKReadinessGates gates, - long startingChangeNumber) { - _splitChangeFetcher = splitChangeFetcher; - _parser = parser; - _gates = gates; - _changeNumber = new AtomicLong(startingChangeNumber); - - checkNotNull(_parser); - checkNotNull(_splitChangeFetcher); + public RefreshableSplitFetcher(SplitChangeFetcher splitChangeFetcher, SplitParser parser, SDKReadinessGates gates, SplitCache splitCache) { + _splitChangeFetcher = checkNotNull(splitChangeFetcher); + _parser = checkNotNull(parser); + _gates = checkNotNull(gates); + _splitCache = checkNotNull(splitCache); } @Override @@ -85,9 +59,9 @@ public void forceRefresh() { _log.debug("Force Refresh splits starting ..."); try { while (true) { - long start = _changeNumber.get(); + long start = _splitCache.getChangeNumber(); runWithoutExceptionHandling(); - long end = _changeNumber.get(); + long end = _splitCache.getChangeNumber(); if (start >= end) { break; @@ -103,13 +77,13 @@ public void forceRefresh() { @Override public long changeNumber() { - return _changeNumber.get(); + return _splitCache.getChangeNumber(); } @Override public void killSplit(String splitName, String defaultTreatment, long changeNumber) { synchronized (_lock) { - ParsedSplit parsedSplit = _concurrentMap.get(splitName); + ParsedSplit parsedSplit = _splitCache.get(splitName); ParsedSplit updatedSplit = new ParsedSplit(parsedSplit.feature(), parsedSplit.seed(), @@ -123,17 +97,17 @@ public void killSplit(String splitName, String defaultTreatment, long changeNumb parsedSplit.algo(), parsedSplit.configurations()); - _concurrentMap.put(splitName, updatedSplit); + _splitCache.put(updatedSplit); } } @Override public ParsedSplit fetch(String test) { - return _concurrentMap.get(test); + return _splitCache.get(test); } public List fetchAll() { - return Lists.newArrayList(_concurrentMap.values()); + return Lists.newArrayList(_splitCache.getAll()); } @Override @@ -145,18 +119,18 @@ public Set fetchKnownTrafficTypes() { } public Collection fetch() { - return _concurrentMap.values(); + return _splitCache.getAll(); } public void clear() { - _concurrentMap.clear(); + _splitCache.clear(); _concurrentTrafficTypeNameSet.clear(); } @Override public void run() { _log.debug("Fetch splits starting ..."); - long start = _changeNumber.get(); + long start = _splitCache.getChangeNumber(); try { runWithoutExceptionHandling(); _gates.splitsAreReady(); @@ -170,38 +144,38 @@ public void run() { } } finally { if (_log.isDebugEnabled()) { - _log.debug("split fetch before: " + start + ", after: " + _changeNumber.get()); + _log.debug("split fetch before: " + start + ", after: " + _splitCache.getChangeNumber()); } } } public void runWithoutExceptionHandling() throws InterruptedException { - SplitChange change = _splitChangeFetcher.fetch(_changeNumber.get()); + SplitChange change = _splitChangeFetcher.fetch(_splitCache.getChangeNumber()); if (change == null) { throw new IllegalStateException("SplitChange was null"); } - if (change.till == _changeNumber.get()) { + if (change.till == _splitCache.getChangeNumber()) { // no change. return; } - if (change.since != _changeNumber.get() || change.till < _changeNumber.get()) { + if (change.since != _splitCache.getChangeNumber() || change.till < _splitCache.getChangeNumber()) { // some other thread may have updated the shared state. exit return; } if (change.splits.isEmpty()) { // there are no changes. weird! - _changeNumber.set(change.till); + _splitCache.setChangeNumber(change.till); return; } synchronized (_lock) { // check state one more time. - if (change.since != _changeNumber.get() - || change.till < _changeNumber.get()) { + if (change.since != _splitCache.getChangeNumber() + || change.till < _splitCache.getChangeNumber()) { // some other thread may have updated the shared state. exit return; } @@ -243,7 +217,7 @@ public void runWithoutExceptionHandling() throws InterruptedException { // If it's deleted & recreated, the old one should be decreased and the new one increased. // To handle both cases, we simply delete the old one if the split is present. // The new one is always increased. - ParsedSplit current = _concurrentMap.get(split.name); + ParsedSplit current = _splitCache.get(split.name); if (current != null && current.trafficTypeName() != null) { trafficTypeNamesToRemove.add(current.trafficTypeName()); } @@ -253,13 +227,13 @@ public void runWithoutExceptionHandling() throws InterruptedException { } } - _concurrentMap.putAll(toAdd); + _splitCache.putAll(toAdd); _concurrentTrafficTypeNameSet.addAll(trafficTypeNamesToAdd); //removeAll does not work here, since it wont remove all the occurrences, just one Multisets.removeOccurrences(_concurrentTrafficTypeNameSet, trafficTypeNamesToRemove); for (String remove : toRemove) { - _concurrentMap.remove(remove); + _splitCache.remove(remove); } if (!toAdd.isEmpty()) { @@ -270,7 +244,7 @@ public void runWithoutExceptionHandling() throws InterruptedException { _log.debug("Deleted features: " + toRemove); } - _changeNumber.set(change.till); + _splitCache.setChangeNumber(change.till); } } } diff --git a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcherProvider.java b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcherProvider.java index 04760b941..5113a9a85 100644 --- a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcherProvider.java +++ b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcherProvider.java @@ -2,6 +2,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.split.engine.SDKReadinessGates; +import io.split.engine.cache.SplitCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,30 +28,26 @@ public class RefreshableSplitFetcherProvider implements Closeable { private static final Logger _log = LoggerFactory.getLogger(RefreshableSplitFetcherProvider.class); + private final AtomicReference _splitFetcher = new AtomicReference(); + private final AtomicReference _executorService = new AtomicReference<>(); private final SplitParser _splitParser; private final SplitChangeFetcher _splitChangeFetcher; private final AtomicLong _refreshEveryNSeconds; - private final AtomicReference _splitFetcher = new AtomicReference(); private final SDKReadinessGates _gates; - private final AtomicReference _executorService = new AtomicReference<>(); private final ScheduledExecutorService _scheduledExecutorService; private final Object _lock = new Object(); private final AtomicBoolean _running; + private final SplitCache _splitCache; private ScheduledFuture _scheduledFuture; - public RefreshableSplitFetcherProvider(SplitChangeFetcher splitChangeFetcher, SplitParser splitParser, long refreshEveryNSeconds, SDKReadinessGates sdkBuildBlocker) { - _splitChangeFetcher = splitChangeFetcher; - checkNotNull(_splitChangeFetcher); - - _splitParser = splitParser; - checkNotNull(_splitParser); - + public RefreshableSplitFetcherProvider(SplitChangeFetcher splitChangeFetcher, SplitParser splitParser, long refreshEveryNSeconds, SDKReadinessGates sdkBuildBlocker, SplitCache splitCache) { + _splitChangeFetcher = checkNotNull(splitChangeFetcher); + _splitParser = checkNotNull(splitParser); checkArgument(refreshEveryNSeconds >= 0L); _refreshEveryNSeconds = new AtomicLong(refreshEveryNSeconds); - - _gates = sdkBuildBlocker; - checkNotNull(_gates); + _gates = checkNotNull(sdkBuildBlocker); + _splitCache = checkNotNull(splitCache); ThreadFactory threadFactory = new ThreadFactoryBuilder() .setDaemon(true) @@ -75,7 +72,7 @@ public RefreshableSplitFetcher getFetcher() { return _splitFetcher.get(); } - RefreshableSplitFetcher splitFetcher = new RefreshableSplitFetcher(_splitChangeFetcher, _splitParser, _gates); + RefreshableSplitFetcher splitFetcher = new RefreshableSplitFetcher(_splitChangeFetcher, _splitParser, _gates, _splitCache); _splitFetcher.set(splitFetcher); return splitFetcher; @@ -130,5 +127,4 @@ public void close() { Thread.currentThread().interrupt(); } } - } diff --git a/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java b/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java index dd00b0744..5477bb5d6 100644 --- a/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java +++ b/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java @@ -10,6 +10,8 @@ import io.split.client.dtos.Status; import io.split.engine.ConditionsTestUtil; import io.split.engine.SDKReadinessGates; +import io.split.engine.cache.InMemoryCacheImp; +import io.split.engine.cache.SplitCache; import io.split.engine.matchers.AllKeysMatcher; import io.split.engine.matchers.CombiningMatcher; import io.split.engine.segments.NoChangeSegmentChangeFetcher; @@ -63,8 +65,9 @@ private void works(long startingChangeNumber) throws InterruptedException { SegmentFetcher segmentFetcher = new StaticSegmentFetcher(Collections.emptyMap()); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(startingChangeNumber); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), gates, startingChangeNumber); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), gates, cache); // execute the fetcher for a little bit. executeWaitAndTerminate(fetcher, 1, 3, TimeUnit.SECONDS); @@ -133,8 +136,8 @@ public void when_parser_fails_we_remove_the_experiment() throws InterruptedExcep when(splitChangeFetcher.fetch(0L)).thenReturn(invalidReturn); when(splitChangeFetcher.fetch(1L)).thenReturn(noReturn); - - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), new SDKReadinessGates(), -1L); + SplitCache cache = new InMemoryCacheImp(-1); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), new SDKReadinessGates(), cache); // execute the fetcher for a little bit. executeWaitAndTerminate(fetcher, 1, 5, TimeUnit.SECONDS); @@ -148,11 +151,12 @@ public void when_parser_fails_we_remove_the_experiment() throws InterruptedExcep public void if_there_is_a_problem_talking_to_split_change_count_down_latch_is_not_decremented() throws Exception { SegmentFetcher segmentFetcher = new StaticSegmentFetcher(Collections.emptyMap()); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(-1); SplitChangeFetcher splitChangeFetcher = mock(SplitChangeFetcher.class); when(splitChangeFetcher.fetch(-1L)).thenThrow(new RuntimeException()); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), gates, -1L); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(splitChangeFetcher, new SplitParser(segmentFetcher), gates, cache); // execute the fetcher for a little bit. executeWaitAndTerminate(fetcher, 1, 5, TimeUnit.SECONDS); @@ -186,11 +190,12 @@ public void works_with_user_defined_segments() throws Exception { String segmentName = "foosegment"; AChangePerCallSplitChangeFetcher experimentChangeFetcher = new AChangePerCallSplitChangeFetcher(segmentName); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(startingChangeNumber); SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); segmentFetcher.startPeriodicFetching(); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(experimentChangeFetcher, new SplitParser(segmentFetcher), gates, startingChangeNumber); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(experimentChangeFetcher, new SplitParser(segmentFetcher), gates, cache); // execute the fetcher for a little bit. executeWaitAndTerminate(fetcher, 1, 5, TimeUnit.SECONDS); @@ -212,13 +217,13 @@ public void works_with_user_defined_segments() throws Exception { @Test public void fetch_traffic_type_names_works_with_adds() throws Exception { - long startingChangeNumber = -1; SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(-1); SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, startingChangeNumber); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); // Before, it should be empty Set usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); @@ -258,13 +263,13 @@ public void fetch_traffic_type_names_works_with_adds() throws Exception { @Test public void fetch_traffic_type_names_already_existing_split() throws Exception { - long startingChangeNumber = -1; SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(-1); SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, startingChangeNumber); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); // Before, it should be empty Set usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); @@ -296,13 +301,13 @@ public void fetch_traffic_type_names_already_existing_split() throws Exception { @Test public void fetch_traffic_type_names_works_with_remove() throws Exception { - long startingChangeNumber = -1; SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); SDKReadinessGates gates = new SDKReadinessGates(); + SplitCache cache = new InMemoryCacheImp(-1); SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, startingChangeNumber); + RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); Set expected = Sets.newHashSet(); From 0bc7d5682f1418dc2f74fb2852d999613ee6dbe8 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Thu, 10 Dec 2020 12:50:32 -0300 Subject: [PATCH 2/3] traffic type exists refactor --- .../java/io/split/client/SplitClientImpl.java | 2 +- .../split/engine/cache/InMemoryCacheImp.java | 30 +++- .../io/split/engine/cache/SplitCache.java | 5 +- .../experiments/RefreshableSplitFetcher.java | 62 ++----- .../engine/experiments/SplitFetcher.java | 11 +- .../split/engine/cache/InMemoryCacheTest.java | 98 +++++++++++ .../RefreshableSplitFetcherTest.java | 159 ++---------------- 7 files changed, 150 insertions(+), 217 deletions(-) create mode 100644 client/src/test/java/io/split/engine/cache/InMemoryCacheTest.java diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 140e581d1..4b61c7d6c 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -192,7 +192,7 @@ private boolean track(Event event) { event.trafficTypeName = event.trafficTypeName.toLowerCase(); } - if (!_splitFetcher.fetchKnownTrafficTypes().contains(event.trafficTypeName)) { + if (!_splitFetcher.trafficTypeExists(event.trafficTypeName)) { _log.warn("track: Traffic Type " + event.trafficTypeName + " does not have any corresponding Splits in this environment, " + "make sure you’re tracking your events to a valid traffic type defined in the Split console."); } diff --git a/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java b/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java index 51a7075f4..af4e5e4d1 100644 --- a/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java +++ b/client/src/main/java/io/split/engine/cache/InMemoryCacheImp.java @@ -1,6 +1,9 @@ package io.split.engine.cache; +import com.google.common.collect.ConcurrentHashMultiset; import com.google.common.collect.Maps; +import com.google.common.collect.Multiset; +import com.google.common.collect.Sets; import io.split.engine.experiments.ParsedSplit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,7 +11,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; @@ -17,27 +20,37 @@ public class InMemoryCacheImp implements SplitCache { private static final Logger _log = LoggerFactory.getLogger(InMemoryCacheImp.class); private final ConcurrentMap _concurrentMap; + private final Multiset _concurrentTrafficTypeNameSet; + private AtomicLong _changeNumber; + public InMemoryCacheImp() { + this(-1); + } + public InMemoryCacheImp(long startingChangeNumber) { _concurrentMap = Maps.newConcurrentMap(); _changeNumber = new AtomicLong(startingChangeNumber); + _concurrentTrafficTypeNameSet = ConcurrentHashMultiset.create(); } @Override public void put(ParsedSplit split) { _concurrentMap.put(split.feature(), split); - } - @Override - public void putAll(Map splits) { - _concurrentMap.putAll(splits); + if (split.trafficTypeName() != null) { + _concurrentTrafficTypeNameSet.add(split.trafficTypeName()); + } } @Override public boolean remove(String name) { ParsedSplit removed = _concurrentMap.remove(name); + if (removed != null && removed.trafficTypeName() != null) { + _concurrentTrafficTypeNameSet.remove(removed.trafficTypeName()); + } + return removed != null; } @@ -81,12 +94,15 @@ public void setChangeNumber(long changeNumber) { } @Override - public boolean trafficTypeExists(String trafficType) { - return false; + public boolean trafficTypeExists(String trafficTypeName) { + // If the multiset has [{"user",2}.{"account",0}], elementSet only returns + // ["user"] (it ignores "account") + return Sets.newHashSet(_concurrentTrafficTypeNameSet.elementSet()).contains(trafficTypeName); } @Override public void clear() { _concurrentMap.clear(); + _concurrentTrafficTypeNameSet.clear(); } } diff --git a/client/src/main/java/io/split/engine/cache/SplitCache.java b/client/src/main/java/io/split/engine/cache/SplitCache.java index dae418bd5..3ab9916bd 100644 --- a/client/src/main/java/io/split/engine/cache/SplitCache.java +++ b/client/src/main/java/io/split/engine/cache/SplitCache.java @@ -4,17 +4,16 @@ import java.util.Collection; import java.util.List; -import java.util.Map; +import java.util.Set; public interface SplitCache { void put(ParsedSplit split); - void putAll(Map splits); boolean remove(String name); ParsedSplit get(String name); Collection getAll(); Collection getMany(List names); long getChangeNumber(); void setChangeNumber(long changeNumber); - boolean trafficTypeExists(String trafficType); + boolean trafficTypeExists(String trafficTypeName); void clear(); } diff --git a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java index 3aa689774..1fd8d5088 100644 --- a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java +++ b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java @@ -1,11 +1,6 @@ package io.split.engine.experiments; -import com.google.common.collect.ConcurrentHashMultiset; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multiset; -import com.google.common.collect.Multisets; -import com.google.common.collect.Sets; import io.split.client.dtos.Split; import io.split.client.dtos.SplitChange; import io.split.client.dtos.Status; @@ -16,8 +11,6 @@ import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -45,7 +38,6 @@ public class RefreshableSplitFetcher implements SplitFetcher, Runnable { * The count is used to maintain how many splits are using a traffic type, so when * an ARCHIVED split is received, we know if we need to remove a traffic type from the multiset. */ - Multiset _concurrentTrafficTypeNameSet = ConcurrentHashMultiset.create(); public RefreshableSplitFetcher(SplitChangeFetcher splitChangeFetcher, SplitParser parser, SDKReadinessGates gates, SplitCache splitCache) { _splitChangeFetcher = checkNotNull(splitChangeFetcher); @@ -111,11 +103,8 @@ public List fetchAll() { } @Override - public Set fetchKnownTrafficTypes() { - // We return the "keys" of the multiset that have a count greater than 0 - // If the multiset has [{"user",2}.{"account",0}], elementSet only returns - // ["user"] (it ignores "account") - return Sets.newHashSet(_concurrentTrafficTypeNameSet.elementSet()); + public boolean trafficTypeExists(String trafficTypeName) { + return _splitCache.trafficTypeExists(trafficTypeName); } public Collection fetch() { @@ -124,7 +113,6 @@ public Collection fetch() { public void clear() { _splitCache.clear(); - _concurrentTrafficTypeNameSet.clear(); } @Override @@ -180,11 +168,6 @@ public void runWithoutExceptionHandling() throws InterruptedException { return; } - Set toRemove = Sets.newHashSet(); - Map toAdd = Maps.newHashMap(); - List trafficTypeNamesToRemove = Lists.newArrayList(); - List trafficTypeNamesToAdd = Lists.newArrayList(); - for (Split split : change.splits) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -192,25 +175,20 @@ public void runWithoutExceptionHandling() throws InterruptedException { if (split.status != Status.ACTIVE) { // archive. - toRemove.add(split.name); - if (split.trafficTypeName != null) { - trafficTypeNamesToRemove.add(split.trafficTypeName); - } + _splitCache.remove(split.name); continue; } ParsedSplit parsedSplit = _parser.parse(split); if (parsedSplit == null) { _log.info("We could not parse the experiment definition for: " + split.name + " so we are removing it completely to be careful"); - toRemove.add(split.name); - if (split.trafficTypeName != null) { - trafficTypeNamesToRemove.add(split.trafficTypeName); - } + + _splitCache.remove(split.name); + _log.debug("Deleted feature: " + split.name); + continue; } - toAdd.put(split.name, parsedSplit); - // If the split already exists, this is either an update, or the split has been // deleted and recreated (possibly with a different traffic type). // If it's an update, the traffic type should NOT be increased. @@ -218,30 +196,12 @@ public void runWithoutExceptionHandling() throws InterruptedException { // To handle both cases, we simply delete the old one if the split is present. // The new one is always increased. ParsedSplit current = _splitCache.get(split.name); - if (current != null && current.trafficTypeName() != null) { - trafficTypeNamesToRemove.add(current.trafficTypeName()); - } - - if (split.trafficTypeName != null) { - trafficTypeNamesToAdd.add(split.trafficTypeName); + if (current != null) { + _splitCache.remove(split.name); } - } - - _splitCache.putAll(toAdd); - _concurrentTrafficTypeNameSet.addAll(trafficTypeNamesToAdd); - //removeAll does not work here, since it wont remove all the occurrences, just one - Multisets.removeOccurrences(_concurrentTrafficTypeNameSet, trafficTypeNamesToRemove); - - for (String remove : toRemove) { - _splitCache.remove(remove); - } - - if (!toAdd.isEmpty()) { - _log.debug("Updated features: " + toAdd.keySet()); - } - if (!toRemove.isEmpty()) { - _log.debug("Deleted features: " + toRemove); + _splitCache.put(parsedSplit); + _log.debug("Updated feature: " + parsedSplit.feature()); } _splitCache.setChangeNumber(change.till); diff --git a/client/src/main/java/io/split/engine/experiments/SplitFetcher.java b/client/src/main/java/io/split/engine/experiments/SplitFetcher.java index 585a53846..203fbb588 100644 --- a/client/src/main/java/io/split/engine/experiments/SplitFetcher.java +++ b/client/src/main/java/io/split/engine/experiments/SplitFetcher.java @@ -1,7 +1,6 @@ package io.split.engine.experiments; import java.util.List; -import java.util.Set; /** * Created by adilaijaz on 5/8/15. @@ -11,15 +10,7 @@ public interface SplitFetcher { List fetchAll(); - /** - * Fetches all the traffic types that are being used by the splits that are currently stored. - * - * For example, if the fetcher currently contains three splits, one of traffic type "account" - * and two of traffic type "user", this method will return ["account", "user"] - * - * @return a set of all the traffic types used by the parsed splits - */ - Set fetchKnownTrafficTypes(); + boolean trafficTypeExists(String trafficTypeName); /** * Forces a sync of splits, outside of any scheduled diff --git a/client/src/test/java/io/split/engine/cache/InMemoryCacheTest.java b/client/src/test/java/io/split/engine/cache/InMemoryCacheTest.java new file mode 100644 index 000000000..58db3905a --- /dev/null +++ b/client/src/test/java/io/split/engine/cache/InMemoryCacheTest.java @@ -0,0 +1,98 @@ +package io.split.engine.cache; + +import io.split.engine.experiments.ParsedSplit; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.*; + +public class InMemoryCacheTest { + private SplitCache _cache; + + @Before + public void before() { + _cache = new InMemoryCacheImp(); + } + + @Test + public void putAndGetSplit() { + ParsedSplit split = getParsedSplit("split_name"); + _cache.put(split); + + ParsedSplit result = _cache.get("split_name"); + Assert.assertNotNull(result); + Assert.assertEquals(split.changeNumber(), result.changeNumber()); + Assert.assertEquals(split.trafficTypeName(), result.trafficTypeName()); + Assert.assertEquals(split.defaultTreatment(), result.defaultTreatment()); + } + + @Test + public void putDuplicateSplit() { + ParsedSplit split = getParsedSplit("split_name"); + ParsedSplit split2 = getParsedSplit("split_name"); + _cache.put(split); + _cache.put(split2); + + int result = _cache.getAll().size(); + + Assert.assertEquals(1, result); + } + + @Test + public void getInExistentSplit() { + ParsedSplit split = getParsedSplit("split_name"); + _cache.put(split); + + ParsedSplit result = _cache.get("split_name_2"); + Assert.assertNull(result); + } + + @Test + public void removeSplit() { + ParsedSplit split = getParsedSplit("split_name"); + ParsedSplit split2 = getParsedSplit("split_name_2"); + _cache.put(split); + _cache.put(split2); + + int result = _cache.getAll().size(); + Assert.assertEquals(2, result); + + _cache.remove("split_name"); + result = _cache.getAll().size(); + Assert.assertEquals(1, result); + + Assert.assertNull(_cache.get("split_name")); + } + + @Test + public void setAndGetChangeNumber() { + _cache.setChangeNumber(223); + + long changeNumber = _cache.getChangeNumber(); + Assert.assertEquals(223, changeNumber); + + _cache.setChangeNumber(539); + changeNumber = _cache.getChangeNumber(); + Assert.assertEquals(539, changeNumber); + } + + @Test + public void getMany() { + _cache.put(getParsedSplit("split_name_1")); + _cache.put(getParsedSplit("split_name_2")); + _cache.put(getParsedSplit("split_name_3")); + _cache.put(getParsedSplit("split_name_4")); + + List names = new ArrayList<>(); + names.add("split_name_2"); + names.add("split_name_3"); + + Collection result = _cache.getMany(names); + Assert.assertEquals(2, result.size()); + } + + private ParsedSplit getParsedSplit(String splitName) { + return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2); + } +} diff --git a/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java b/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java index 5477bb5d6..67e07b45b 100644 --- a/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java +++ b/client/src/test/java/io/split/engine/experiments/RefreshableSplitFetcherTest.java @@ -1,7 +1,6 @@ package io.split.engine.experiments; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import io.split.client.dtos.Condition; import io.split.client.dtos.Matcher; import io.split.client.dtos.MatcherGroup; @@ -21,16 +20,13 @@ import io.split.engine.segments.StaticSegment; import io.split.engine.segments.StaticSegmentFetcher; import io.split.grammar.Treatments; -import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -40,7 +36,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -216,7 +212,7 @@ public void works_with_user_defined_segments() throws Exception { } @Test - public void fetch_traffic_type_names_works_with_adds() throws Exception { + public void trafficTypesExist() { SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); SDKReadinessGates gates = new SDKReadinessGates(); SplitCache cache = new InMemoryCacheImp(-1); @@ -225,146 +221,19 @@ public void fetch_traffic_type_names_works_with_adds() throws Exception { SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); - // Before, it should be empty - Set usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Set expected = Sets.newHashSet(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, it starts with since -1; - changeFetcher.addSplitForSince(-1L, "test_1", "user"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("user"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 0; - changeFetcher.addSplitForSince(0L, "test_2", "user"); - changeFetcher.addSplitForSince(0L, "test_3", "account"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("account"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 1; - changeFetcher.addSplitForSince(1L, "test_4", "experiment"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("experiment"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 2; - changeFetcher.addSplitForSince(2L, "test_2", "user"); - changeFetcher.addSplitForSince(2L, "test_4", "account"); - changeFetcher.addSplitForSince(2L, "test_5", "experiment"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - } + cache.put(ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2)); + cache.put(ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2)); + cache.put(ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2)); + cache.put(ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2)); - @Test - public void fetch_traffic_type_names_already_existing_split() throws Exception { - SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); - SDKReadinessGates gates = new SDKReadinessGates(); - SplitCache cache = new InMemoryCacheImp(-1); + assertTrue(fetcher.trafficTypeExists("tt_2")); + assertTrue(fetcher.trafficTypeExists("tt")); + assertFalse(fetcher.trafficTypeExists("tt_5")); - SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); - SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); + cache.remove("splitName_2"); + assertTrue(fetcher.trafficTypeExists("tt")); - // Before, it should be empty - Set usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Set expected = Sets.newHashSet(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, it starts with since -1; - changeFetcher.addSplitForSince(-1L, "test_1", "user"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("user"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // Simulate that the split arrives again as active because it has been updated - changeFetcher.addSplitForSince(0L, "test_1", "user"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("user"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // Simulate that the split is now removed. Traffic type user should no longer be present. - changeFetcher.removeSplitForSince(1L, "test_1", "user"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.clear(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); + cache.remove("splitName_1"); + assertFalse(fetcher.trafficTypeExists("tt")); } - - - @Test - public void fetch_traffic_type_names_works_with_remove() throws Exception { - SplitChangeFetcherWithTrafficTypeNames changeFetcher = new SplitChangeFetcherWithTrafficTypeNames(); - SDKReadinessGates gates = new SDKReadinessGates(); - SplitCache cache = new InMemoryCacheImp(-1); - - SegmentChangeFetcher segmentChangeFetcher = new NoChangeSegmentChangeFetcher(); - SegmentFetcher segmentFetcher = new RefreshableSegmentFetcher(segmentChangeFetcher, 1,10, gates); - RefreshableSplitFetcher fetcher = new RefreshableSplitFetcher(changeFetcher, new SplitParser(segmentFetcher), gates, cache); - - Set expected = Sets.newHashSet(); - - // execute once, it starts with since -1; - changeFetcher.addSplitForSince(-1L, "test_1", "user"); - executeOnce(fetcher); - Set usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - expected.add("user"); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 0; - changeFetcher.addSplitForSince(0L, "test_2", "user"); - changeFetcher.addSplitForSince(0L, "test_3", "account"); - executeOnce(fetcher); - expected.add("account"); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 1; - // This removes test_1, but still test_2 exists with user, so it should still return user and account - changeFetcher.removeSplitForSince(1L, "test_1", "user"); - executeOnce(fetcher); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 2; - // This removes test_2, so now there are no more splits with traffic type user. - changeFetcher.removeSplitForSince(2L, "test_2", "user"); - executeOnce(fetcher); - expected.remove("user"); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 3; - // This removes test_3, which removes account, now it should be empty - changeFetcher.removeSplitForSince(3L, "test_3", "account"); - executeOnce(fetcher); - expected.remove("account"); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - - // execute once, now with 4; - // Adding user once more - changeFetcher.addSplitForSince(4L, "test_1", "user"); - executeOnce(fetcher); - expected.add("user"); - usedTrafficTypes = fetcher.fetchKnownTrafficTypes(); - Assert.assertThat(usedTrafficTypes, Matchers.is(Matchers.equalTo(expected))); - } - - private void executeOnce(Runnable runnable) throws InterruptedException { - // execute the fetcher for a little bit. - ExecutorService executor = Executors.newSingleThreadExecutor(); - executor.submit(runnable); - executor.shutdown(); - executor.awaitTermination(10, TimeUnit.SECONDS); - } - - } From 1c45e7776103e94aa6c97ce39006c0d53fffd12b Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Fri, 11 Dec 2020 11:59:59 -0300 Subject: [PATCH 3/3] pr feedback --- client/src/main/java/io/split/client/SplitFactoryImpl.java | 2 +- .../io/split/engine/experiments/RefreshableSplitFetcher.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 15cbb09e8..dafda7bf6 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -202,7 +202,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn // Feature Changes SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(httpclient, rootTarget, uncachedFireAndForget); - final SplitCache cache = new InMemoryCacheImp(-1); + final SplitCache cache = new InMemoryCacheImp(); final RefreshableSplitFetcherProvider splitFetcherProvider = new RefreshableSplitFetcherProvider(splitChangeFetcher, splitParser, findPollingPeriod(RANDOM, config.featuresRefreshRate()), gates, cache); diff --git a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java index 1fd8d5088..982c7184a 100644 --- a/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java +++ b/client/src/main/java/io/split/engine/experiments/RefreshableSplitFetcher.java @@ -137,7 +137,7 @@ public void run() { } } - public void runWithoutExceptionHandling() throws InterruptedException { + private void runWithoutExceptionHandling() throws InterruptedException { SplitChange change = _splitChangeFetcher.fetch(_splitCache.getChangeNumber()); if (change == null) {