Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/main/java/io/split/Spec.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ private Spec() {
}

// TODO: Change the schema to 1.3 when updating splitclient
public static String SPEC_VERSION = "1.1";
public static final String SPEC_1_3 = "1.3";
public static final String SPEC_1_1 = "1.1";
public static String SPEC_VERSION = SPEC_1_3;
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import io.split.engine.matchers.CombiningMatcher;
import io.split.engine.matchers.strings.WhitelistMatcher;
import io.split.grammar.Treatments;
import io.split.storages.SplitCacheConsumer;
import io.split.storages.SplitCacheProducer;

import java.util.ArrayList;
Expand Down
31 changes: 18 additions & 13 deletions client/src/main/java/io/split/client/HttpSplitChangeFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher {
private static final Logger _log = LoggerFactory.getLogger(HttpSplitChangeFetcher.class);

private static final String SINCE = "since";
private static final String RB_SINCE = "rbSince";
private static final String TILL = "till";
private static final String SETS = "sets";
private static final String SPEC = "s";
Expand All @@ -56,27 +57,18 @@ long makeRandomTill() {
}

@Override
public SplitChange fetch(long since, FetchOptions options) {

public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
long start = System.currentTimeMillis();

try {
URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION);
uriBuilder.addParameter(SINCE, "" + since);
if (!options.flagSetsFilter().isEmpty()) {
uriBuilder.addParameter(SETS, "" + options.flagSetsFilter());
}
if (options.hasCustomCN()) {
uriBuilder.addParameter(TILL, "" + options.targetCN());
}
URI uri = uriBuilder.build();
URI uri = buildURL(options, since, sinceRBS);
SplitHttpResponse response = _client.get(uri, options, null);

if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
if (response.statusCode() == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
_log.error("The amount of flag sets provided are big causing uri length error.");
throw new UriTooLongException(String.format("Status code: %s. Message: %s", response.statusCode(), response.statusMessage()));
}

_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode());
throw new IllegalStateException(
String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode())
Expand All @@ -86,8 +78,21 @@ public SplitChange fetch(long since, FetchOptions options) {
} catch (Exception e) {
throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e);
} finally {
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis()-start);
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start);
}
}

private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION);
uriBuilder.addParameter(SINCE, "" + since);
uriBuilder.addParameter(RB_SINCE, "" + sinceRBS);
if (!options.flagSetsFilter().isEmpty()) {
uriBuilder.addParameter(SETS, "" + options.flagSetsFilter());
}
if (options.hasCustomCN()) {
uriBuilder.addParameter(TILL, "" + options.targetCN());
}
return uriBuilder.build();
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.split.client;

import com.google.gson.stream.JsonReader;
import io.split.client.dtos.ChangeDto;
import io.split.client.dtos.SplitChange;
import io.split.client.utils.InputStreamProvider;
import io.split.client.utils.Json;
import io.split.client.utils.LocalhostSanitizer;
import io.split.engine.common.FetchOptions;
import io.split.engine.experiments.SplitChangeFetcher;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -15,6 +17,7 @@
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;

public class JsonLocalhostSplitChangeFetcher implements SplitChangeFetcher {
Expand All @@ -29,10 +32,16 @@ public JsonLocalhostSplitChangeFetcher(InputStreamProvider inputStreamProvider)
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
try {
JsonReader jsonReader = new JsonReader(new BufferedReader(new InputStreamReader(_inputStreamProvider.get(), StandardCharsets.UTF_8)));
SplitChange splitChange = Json.fromJson(jsonReader, SplitChange.class);
splitChange.ruleBasedSegments = new ChangeDto<>();

// TODO: Remove when updating the class to support RBS
splitChange.ruleBasedSegments.d = new ArrayList<>();
splitChange.ruleBasedSegments.t = -1;
splitChange.ruleBasedSegments.s = -1;
return processSplitChange(splitChange, since);
} catch (Exception e) {
throw new IllegalStateException("Problem fetching splitChanges: " + e.getMessage(), e);
Expand All @@ -42,22 +51,22 @@ public SplitChange fetch(long since, FetchOptions options) {
private SplitChange processSplitChange(SplitChange splitChange, long changeNumber) throws NoSuchAlgorithmException {
SplitChange splitChangeToProcess = LocalhostSanitizer.sanitization(splitChange);
// if the till is less than storage CN and different from the default till ignore the change
if (splitChangeToProcess.till < changeNumber && splitChangeToProcess.till != -1) {
if (splitChangeToProcess.featureFlags.t < changeNumber && splitChangeToProcess.featureFlags.t != -1) {
_log.warn("The till is lower than the change number or different to -1");
return null;
}
String splitJson = splitChange.splits.toString();
String splitJson = splitChange.featureFlags.d.toString();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(splitJson.getBytes());
// calculate the json sha
byte [] currHash = digest.digest();
//if sha exist and is equal to before sha, or if till is equal to default till returns the same segmentChange with till equals to storage CN
if (Arrays.equals(lastHash, currHash) || splitChangeToProcess.till == -1) {
splitChangeToProcess.till = changeNumber;
if (Arrays.equals(lastHash, currHash) || splitChangeToProcess.featureFlags.t == -1) {
splitChangeToProcess.featureFlags.t = changeNumber;
}
lastHash = currHash;
splitChangeToProcess.since = changeNumber;
splitChangeToProcess.featureFlags.s = changeNumber;
return splitChangeToProcess;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import io.split.client.dtos.Status;
import io.split.client.dtos.ChangeDto;
import io.split.client.utils.LocalhostConstants;
import io.split.client.utils.LocalhostSanitizer;
import io.split.engine.common.FetchOptions;
Expand Down Expand Up @@ -34,11 +35,12 @@ public LegacyLocalhostSplitChangeFetcher(String directory) {
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {

try (BufferedReader reader = new BufferedReader(new FileReader(_splitFile))) {
SplitChange splitChange = new SplitChange();
splitChange.splits = new ArrayList<>();
splitChange.featureFlags = new ChangeDto<>();
splitChange.featureFlags.d = new ArrayList<>();
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
String lineTrim = line.trim();
if (lineTrim.isEmpty() || lineTrim.startsWith("#")) {
Expand All @@ -51,15 +53,16 @@ public SplitChange fetch(long since, FetchOptions options) {
_log.info("Ignoring line since it does not have 2 or 3 columns: " + lineTrim);
continue;
}
Optional<Split> splitOptional = splitChange.splits.stream().filter(split -> split.name.equals(featureTreatment[0])).findFirst();
Optional<Split> splitOptional = splitChange.featureFlags.d.stream().
filter(split -> split.name.equals(featureTreatment[0])).findFirst();
Split split = splitOptional.orElse(null);
if(split == null) {
split = new Split();
split.name = featureTreatment[0];
split.configurations = new HashMap<>();
split.conditions = new ArrayList<>();
} else {
splitChange.splits.remove(split);
splitChange.featureFlags.d.remove(split);
}
split.status = Status.ACTIVE;
split.defaultTreatment = featureTreatment[1];
Expand All @@ -78,10 +81,14 @@ public SplitChange fetch(long since, FetchOptions options) {
} else {
split.conditions.add(condition);
}
splitChange.splits.add(split);
splitChange.featureFlags.d.add(split);
}
splitChange.till = since;
splitChange.since = since;
splitChange.featureFlags.t = since;
splitChange.featureFlags.s = since;
splitChange.ruleBasedSegments = new ChangeDto<>();
splitChange.ruleBasedSegments.s = -1;
splitChange.ruleBasedSegments.t = -1;
splitChange.ruleBasedSegments.d = new ArrayList<>();
return splitChange;
} catch (FileNotFoundException f) {
_log.warn("There was no file named " + _splitFile.getPath() + " found. " +
Expand Down
3 changes: 0 additions & 3 deletions client/src/main/java/io/split/client/SplitClientImpl.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package io.split.client;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import io.split.client.api.Key;
import io.split.client.api.SplitResult;
import io.split.client.dtos.DecoratedImpression;
Expand All @@ -26,7 +24,6 @@
import io.split.telemetry.domain.enums.MethodEnum;
import io.split.telemetry.storage.TelemetryConfigProducer;
import io.split.telemetry.storage.TelemetryEvaluationProducer;
import io.split.client.utils.Json;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.split.inputValidation.ApiKeyValidator;
import io.split.grammar.Treatments;
import io.split.service.SplitHttpClient;
import io.split.storages.enums.StorageMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
14 changes: 10 additions & 4 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import io.split.engine.experiments.SplitFetcherImp;
import io.split.engine.experiments.SplitParser;
import io.split.engine.experiments.SplitSynchronizationTask;
import io.split.engine.experiments.RuleBasedSegmentParser;
import io.split.engine.segments.SegmentChangeFetcher;
import io.split.engine.segments.SegmentSynchronizationTaskImp;
import io.split.integrations.IntegrationsConfig;
Expand All @@ -68,6 +69,7 @@
import io.split.storages.SplitCacheProducer;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.RuleBasedSegmentCache;
import io.split.storages.RuleBasedSegmentCacheProducer;
import io.split.storages.enums.OperationMode;
import io.split.storages.memory.InMemoryCacheImp;
import io.split.storages.memory.SegmentCacheInMemoryImpl;
Expand Down Expand Up @@ -220,8 +222,10 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn


SplitParser splitParser = new SplitParser();
RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser();
// SplitFetcher
_splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter);
_splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter,
ruleBasedSegmentParser, ruleBasedSegmentCache);

// SplitSynchronizationTask
_splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher,
Expand Down Expand Up @@ -422,9 +426,10 @@ protected SplitFactoryImpl(SplitClientConfig config) {
// SplitFetcher
SplitChangeFetcher splitChangeFetcher = createSplitChangeFetcher(config);
SplitParser splitParser = new SplitParser();
RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser();

_splitFetcher = new SplitFetcherImp(splitChangeFetcher, splitParser, splitCache, _telemetryStorageProducer,
flagSetsFilter);
flagSetsFilter, ruleBasedSegmentParser, _ruleBasedSegmentCache);

// SplitSynchronizationTask
_splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher, splitCache,
Expand Down Expand Up @@ -617,11 +622,12 @@ private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config,
}

private SplitFetcher buildSplitFetcher(SplitCacheProducer splitCacheProducer, SplitParser splitParser,
FlagSetsFilter flagSetsFilter) throws URISyntaxException {
FlagSetsFilter flagSetsFilter, RuleBasedSegmentParser ruleBasedSegmentParser,
RuleBasedSegmentCacheProducer ruleBasedSegmentCache) throws URISyntaxException {
SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(_splitHttpClient, _rootTarget,
_telemetryStorageProducer);
return new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, _telemetryStorageProducer,
flagSetsFilter);
flagSetsFilter, ruleBasedSegmentParser, ruleBasedSegmentCache);
}

private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import io.split.client.dtos.Status;
import io.split.client.dtos.ChangeDto;
import io.split.client.utils.InputStreamProvider;
import io.split.client.utils.LocalhostConstants;
import io.split.engine.common.FetchOptions;
Expand Down Expand Up @@ -32,25 +33,27 @@ public YamlLocalhostSplitChangeFetcher(InputStreamProvider inputStreamProvider)
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
try {
Yaml yaml = new Yaml();
List<Map<String, Map<String, Object>>> yamlSplits = yaml.load(_inputStreamProvider.get());
SplitChange splitChange = new SplitChange();
splitChange.splits = new ArrayList<>();
splitChange.featureFlags = new ChangeDto<>();
splitChange.featureFlags.d = new ArrayList<>();
for(Map<String, Map<String, Object>> aSplit : yamlSplits) {
// The outter map is a map with one key, the split name
Map.Entry<String, Map<String, Object>> splitAndValues = aSplit.entrySet().iterator().next();

Optional<Split> splitOptional = splitChange.splits.stream().filter(split -> split.name.equals(splitAndValues.getKey())).findFirst();
Optional<Split> splitOptional = splitChange.featureFlags.d.stream().
filter(split -> split.name.equals(splitAndValues.getKey())).findFirst();
Split split = splitOptional.orElse(null);
if(split == null) {
split = new Split();
split.name = splitAndValues.getKey();
split.configurations = new HashMap<>();
split.conditions = new ArrayList<>();
} else {
splitChange.splits.remove(split);
splitChange.featureFlags.d.remove(split);
}
String treatment = (String) splitAndValues.getValue().get("treatment");
String configurations = splitAndValues.getValue().get("config") != null ? (String) splitAndValues.getValue().get("config") : null;
Expand All @@ -68,11 +71,14 @@ public SplitChange fetch(long since, FetchOptions options) {
split.trafficTypeName = LocalhostConstants.USER;
split.trafficAllocation = LocalhostConstants.SIZE_100;
split.trafficAllocationSeed = LocalhostConstants.SIZE_1;

splitChange.splits.add(split);
splitChange.featureFlags.d.add(split);
}
splitChange.till = since;
splitChange.since = since;
splitChange.featureFlags.t = since;
splitChange.featureFlags.s = since;
splitChange.ruleBasedSegments = new ChangeDto<>();
splitChange.ruleBasedSegments.s = -1;
splitChange.ruleBasedSegments.t = -1;
splitChange.ruleBasedSegments.d = new ArrayList<>();
return splitChange;
} catch (Exception e) {
throw new IllegalStateException("Problem fetching splitChanges using a yaml file: " + e.getMessage(), e);
Expand Down
9 changes: 9 additions & 0 deletions client/src/main/java/io/split/client/dtos/ChangeDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.split.client.dtos;

import java.util.List;

public class ChangeDto<T> {
public long s;
public long t;
public List<T> d;
}
9 changes: 5 additions & 4 deletions client/src/main/java/io/split/client/dtos/SplitChange.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.split.client.dtos;

import java.util.List;
import com.google.gson.annotations.SerializedName;

public class SplitChange {
public List<Split> splits;
public long since;
public long till;
@SerializedName("ff")
public ChangeDto<Split> featureFlags;
@SerializedName("rbs")
public ChangeDto<RuleBasedSegment> ruleBasedSegments;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ public static<T> void process(List<T> data, URI endpoint, CloseableHttpClient cl

}
}

Loading