Skip to content

Commit 26109f3

Browse files
Merge pull request #95 from Netflix/feature/base85
Added support for Ascii85 encoding
2 parents 0e8b973 + 1c0f424 commit 26109f3

File tree

8 files changed

+109
-68
lines changed

8 files changed

+109
-68
lines changed

evcache-core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ dependencies {
3838
compile group:"org.apache.httpcomponents", name:"httpclient", version:"latest.release"
3939
compile group:"joda-time", name:"joda-time", version:"latest.release"
4040
compile group:"javax.annotation", name:"javax.annotation-api", version:"latest.release"
41+
compile group:"com.github.fzakaria", name:"ascii85", version:"latest.release"
4142

4243
testCompile group:"org.testng", name:"testng", version:"latest.release"
4344
testCompile group:"com.beust", name:"jcommander", version:"1.72"

evcache-core/src/main/java/com/netflix/evcache/EVCacheImpl.java

Lines changed: 25 additions & 22 deletions
Large diffs are not rendered by default.

evcache-core/src/main/java/com/netflix/evcache/EVCacheInternalImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ private EVCacheLatch addOrSet(boolean replaceItem, String key, CachedData value,
165165
// identify that evcache client whose primary node is the destination ip for the key being processed
166166
evCacheClients = evCacheClients.stream().filter(client ->
167167
destinationIps.contains(((InetSocketAddress) client.getNodeLocator()
168-
.getPrimary(getEVCacheKey(key).getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength()))
168+
.getPrimary(getEVCacheKey(key).getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength(), client.getBaseEncoder()))
169169
.getSocketAddress()).getAddress().getHostAddress())
170170
).collect(Collectors.toList());
171171
}

evcache-core/src/main/java/com/netflix/evcache/EVCacheKey.java

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ public class EVCacheKey {
1919
// like max.hash.length. So changing max.hash.length alone would not necessarily trigger hash recalculation, but
2020
// one would have to change the hashing algorithm in order to having hashing properties taken into account.
2121
// This is to make such a hashing property change very obvious and not subtle.
22-
private final Map<HashingAlgorithm, String> hashedKeysByAlgorithm;
23-
private final Map<HashingAlgorithm, String> hashedKeysByAlgorithmForDuet;
22+
private final Map<String, String> hashedKeysByAlgorithm;
23+
private final Map<String, String> hashedKeysByAlgorithmForDuet;
24+
private final String encoder;
2425

2526
public EVCacheKey(String appName, String key, String canonicalKey, HashingAlgorithm hashingAlgorithmAtAppLevel, Property<Boolean> shouldEncodeHashKeyAtAppLevel, Property<Integer> maxDigestBytesAtAppLevel, Property<Integer> maxHashLengthAtAppLevel) {
27+
this(appName, key, canonicalKey, hashingAlgorithmAtAppLevel, shouldEncodeHashKeyAtAppLevel, maxDigestBytesAtAppLevel, maxHashLengthAtAppLevel, null);
28+
}
29+
30+
public EVCacheKey(String appName, String key, String canonicalKey, HashingAlgorithm hashingAlgorithmAtAppLevel, Property<Boolean> shouldEncodeHashKeyAtAppLevel, Property<Integer> maxDigestBytesAtAppLevel, Property<Integer> maxHashLengthAtAppLevel, String encoder) {
2631
super();
2732
this.appName = appName;
2833
this.key = key;
@@ -31,6 +36,7 @@ public EVCacheKey(String appName, String key, String canonicalKey, HashingAlgori
3136
this.shouldEncodeHashKeyAtAppLevel = shouldEncodeHashKeyAtAppLevel;
3237
this.maxDigestBytesAtAppLevel = maxDigestBytesAtAppLevel;
3338
this.maxHashLengthAtAppLevel = maxHashLengthAtAppLevel;
39+
this.encoder = encoder;
3440
hashedKeysByAlgorithm = new HashMap<>();
3541
hashedKeysByAlgorithmForDuet = new HashMap<>();
3642
}
@@ -59,11 +65,11 @@ private String getCanonicalKeyForDuet() {
5965

6066
@Deprecated
6167
public String getHashKey() {
62-
return getHashKey(hashingAlgorithmAtAppLevel, null == shouldEncodeHashKeyAtAppLevel ? null : shouldEncodeHashKeyAtAppLevel.get(), null == maxDigestBytesAtAppLevel ? null : maxDigestBytesAtAppLevel.get(), null == maxHashLengthAtAppLevel ? null : maxHashLengthAtAppLevel.get());
68+
return getHashKey(hashingAlgorithmAtAppLevel, null == shouldEncodeHashKeyAtAppLevel ? null : shouldEncodeHashKeyAtAppLevel.get(), null == maxDigestBytesAtAppLevel ? null : maxDigestBytesAtAppLevel.get(), null == maxHashLengthAtAppLevel ? null : maxHashLengthAtAppLevel.get(), encoder);
6369
}
6470

6571
// overlays app level hashing and client level hashing
66-
public String getHashKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength) {
72+
public String getHashKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String baseEnoder) {
6773
if (hashingAlgorithm == HashingAlgorithm.NO_HASHING) {
6874
return null;
6975
}
@@ -83,36 +89,52 @@ public String getHashKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Bool
8389
if (null == maxHashLength) {
8490
maxHashLength = this.maxHashLengthAtAppLevel.get();
8591
}
92+
93+
if(null == baseEnoder) {
94+
baseEnoder = encoder;
95+
}
8696

87-
return isDuet ? getHashKeyForDuet(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength) : getHashKey(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength);
97+
return isDuet ? getHashKeyForDuet(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder) : getHashKey(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder);
8898
}
8999

90100
// overlays app level hashing algorithm and client level hashing algorithm
91-
public String getDerivedKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength) {
101+
public String getDerivedKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String baseEnoder) {
92102
// this overlay of hashingAlgorithm helps determine if there at all needs to be hashing performed, otherwise, will return canonical key
93103
if (null == hashingAlgorithm) {
94104
hashingAlgorithm = hashingAlgorithmAtAppLevel;
95105
}
96106

97-
return null == hashingAlgorithm || hashingAlgorithm == HashingAlgorithm.NO_HASHING ? getCanonicalKey(isDuet) : getHashKey(isDuet, hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength);
107+
return null == hashingAlgorithm || hashingAlgorithm == HashingAlgorithm.NO_HASHING ? getCanonicalKey(isDuet) : getHashKey(isDuet, hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder);
98108
}
99109

100-
private String getHashKey(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength) {
110+
private String getHashKey(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String encoder) {
101111
if (null == hashingAlgorithm) {
102112
return null;
103113
}
104114

115+
final String key = hashingAlgorithm.toString()+ maxDigestBytes != null ? maxDigestBytes.toString() : "-" + maxHashLength != null ? maxHashLength.toString() : "-" + encoder != null ? encoder : "-";
116+
String val = hashedKeysByAlgorithm.get(key);
117+
if(val == null) {
118+
val = KeyHasher.getHashedKeyEncoded(getCanonicalKeyForDuet(), hashingAlgorithm, maxDigestBytes, maxHashLength, encoder);
119+
hashedKeysByAlgorithm.put(key , val);
120+
}
105121
// TODO: Once the issue around passing hashedKey in bytes[] is figured, we will start using (nullable) shouldEncodeHashKey, and call KeyHasher.getHashedKeyInBytes() accordingly
106-
return hashedKeysByAlgorithm.computeIfAbsent(hashingAlgorithm, ha -> KeyHasher.getHashedKeyEncoded(canonicalKey, ha, maxDigestBytes, maxHashLength));
122+
return val;
107123
}
108124

109-
private String getHashKeyForDuet(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength) {
125+
private String getHashKeyForDuet(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String encoder) {
110126
if (null == hashingAlgorithm) {
111127
return null;
112128
}
113129

130+
final String key = hashingAlgorithm.toString()+ maxDigestBytes != null ? maxDigestBytes.toString() : "-" + maxHashLength != null ? maxHashLength.toString() : "-" + encoder != null ? encoder : "-";
131+
String val = hashedKeysByAlgorithmForDuet.get(key);
132+
if(val == null) {
133+
val = KeyHasher.getHashedKeyEncoded(getCanonicalKeyForDuet(), hashingAlgorithm, maxDigestBytes, maxHashLength, encoder);
134+
hashedKeysByAlgorithmForDuet.put(key , val);
135+
}
114136
// TODO: Once the issue around passing hashedKey in bytes[] is figured, we will start using (nullable) shouldEncodeHashKey, and call KeyHasher.getHashedKeyInBytes() accordingly
115-
return hashedKeysByAlgorithmForDuet.computeIfAbsent(hashingAlgorithm, ha -> KeyHasher.getHashedKeyEncoded(getCanonicalKeyForDuet(), ha, maxDigestBytes, maxHashLength));
137+
return val;
116138
}
117139

118140
@Override

evcache-core/src/main/java/com/netflix/evcache/event/EVCacheEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public Collection<String> getCanonicalKeys() {
170170
public Collection<MemcachedNode> getMemcachedNode(EVCacheKey evckey) {
171171
final Collection<MemcachedNode> nodeList = new ArrayList<MemcachedNode>(clients.size());
172172
for(EVCacheClient client : clients) {
173-
String key = evckey.getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength());
173+
String key = evckey.getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength(), client.getBaseEncoder());
174174
nodeList.add(client.getNodeLocator().getPrimary(key));
175175
}
176176
return nodeList;

evcache-core/src/main/java/com/netflix/evcache/pool/EVCacheClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ public class EVCacheClient {
9292
private final Property<Integer> maxDigestBytes;
9393
private final Property<Integer> maxHashLength;
9494
private final Property<Integer> chunkSize, writeBlock;
95+
private final Property<String> encoderBase;
96+
9597
private final ChunkTranscoder chunkingTranscoder;
9698
private final SerializingTranscoder decodingTranscoder;
9799
private static final int SPECIAL_BYTEARRAY = (8 << 8);
@@ -153,6 +155,7 @@ public class EVCacheClient {
153155
this.shouldEncodeHashKey = EVCacheConfig.getInstance().getPropertyRepository().get(this.serverGroup.getName() + ".hash.encode", Boolean.class).orElse(null);
154156
this.maxDigestBytes = EVCacheConfig.getInstance().getPropertyRepository().get(this.serverGroup.getName() + ".max.digest.bytes", Integer.class).orElse(null);
155157
this.maxHashLength = EVCacheConfig.getInstance().getPropertyRepository().get(this.serverGroup.getName() + ".max.hash.length", Integer.class).orElse(null);
158+
this.encoderBase = EVCacheConfig.getInstance().getPropertyRepository().get(this.serverGroup.getName() + ".hash.encoder", String.class).orElse("base64");
156159
ping();
157160
}
158161

@@ -176,6 +179,10 @@ public Boolean shouldEncodeHashKey() {
176179
return this.shouldEncodeHashKey.get();
177180
}
178181

182+
public String getBaseEncoder() {
183+
return this.encoderBase.get();
184+
}
185+
179186
public Integer getMaxDigestBytes() {
180187
return this.maxDigestBytes.get();
181188
}

evcache-core/src/main/java/com/netflix/evcache/pool/EVCacheClientUtil.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public EVCacheLatch add(EVCacheKey evcKey, final CachedData cd, Transcoder evcac
3838
Boolean firstStatus = null;
3939
for (EVCacheClient client : clients) {
4040
CachedData cd1;
41-
if (evcKey.getHashKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength()) != null) {
41+
if (evcKey.getHashKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength(), client.getBaseEncoder()) != null) {
4242
if(cdHashed == null) {
4343
final EVCacheValue val = new EVCacheValue(evcKey.getCanonicalKey(client.isDuetClient()), cd.getData(), cd.getFlags(), timeToLive, System.currentTimeMillis());
4444
cdHashed = evcacheValueTranscoder.encode(val);
@@ -47,7 +47,7 @@ public EVCacheLatch add(EVCacheKey evcKey, final CachedData cd, Transcoder evcac
4747
} else {
4848
cd1 = cd;
4949
}
50-
String key = evcKey.getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength());
50+
String key = evcKey.getDerivedKey(client.isDuetClient(), client.getHashingAlgorithm(), client.shouldEncodeHashKey(), client.getMaxDigestBytes(), client.getMaxHashLength(), client.getBaseEncoder());
5151
final Future<Boolean> f = client.add(key, timeToLive, cd1, latch);
5252
if (log.isDebugEnabled()) log.debug("ADD : Op Submitted : APP " + _appName + ", key " + key + "; future : " + f + "; client : " + client);
5353
if(fixMissing) {
@@ -71,12 +71,12 @@ public EVCacheLatch add(EVCacheKey evcKey, final CachedData cd, Transcoder evcac
7171
private EVCacheLatch fixup(EVCacheClient sourceClient, EVCacheClient[] destClients, EVCacheKey evcKey, int timeToLive, Policy policy) {
7272
final EVCacheLatchImpl latch = new EVCacheLatchImpl(policy, destClients.length, _appName);
7373
try {
74-
final CachedData readData = sourceClient.get(evcKey.getDerivedKey(sourceClient.isDuetClient(), sourceClient.getHashingAlgorithm(), sourceClient.shouldEncodeHashKey(), sourceClient.getMaxDigestBytes(), sourceClient.getMaxHashLength()), ct, false, false);
74+
final CachedData readData = sourceClient.get(evcKey.getDerivedKey(sourceClient.isDuetClient(), sourceClient.getHashingAlgorithm(), sourceClient.shouldEncodeHashKey(), sourceClient.getMaxDigestBytes(), sourceClient.getMaxHashLength(), sourceClient.getBaseEncoder()), ct, false, false);
7575

7676
if(readData != null) {
77-
sourceClient.touch(evcKey.getDerivedKey(sourceClient.isDuetClient(), sourceClient.getHashingAlgorithm(), sourceClient.shouldEncodeHashKey(), sourceClient.getMaxDigestBytes(), sourceClient.getMaxHashLength()), timeToLive);
77+
sourceClient.touch(evcKey.getDerivedKey(sourceClient.isDuetClient(), sourceClient.getHashingAlgorithm(), sourceClient.shouldEncodeHashKey(), sourceClient.getMaxDigestBytes(), sourceClient.getMaxHashLength(), sourceClient.getBaseEncoder()), timeToLive);
7878
for(EVCacheClient destClient : destClients) {
79-
destClient.set(evcKey.getDerivedKey(destClient.isDuetClient(), destClient.getHashingAlgorithm(), destClient.shouldEncodeHashKey(), destClient.getMaxDigestBytes(), destClient.getMaxHashLength()), readData, timeToLive, latch);
79+
destClient.set(evcKey.getDerivedKey(destClient.isDuetClient(), destClient.getHashingAlgorithm(), destClient.shouldEncodeHashKey(), destClient.getMaxDigestBytes(), destClient.getMaxHashLength(), destClient.getBaseEncoder()), readData, timeToLive, latch);
8080
}
8181
}
8282
latch.await(_operationTimeout, TimeUnit.MILLISECONDS);

0 commit comments

Comments
 (0)