Skip to content

Commit d8ec35f

Browse files
DATAREDIS-744 - Polishing
Move binary lookup methods to ByteUtils, update license headers and restore altered tests by creating additional ones. Original Pull Request: #298
1 parent 5de7390 commit d8ec35f

File tree

7 files changed

+136
-44
lines changed

7 files changed

+136
-44
lines changed

src/main/java/org/springframework/data/redis/core/RedisKeyExpiredEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class RedisKeyExpiredEvent<T> extends RedisKeyspaceEvent {
3535
/**
3636
* Use {@literal UTF-8} as default charset.
3737
*/
38-
public static final Charset CHARSET = StandardCharsets.UTF_8;
38+
static final Charset CHARSET = StandardCharsets.UTF_8;
3939

4040
private final BinaryKeyspaceIdentifier objectId;
4141
private final @Nullable Object value;

src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,11 +1264,11 @@ public static BinaryKeyspaceIdentifier of(byte[] key) {
12641264

12651265
Assert.isTrue(isValid(key), String.format("Invalid key %s", new String(key)));
12661266

1267-
boolean phantomKey = startsWith(key, PHANTOM_SUFFIX, key.length - PHANTOM_SUFFIX.length);
1267+
boolean phantomKey = ByteUtils.startsWith(key, PHANTOM_SUFFIX, key.length - PHANTOM_SUFFIX.length);
12681268

1269-
int keyspaceEndIndex = find(key, DELIMITTER);
1270-
byte[] keyspace = getKeyspace(key, keyspaceEndIndex);
1271-
byte[] id = getId(key, phantomKey, keyspaceEndIndex);
1269+
int keyspaceEndIndex = ByteUtils.indexOf(key, DELIMITTER);
1270+
byte[] keyspace = extractKeyspace(key, keyspaceEndIndex);
1271+
byte[] id = extractId(key, phantomKey, keyspaceEndIndex);
12721272

12731273
return new BinaryKeyspaceIdentifier(keyspace, id, phantomKey);
12741274
}
@@ -1286,12 +1286,12 @@ public static boolean isValid(byte[] key) {
12861286
return false;
12871287
}
12881288

1289-
int keyspaceEndIndex = find(key, DELIMITTER);
1289+
int keyspaceEndIndex = ByteUtils.indexOf(key, DELIMITTER);
12901290

12911291
return keyspaceEndIndex > 0 && key.length > keyspaceEndIndex;
12921292
}
12931293

1294-
private static byte[] getId(byte[] key, boolean phantomKey, int keyspaceEndIndex) {
1294+
private static byte[] extractId(byte[] key, boolean phantomKey, int keyspaceEndIndex) {
12951295

12961296
int idSize;
12971297

@@ -1308,42 +1308,12 @@ private static byte[] getId(byte[] key, boolean phantomKey, int keyspaceEndIndex
13081308
return id;
13091309
}
13101310

1311-
private static byte[] getKeyspace(byte[] key, int keyspaceEndIndex) {
1311+
private static byte[] extractKeyspace(byte[] key, int keyspaceEndIndex) {
13121312

13131313
byte[] keyspace = new byte[keyspaceEndIndex];
13141314
System.arraycopy(key, 0, keyspace, 0, keyspaceEndIndex);
13151315

13161316
return keyspace;
13171317
}
1318-
1319-
private static boolean startsWith(byte[] haystack, byte[] prefix, int offset) {
1320-
1321-
int to = offset;
1322-
int prefixOffset = 0;
1323-
int prefixLength = prefix.length;
1324-
1325-
if ((offset < 0) || (offset > haystack.length - prefixLength)) {
1326-
return false;
1327-
}
1328-
1329-
while (--prefixLength >= 0) {
1330-
if (haystack[to++] != prefix[prefixOffset++]) {
1331-
return false;
1332-
}
1333-
}
1334-
1335-
return true;
1336-
}
1337-
1338-
private static int find(byte[] haystack, byte needle) {
1339-
1340-
for (int i = 0; i < haystack.length; i++) {
1341-
if (haystack[i] == needle) {
1342-
return i;
1343-
}
1344-
}
1345-
1346-
return -1;
1347-
}
13481318
}
13491319
}

src/main/java/org/springframework/data/redis/util/ByteUtils.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,65 @@ public static byte[] getBytes(ByteBuffer byteBuffer) {
142142
duplicate.get(bytes);
143143
return bytes;
144144
}
145+
146+
/**
147+
* Tests if the {@code haystack} starts with the given {@code prefix}.
148+
*
149+
* @param haystack the source to scan.
150+
* @param prefix the prefix to find.
151+
* @return {@literal true} if {@code haystack} at position {@code offset} starts with {@code prefix}.
152+
* @since 1.8.10
153+
* @see #startsWith(byte[], byte[], int)
154+
*/
155+
public static boolean startsWith(byte[] haystack, byte[] prefix) {
156+
return startsWith(haystack, prefix, 0);
157+
}
158+
159+
/**
160+
* Tests if the {@code haystack} beginning at the specified {@code offset} starts with the given {@code prefix}.
161+
*
162+
* @param haystack the source to scan.
163+
* @param prefix the prefix to find.
164+
* @param offset the offset to start at.
165+
* @return {@literal true} if {@code haystack} at position {@code offset} starts with {@code prefix}.
166+
* @since 1.8.10
167+
*/
168+
public static boolean startsWith(byte[] haystack, byte[] prefix, int offset) {
169+
170+
int to = offset;
171+
int prefixOffset = 0;
172+
int prefixLength = prefix.length;
173+
174+
if ((offset < 0) || (offset > haystack.length - prefixLength)) {
175+
return false;
176+
}
177+
178+
while (--prefixLength >= 0) {
179+
if (haystack[to++] != prefix[prefixOffset++]) {
180+
return false;
181+
}
182+
}
183+
184+
return true;
185+
}
186+
187+
/**
188+
* Searches the specified array of bytes for the specified value. Returns the index of the first matching value in the
189+
* {@code haystack}s natural order or {@code -1} of {@code needle} could not be found.
190+
*
191+
* @param haystack the source to scan.
192+
* @param needle the value to scan for.
193+
* @return index of first appearance, or -1 if not found.
194+
* @since 1.8.10
195+
*/
196+
public static int indexOf(byte[] haystack, byte needle) {
197+
198+
for (int i = 0; i < haystack.length; i++) {
199+
if (haystack[i] == needle) {
200+
return i;
201+
}
202+
}
203+
204+
return -1;
205+
}
145206
}

src/test/java/org/springframework/data/redis/core/RedisKeyExpiredEventUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

src/test/java/org/springframework/data/redis/core/RedisKeyValueAdapterTests.java

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,26 @@ public void putWritesSimpleNestedIndexValuesCorrectly() {
210210
assertThat(template.opsForSet().members("persons:address.country:Andor"), hasItems("1"));
211211
}
212212

213-
@Test // DATAREDIS-425, DATAREDIS-744
213+
@Test // DATAREDIS-425
214214
public void getShouldReadSimpleObjectCorrectly() {
215215

216216
Map<String, String> map = new LinkedHashMap<>();
217217
map.put("_class", Person.class.getName());
218218
map.put("age", "24");
219+
template.opsForHash().putAll("persons:load-1", map);
220+
221+
Object loaded = adapter.get("load-1", "persons");
222+
223+
assertThat(loaded, instanceOf(Person.class));
224+
assertThat(((Person) loaded).age, is(24));
225+
}
226+
227+
@Test // DATAREDIS-744
228+
public void getShouldReadSimpleObjectWithColonInIdCorrectly() {
229+
230+
Map<String, String> map = new LinkedHashMap<String, String>();
231+
map.put("_class", Person.class.getName());
232+
map.put("age", "24");
219233
template.opsForHash().putAll("persons:load-1:a", map);
220234

221235
Object loaded = adapter.get("load-1:a", "persons");
@@ -283,7 +297,7 @@ public void deleteCleansIndexedDataCorrectly() {
283297
assertThat(template.opsForSet().members("persons:firstname:rand"), not(hasItem("1")));
284298
}
285299

286-
@Test // DATAREDIS-425, DATAREDIS-744
300+
@Test // DATAREDIS-425
287301
public void keyExpiredEventShouldRemoveHelperStructures() throws Exception {
288302

289303
assumeTrue(RedisTestProfileValueSource.matches("runLongTests", "true"));
@@ -293,6 +307,34 @@ public void keyExpiredEventShouldRemoveHelperStructures() throws Exception {
293307
map.put("firstname", "rand");
294308
map.put("address.country", "Andor");
295309

310+
template.opsForHash().putAll("persons:1", map);
311+
312+
template.opsForSet().add("persons", "1");
313+
template.opsForSet().add("persons:firstname:rand", "1");
314+
template.opsForSet().add("persons:1:idx", "persons:firstname:rand");
315+
316+
template.expire("persons:1", 100, TimeUnit.MILLISECONDS);
317+
318+
waitUntilKeyIsGone(template, "persons:1");
319+
waitUntilKeyIsGone(template, "persons:1:phantom");
320+
waitUntilKeyIsGone(template, "persons:firstname:rand");
321+
322+
assertThat(template.hasKey("persons:1"), is(false));
323+
assertThat(template.hasKey("persons:firstname:rand"), is(false));
324+
assertThat(template.hasKey("persons:1:idx"), is(false));
325+
assertThat(template.opsForSet().members("persons"), not(hasItem("1")));
326+
}
327+
328+
@Test // DATAREDIS-744
329+
public void keyExpiredEventShouldRemoveHelperStructuresForObjectsWithColonInId() throws Exception {
330+
331+
assumeTrue(RedisTestProfileValueSource.matches("runLongTests", "true"));
332+
333+
Map<String, String> map = new LinkedHashMap<String, String>();
334+
map.put("_class", Person.class.getName());
335+
map.put("firstname", "rand");
336+
map.put("address.country", "Andor");
337+
296338
template.opsForHash().putAll("persons:1:b", map);
297339

298340
template.opsForSet().add("persons", "1");
@@ -374,12 +416,31 @@ public void putWritesIndexDataCorrectly() {
374416
assertThat(template.opsForSet().isMember("persons:mat:idx", "persons:firstname:mat"), is(true));
375417
}
376418

377-
@Test // DATAREDIS-471, DATAREDIS-744
419+
@Test // DATAREDIS-471
378420
public void updateShouldAlterIndexDataCorrectly() {
379421

380422
Person rand = new Person();
381423
rand.firstname = "rand";
382424

425+
adapter.put("1", rand, "persons");
426+
427+
assertThat(template.hasKey("persons:firstname:rand"), is(true));
428+
429+
PartialUpdate<Person> update = new PartialUpdate<Person>("1", Person.class) //
430+
.set("firstname", "mat");
431+
432+
adapter.update(update);
433+
434+
assertThat(template.hasKey("persons:firstname:rand"), is(false));
435+
assertThat(template.hasKey("persons:firstname:mat"), is(true));
436+
}
437+
438+
@Test // DATAREDIS-744
439+
public void updateShouldAlterIndexDataForObjectsWithColonInIdCorrectly() {
440+
441+
Person rand = new Person();
442+
rand.firstname = "rand";
443+
383444
adapter.put("1:a", rand, "persons");
384445

385446
assertThat(template.hasKey("persons:firstname:rand"), is(true));

src/test/java/org/springframework/data/redis/core/convert/BinaryKeyspaceIdentifierUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

src/test/java/org/springframework/data/redis/core/convert/KeyspaceIdentifierUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)