DATAREDIS-744 - Polishing

Move binary lookup methods to ByteUtils, update license headers and restore altered tests by creating additional ones.

Original Pull Request: #298
This commit is contained in:
Christoph Strobl
2018-01-11 14:09:05 +01:00
parent c6ad238cea
commit 765a6d1cb0
8 changed files with 140 additions and 48 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ public class RedisKeyExpiredEvent<T> extends RedisKeyspaceEvent {
/**
* Use {@literal UTF-8} as default charset.
*/
public static final Charset CHARSET = Charset.forName("UTF-8");
static final Charset CHARSET = Charset.forName("UTF-8");
private final BinaryKeyspaceIdentifier objectId;
private final Object value;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1248,11 +1248,11 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
Assert.isTrue(isValid(key), String.format("Invalid key %s", new String(key)));
boolean phantomKey = startsWith(key, PHANTOM_SUFFIX, key.length - PHANTOM_SUFFIX.length);
boolean phantomKey = ByteUtils.startsWith(key, PHANTOM_SUFFIX, key.length - PHANTOM_SUFFIX.length);
int keyspaceEndIndex = find(key, DELIMITTER);
byte[] keyspace = getKeyspace(key, keyspaceEndIndex);
byte[] id = getId(key, phantomKey, keyspaceEndIndex);
int keyspaceEndIndex = ByteUtils.indexOf(key, DELIMITTER);
byte[] keyspace = extractKeyspace(key, keyspaceEndIndex);
byte[] id = extractId(key, phantomKey, keyspaceEndIndex);
return new BinaryKeyspaceIdentifier(keyspace, id, phantomKey);
}
@@ -1270,12 +1270,12 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
return false;
}
int keyspaceEndIndex = find(key, DELIMITTER);
int keyspaceEndIndex = ByteUtils.indexOf(key, DELIMITTER);
return keyspaceEndIndex > 0 && key.length > keyspaceEndIndex;
}
private static byte[] getId(byte[] key, boolean phantomKey, int keyspaceEndIndex) {
private static byte[] extractId(byte[] key, boolean phantomKey, int keyspaceEndIndex) {
int idSize;
@@ -1292,42 +1292,12 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
return id;
}
private static byte[] getKeyspace(byte[] key, int keyspaceEndIndex) {
private static byte[] extractKeyspace(byte[] key, int keyspaceEndIndex) {
byte[] keyspace = new byte[keyspaceEndIndex];
System.arraycopy(key, 0, keyspace, 0, keyspaceEndIndex);
return keyspace;
}
private static boolean startsWith(byte[] haystack, byte[] prefix, int offset) {
int to = offset;
int prefixOffset = 0;
int prefixLength = prefix.length;
if ((offset < 0) || (offset > haystack.length - prefixLength)) {
return false;
}
while (--prefixLength >= 0) {
if (haystack[to++] != prefix[prefixOffset++]) {
return false;
}
}
return true;
}
private static int find(byte[] haystack, byte needle) {
for (int i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) {
return i;
}
}
return -1;
}
}
}

View File

@@ -98,4 +98,65 @@ public final class ByteUtils {
return result;
}
/**
* Tests if the {@code haystack} starts with the given {@code prefix}.
*
* @param haystack the source to scan.
* @param prefix the prefix to find.
* @return {@literal true} if {@code haystack} at position {@code offset} starts with {@code prefix}.
* @since 1.8.10
* @see #startsWith(byte[], byte[], int)
*/
public static boolean startsWith(byte[] haystack, byte[] prefix) {
return startsWith(haystack, prefix, 0);
}
/**
* Tests if the {@code haystack} beginning at the specified {@code offset} starts with the given {@code prefix}.
*
* @param haystack the source to scan.
* @param prefix the prefix to find.
* @param offset the offset to start at.
* @return {@literal true} if {@code haystack} at position {@code offset} starts with {@code prefix}.
* @since 1.8.10
*/
public static boolean startsWith(byte[] haystack, byte[] prefix, int offset) {
int to = offset;
int prefixOffset = 0;
int prefixLength = prefix.length;
if ((offset < 0) || (offset > haystack.length - prefixLength)) {
return false;
}
while (--prefixLength >= 0) {
if (haystack[to++] != prefix[prefixOffset++]) {
return false;
}
}
return true;
}
/**
* Searches the specified array of bytes for the specified value. Returns the index of the first matching value in the
* {@code haystack}s natural order or {@code -1} of {@code needle} could not be found.
*
* @param haystack the source to scan.
* @param needle the value to scan for.
* @return index of first appearance, or -1 if not found.
* @since 1.8.10
*/
public static int indexOf(byte[] haystack, byte needle) {
for (int i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) {
return i;
}
}
return -1;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2015-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -215,9 +215,23 @@ public class RedisKeyValueAdapterTests {
assertThat(template.opsForSet().members("persons:address.country:Andor"), hasItems("1"));
}
@Test // DATAREDIS-425, DATAREDIS-744
@Test // DATAREDIS-425
public void getShouldReadSimpleObjectCorrectly() {
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("_class", Person.class.getName());
map.put("age", "24");
template.opsForHash().putAll("persons:load-1", map);
Object loaded = adapter.get("load-1", "persons");
assertThat(loaded, instanceOf(Person.class));
assertThat(((Person) loaded).age, is(24));
}
@Test // DATAREDIS-744
public void getShouldReadSimpleObjectWithColonInIdCorrectly() {
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("_class", Person.class.getName());
map.put("age", "24");
@@ -288,7 +302,7 @@ public class RedisKeyValueAdapterTests {
assertThat(template.opsForSet().members("persons:firstname:rand"), not(hasItem("1")));
}
@Test // DATAREDIS-425, DATAREDIS-744
@Test // DATAREDIS-425
public void keyExpiredEventShouldRemoveHelperStructures() throws Exception {
assumeTrue(RedisTestProfileValueSource.matches("runLongTests", "true"));
@@ -298,6 +312,34 @@ public class RedisKeyValueAdapterTests {
map.put("firstname", "rand");
map.put("address.country", "Andor");
template.opsForHash().putAll("persons:1", map);
template.opsForSet().add("persons", "1");
template.opsForSet().add("persons:firstname:rand", "1");
template.opsForSet().add("persons:1:idx", "persons:firstname:rand");
template.expire("persons:1", 100, TimeUnit.MILLISECONDS);
waitUntilKeyIsGone(template, "persons:1");
waitUntilKeyIsGone(template, "persons:1:phantom");
waitUntilKeyIsGone(template, "persons:firstname:rand");
assertThat(template.hasKey("persons:1"), is(false));
assertThat(template.hasKey("persons:firstname:rand"), is(false));
assertThat(template.hasKey("persons:1:idx"), is(false));
assertThat(template.opsForSet().members("persons"), not(hasItem("1")));
}
@Test // DATAREDIS-744
public void keyExpiredEventShouldRemoveHelperStructuresForObjectsWithColonInId() throws Exception {
assumeTrue(RedisTestProfileValueSource.matches("runLongTests", "true"));
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("_class", Person.class.getName());
map.put("firstname", "rand");
map.put("address.country", "Andor");
template.opsForHash().putAll("persons:1:b", map);
template.opsForSet().add("persons", "1");
@@ -379,12 +421,31 @@ public class RedisKeyValueAdapterTests {
assertThat(template.opsForSet().isMember("persons:mat:idx", "persons:firstname:mat"), is(true));
}
@Test // DATAREDIS-471, DATAREDIS-744
@Test // DATAREDIS-471
public void updateShouldAlterIndexDataCorrectly() {
Person rand = new Person();
rand.firstname = "rand";
adapter.put("1", rand, "persons");
assertThat(template.hasKey("persons:firstname:rand"), is(true));
PartialUpdate<Person> update = new PartialUpdate<Person>("1", Person.class) //
.set("firstname", "mat");
adapter.update(update);
assertThat(template.hasKey("persons:firstname:rand"), is(false));
assertThat(template.hasKey("persons:firstname:mat"), is(true));
}
@Test // DATAREDIS-744
public void updateShouldAlterIndexDataForObjectsWithColonInIdCorrectly() {
Person rand = new Person();
rand.firstname = "rand";
adapter.put("1:a", rand, "persons");
assertThat(template.hasKey("persons:firstname:rand"), is(true));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.