Skip to content

Commit df6bc39

Browse files
committed
Added inmemory storage classes
1 parent 2ff316f commit df6bc39

File tree

10 files changed

+359
-6
lines changed

10 files changed

+359
-6
lines changed

client/src/main/java/io/split/Spec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private Spec() {
66
// restrict instantiation
77
}
88

9-
public static String SPEC_VERSION = "1.3";
9+
public static String SPEC_VERSION = "1.1";
1010
public static final String SPEC_1_3 = "1.3";
1111
public static final String SPEC_1_1 = "1.1";
1212
}

client/src/main/java/io/split/engine/experiments/ParsedCondition.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ public int hashCode() {
5353
result = 31 * result + _matcher.hashCode();
5454

5555
int partitionsHashCode = 17;
56-
for (Partition p : _partitions) {
57-
partitionsHashCode = 31 * partitionsHashCode + p.treatment.hashCode();
58-
partitionsHashCode = 31 * partitionsHashCode + p.size;
56+
if (_partitions != null) {
57+
for (Partition p : _partitions) {
58+
partitionsHashCode = 31 * partitionsHashCode + p.treatment.hashCode();
59+
partitionsHashCode = 31 * partitionsHashCode + p.size;
60+
}
5961
}
60-
6162
result = 31 * result + partitionsHashCode;
6263
return result;
6364
}
@@ -75,7 +76,9 @@ public boolean equals(Object obj) {
7576
if (!result) {
7677
return result;
7778
}
78-
79+
if (_partitions == null) {
80+
return result & (_partitions == other._partitions);
81+
}
7982
if (_partitions.size() != other._partitions.size()) {
8083
return result;
8184
}
@@ -97,6 +100,9 @@ public String toString() {
97100
bldr.append(_matcher);
98101
bldr.append(" then split ");
99102
boolean first = true;
103+
if (_partitions == null) {
104+
return bldr.toString();
105+
}
100106
for (Partition partition : _partitions) {
101107
if (!first) {
102108
bldr.append(',');
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package io.split.engine.experiments;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import io.split.engine.matchers.AttributeMatcher;
5+
import io.split.engine.matchers.UserDefinedSegmentMatcher;
6+
7+
import java.util.List;
8+
import java.util.Set;
9+
import java.util.stream.Collectors;
10+
11+
public class ParsedRuleBasedSegment {
12+
13+
private final String _ruleBasedSegment;
14+
private final ImmutableList<ParsedCondition> _parsedCondition;
15+
private final String _trafficTypeName;
16+
private final long _changeNumber;
17+
private final List<String> _excludedKeys;
18+
private final List<String> _excludedSegments;
19+
20+
public static ParsedRuleBasedSegment createParsedRuleBasedSegmentForTests(
21+
String ruleBasedSegment,
22+
List<ParsedCondition> matcherAndSplits,
23+
String trafficTypeName,
24+
long changeNumber,
25+
List<String> excludedKeys,
26+
List<String> excludedSegments
27+
) {
28+
return new ParsedRuleBasedSegment(
29+
ruleBasedSegment,
30+
matcherAndSplits,
31+
trafficTypeName,
32+
changeNumber,
33+
excludedKeys,
34+
excludedSegments
35+
);
36+
}
37+
38+
public ParsedRuleBasedSegment(
39+
String ruleBasedSegment,
40+
List<ParsedCondition> matcherAndSplits,
41+
String trafficTypeName,
42+
long changeNumber,
43+
List<String> excludedKeys,
44+
List<String> excludedSegments
45+
) {
46+
_ruleBasedSegment = ruleBasedSegment;
47+
_parsedCondition = ImmutableList.copyOf(matcherAndSplits);
48+
_trafficTypeName = trafficTypeName;
49+
_changeNumber = changeNumber;
50+
_excludedKeys = excludedKeys;
51+
_excludedSegments = excludedSegments;
52+
}
53+
54+
public String ruleBasedSegment() {
55+
return _ruleBasedSegment;
56+
}
57+
58+
public List<ParsedCondition> parsedConditions() {
59+
return _parsedCondition;
60+
}
61+
62+
public String trafficTypeName() {return _trafficTypeName;}
63+
64+
public long changeNumber() {return _changeNumber;}
65+
66+
public List<String> excludedKeys() {return _excludedKeys;}
67+
public List<String> excludedSegments() {return _excludedSegments;}
68+
69+
@Override
70+
public int hashCode() {
71+
int result = 17;
72+
result = 31 * result + _ruleBasedSegment.hashCode();
73+
result = 31 * result + _parsedCondition.hashCode();
74+
result = 31 * result + (_trafficTypeName == null ? 0 : _trafficTypeName.hashCode());
75+
result = 31 * result + (int)(_changeNumber ^ (_changeNumber >>> 32));
76+
return result;
77+
}
78+
79+
@Override
80+
public boolean equals(Object obj) {
81+
if (obj == null) return false;
82+
if (this == obj) return true;
83+
if (!(obj instanceof ParsedRuleBasedSegment)) return false;
84+
85+
ParsedRuleBasedSegment other = (ParsedRuleBasedSegment) obj;
86+
87+
return _ruleBasedSegment.equals(other._ruleBasedSegment)
88+
&& _parsedCondition.equals(other._parsedCondition)
89+
&& _trafficTypeName == null ? other._trafficTypeName == null : _trafficTypeName.equals(other._trafficTypeName)
90+
&& _changeNumber == other._changeNumber;
91+
}
92+
93+
@Override
94+
public String toString() {
95+
StringBuilder bldr = new StringBuilder();
96+
bldr.append("name:");
97+
bldr.append(_ruleBasedSegment);
98+
bldr.append(", parsedConditions:");
99+
bldr.append(_parsedCondition);
100+
bldr.append(", trafficTypeName:");
101+
bldr.append(_trafficTypeName);
102+
bldr.append(", changeNumber:");
103+
bldr.append(_changeNumber);
104+
return bldr.toString();
105+
106+
}
107+
108+
public Set<String> getSegmentsNames() {
109+
return parsedConditions().stream()
110+
.flatMap(parsedCondition -> parsedCondition.matcher().attributeMatchers().stream())
111+
.filter(ParsedRuleBasedSegment::isSegmentMatcher)
112+
.map(ParsedRuleBasedSegment::asSegmentMatcherForEach)
113+
.map(UserDefinedSegmentMatcher::getSegmentName)
114+
.collect(Collectors.toSet());
115+
}
116+
117+
private static boolean isSegmentMatcher(AttributeMatcher attributeMatcher) {
118+
return ((AttributeMatcher.NegatableMatcher) attributeMatcher.matcher()).delegate() instanceof UserDefinedSegmentMatcher;
119+
}
120+
121+
private static UserDefinedSegmentMatcher asSegmentMatcherForEach(AttributeMatcher attributeMatcher) {
122+
return (UserDefinedSegmentMatcher) ((AttributeMatcher.NegatableMatcher) attributeMatcher.matcher()).delegate();
123+
}
124+
125+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package io.split.storages;
2+
3+
public interface RuleBasedSegmentCache extends RuleBasedSegmentCacheConsumer, RuleBasedSegmentCacheProducer {
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.split.storages;
2+
3+
import java.util.Set;
4+
5+
public interface RuleBasedSegmentCacheCommons {
6+
long getChangeNumber();
7+
Set<String> getSegments();
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.split.storages;
2+
3+
import io.split.engine.experiments.ParsedRuleBasedSegment;
4+
5+
import java.util.Collection;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
public interface RuleBasedSegmentCacheConsumer extends RuleBasedSegmentCacheCommons {
10+
ParsedRuleBasedSegment get(String name);
11+
Collection<ParsedRuleBasedSegment> getAll();
12+
List<String> ruleBasedSegmentNames();
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.split.storages;
2+
3+
import io.split.engine.experiments.ParsedRuleBasedSegment;
4+
5+
import java.util.List;
6+
7+
public interface RuleBasedSegmentCacheProducer extends RuleBasedSegmentCacheCommons{
8+
boolean remove(String name);
9+
void setChangeNumber(long changeNumber);
10+
void update(List<ParsedRuleBasedSegment> toAdd, List<String> toRemove, long changeNumber);
11+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package io.split.storages.memory;
2+
3+
import com.google.common.collect.Maps;
4+
import io.split.engine.experiments.ParsedRuleBasedSegment;
5+
import io.split.storages.RuleBasedSegmentCache;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import java.util.Collection;
11+
import java.util.List;
12+
import java.util.Set;
13+
import java.util.ArrayList;
14+
import java.util.concurrent.ConcurrentMap;
15+
import java.util.concurrent.atomic.AtomicLong;
16+
import java.util.stream.Collectors;
17+
18+
public class RuleBasedSegmentCacheInMemoryImp implements RuleBasedSegmentCache {
19+
20+
private static final Logger _log = LoggerFactory.getLogger(RuleBasedSegmentCacheInMemoryImp.class);
21+
22+
private final ConcurrentMap<String, ParsedRuleBasedSegment> _concurrentMap;
23+
24+
private AtomicLong _changeNumber;
25+
26+
public RuleBasedSegmentCacheInMemoryImp() {
27+
this(-1);
28+
}
29+
30+
public RuleBasedSegmentCacheInMemoryImp(long startingChangeNumber) {
31+
_concurrentMap = Maps.newConcurrentMap();
32+
_changeNumber = new AtomicLong(startingChangeNumber);
33+
}
34+
35+
@Override
36+
public boolean remove(String name) {
37+
ParsedRuleBasedSegment removed = _concurrentMap.remove(name);
38+
return removed != null;
39+
}
40+
41+
@Override
42+
public ParsedRuleBasedSegment get(String name) {
43+
return _concurrentMap.get(name);
44+
}
45+
46+
@Override
47+
public Collection<ParsedRuleBasedSegment> getAll() {
48+
return _concurrentMap.values();
49+
}
50+
51+
@Override
52+
public long getChangeNumber() {
53+
return _changeNumber.get();
54+
}
55+
56+
@Override
57+
public void setChangeNumber(long changeNumber) {
58+
if (changeNumber < _changeNumber.get()) {
59+
_log.error("ChangeNumber for feature flags cache is less than previous");
60+
}
61+
62+
_changeNumber.set(changeNumber);
63+
}
64+
65+
@Override
66+
public List<String> ruleBasedSegmentNames() {
67+
List<String> ruleBasedSegmentNamesList = new ArrayList<>();
68+
for (String key: _concurrentMap.keySet()) {
69+
ruleBasedSegmentNamesList.add(_concurrentMap.get(key).ruleBasedSegment());
70+
}
71+
return ruleBasedSegmentNamesList;
72+
}
73+
74+
public void clear() {
75+
_concurrentMap.clear();
76+
}
77+
78+
public void putMany(List<ParsedRuleBasedSegment> ruleBasedSegments) {
79+
for (ParsedRuleBasedSegment ruleBasedSegment : ruleBasedSegments) {
80+
_concurrentMap.put(ruleBasedSegment.ruleBasedSegment(), ruleBasedSegment);
81+
}
82+
}
83+
84+
@Override
85+
public void update(List<ParsedRuleBasedSegment> toAdd, List<String> toRemove, long changeNumber) {
86+
if(toAdd != null) {
87+
putMany(toAdd);
88+
}
89+
if(toRemove != null) {
90+
for(String ruleBasedSegment : toRemove) {
91+
remove(ruleBasedSegment);
92+
}
93+
}
94+
setChangeNumber(changeNumber);
95+
}
96+
97+
public Set<String> getSegments() {
98+
return _concurrentMap.values().stream()
99+
.flatMap(parsedRuleBasedSegment -> parsedRuleBasedSegment.getSegmentsNames().stream()).collect(Collectors.toSet());
100+
}
101+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.split.engine.experiments;
2+
3+
import com.google.common.collect.Lists;
4+
import com.google.common.collect.Sets;
5+
import io.split.client.dtos.ConditionType;
6+
import io.split.client.dtos.MatcherCombiner;
7+
import io.split.engine.matchers.AttributeMatcher;
8+
import io.split.engine.matchers.CombiningMatcher;
9+
import io.split.engine.matchers.UserDefinedSegmentMatcher;
10+
11+
import org.junit.Assert;
12+
import org.junit.Test;
13+
14+
public class ParsedRuleBasedSegmentTest {
15+
16+
@Test
17+
public void works() {
18+
AttributeMatcher segmentMatcher = AttributeMatcher.vanilla(new UserDefinedSegmentMatcher("employees"));
19+
CombiningMatcher segmentCombiningMatcher = new CombiningMatcher(MatcherCombiner.AND, Lists.newArrayList(segmentMatcher));
20+
ParsedRuleBasedSegment parsedRuleBasedSegment = new ParsedRuleBasedSegment("another_rule_based_segment",
21+
Lists.newArrayList(new ParsedCondition(ConditionType.WHITELIST, segmentCombiningMatcher, null, "label")),"user",
22+
123, Lists.newArrayList("mauro@test.io","gaston@test.io"), Lists.newArrayList("segment1", "segment2"));
23+
24+
Assert.assertEquals(Sets.newHashSet("employees"), parsedRuleBasedSegment.getSegmentsNames());
25+
Assert.assertEquals("another_rule_based_segment", parsedRuleBasedSegment.ruleBasedSegment());
26+
Assert.assertEquals(Lists.newArrayList(new ParsedCondition(ConditionType.WHITELIST, segmentCombiningMatcher, null, "label")),
27+
parsedRuleBasedSegment.parsedConditions());
28+
Assert.assertEquals(123, parsedRuleBasedSegment.changeNumber());
29+
}
30+
}

0 commit comments

Comments
 (0)