Skip to content

Commit

Permalink
ignore "_#RL#" and "_#TS#" prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
areyouok committed Jan 5, 2023
1 parent 96ff47e commit 00bcbb3
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
/**
* Created on 2016/12/12.
*
* A custom key convertor implements Function<Object, Object> is enough.
* If a key convertor implements this interface, it can process byte[] and String, see AbstractExternalCache.
*
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
*/
public interface KeyConvertor extends Function<Object, Object> {
Expand Down
13 changes: 10 additions & 3 deletions jetcache-core/src/main/java/com/alicp/jetcache/RefreshCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
Expand All @@ -22,6 +26,9 @@ public class RefreshCache<K, V> extends LoadingCache<K, V> {

private static final Logger logger = LoggerFactory.getLogger(RefreshCache.class);

public static final byte[] LOCK_KEY_SUFFIX = "_#RL#".getBytes();
public static final byte[] TIMESTAMP_KEY_SUFFIX = "_#TS#".getBytes();

private ConcurrentHashMap<Object, RefreshTask> taskMap = new ConcurrentHashMap<>();

private boolean multiLevelCache;
Expand Down Expand Up @@ -174,10 +181,10 @@ private void load() throws Throwable {
private void externalLoad(final Cache concreteCache, final long currentTime)
throws Throwable {
byte[] newKey = ((AbstractExternalCache) concreteCache).buildKey(key);
byte[] lockKey = combine(newKey, "_#RL#".getBytes());
byte[] lockKey = combine(newKey, LOCK_KEY_SUFFIX);
long loadTimeOut = RefreshCache.this.config.getRefreshPolicy().getRefreshLockTimeoutMillis();
long refreshMillis = config.getRefreshPolicy().getRefreshMillis();
byte[] timestampKey = combine(newKey, "_#TS#".getBytes());
byte[] timestampKey = combine(newKey, TIMESTAMP_KEY_SUFFIX);

// AbstractExternalCache buildKey method will not convert byte[]
CacheGetResult refreshTimeResult = concreteCache.GET(timestampKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.alicp.jetcache.AbstractCache;
import com.alicp.jetcache.CacheConfigException;
import com.alicp.jetcache.CacheException;
import com.alicp.jetcache.RefreshCache;
import com.alicp.jetcache.anno.KeyConvertor;

import java.io.IOException;
Expand All @@ -28,7 +29,7 @@ protected void checkConfig() {
if (config.getValueDecoder() == null) {
throw new CacheConfigException("no value decoder");
}
if (config.getKeyPrefix() == null){
if (config.getKeyPrefix() == null) {
throw new CacheConfigException("keyPrefix is required");
}
}
Expand All @@ -38,8 +39,10 @@ public byte[] buildKey(K key) {
Object newKey = key;
if (config.getKeyConvertor() != null) {
if (config.getKeyConvertor() instanceof KeyConvertor) {
// since 2.7.3 KeyConvertor extends Function<Object, Object>
newKey = config.getKeyConvertor().apply(key);
if (!isPreservedKey(key)) {
// since 2.7.3 KeyConvertor extends Function<Object, Object>
newKey = config.getKeyConvertor().apply(key);
}
} else {
// before 2.7.3, KeyConvertor is interface only place some constants.
// "key convertor" is Function<Object, Object> and can't process byte[] and String
Expand All @@ -58,4 +61,27 @@ public byte[] buildKey(K key) {
}
}

private boolean isPreservedKey(Object key) {
if (key instanceof byte[]) {
byte[] keyBytes = (byte[]) key;
return endWith(keyBytes, RefreshCache.LOCK_KEY_SUFFIX)
|| endWith(keyBytes, RefreshCache.TIMESTAMP_KEY_SUFFIX);
}
return false;
}

private boolean endWith(byte[] key, byte[] suffix) {
int len = suffix.length;
if (key.length < len) {
return false;
}
int startPos = key.length - len;
for (int i = 0; i < len; i++) {
if (key[startPos + i] != suffix[i]) {
return false;
}
}
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Created on 2023/01/05.
*/
package com.alicp.jetcache.external;

import com.alicp.jetcache.RefreshCache;
import com.alicp.jetcache.anno.KeyConvertor;
import com.alicp.jetcache.support.Fastjson2KeyConvertor;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

/**
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
*/
public class ExternalCacheBuildKeyTest {
@Test
public void testBuildKey() {
MockRemoteCache c = (MockRemoteCache) MockRemoteCacheBuilder.createMockRemoteCacheBuilder()
.keyPrefix("")
.buildCache();
byte[] byteKey = new byte[]{1, 2, 3};
String strKey = "123";
assertArrayEquals(byteKey, c.buildKey(byteKey));
assertArrayEquals(strKey.getBytes(), c.buildKey(strKey));

c.config().setKeyConvertor(Fastjson2KeyConvertor.INSTANCE);
assertArrayEquals(byteKey, c.buildKey(byteKey));
assertArrayEquals(strKey.getBytes(), c.buildKey(strKey));

String convertedKey = "456";
c.config().setKeyConvertor((KeyConvertor) o -> convertedKey);
assertArrayEquals(convertedKey.getBytes(), c.buildKey(byteKey));
assertArrayEquals(convertedKey.getBytes(), c.buildKey(strKey));
assertArrayEquals(convertedKey.getBytes(), c.buildKey("long long long str"));
assertArrayEquals(convertedKey.getBytes(), c.buildKey(1));

strKey = "123" + new String(RefreshCache.LOCK_KEY_SUFFIX);
assertArrayEquals(strKey.getBytes(), c.buildKey(strKey.getBytes()));
strKey = "123" + new String(RefreshCache.TIMESTAMP_KEY_SUFFIX);
assertArrayEquals(strKey.getBytes(), c.buildKey(strKey.getBytes()));
strKey = "" + new String(RefreshCache.TIMESTAMP_KEY_SUFFIX);
assertArrayEquals(strKey.getBytes(), c.buildKey(strKey.getBytes()));
}
}

0 comments on commit 00bcbb3

Please sign in to comment.