Skip to content

Commit 5d3d212

Browse files
Move expires check to dedicated method.
Introduce helper method to unify expiry check and simplify control flow. Original Pull Request: #1961
1 parent 3f4df6d commit 5d3d212

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

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

+34-16
Original file line numberDiff line numberDiff line change
@@ -236,26 +236,28 @@ public Object put(Object id, Object item, String keyspace) {
236236

237237
connection.hMSet(objectKey, rdo.getBucket().rawMap());
238238

239-
if (rdo.getTimeToLive() != null && rdo.getTimeToLive() > 0) {
239+
if(isNew) {
240+
connection.sAdd(toBytes(rdo.getKeyspace()), key);
241+
}
240242

243+
if (expires(rdo)) {
241244
connection.expire(objectKey, rdo.getTimeToLive());
245+
}
246+
247+
if (keepShadowCopy()) { // add phantom key so values can be restored
248+
249+
byte[] phantomKey = ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
242250

243-
if (keepShadowCopy()) { // add phantom key so values can be restored
251+
if (expires(rdo)) {
244252

245-
byte[] phantomKey = ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
246253
connection.del(phantomKey);
247254
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
248255
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
256+
} else if (!isNew) {
257+
connection.del(phantomKey);
249258
}
250259
}
251260

252-
boolean isNoExpire = rdo.getTimeToLive() == null || rdo.getTimeToLive() != null && rdo.getTimeToLive() < 0;
253-
if (isNoExpire && !isNew && keepShadowCopy()){
254-
connection.del(ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
255-
}
256-
257-
connection.sAdd(toBytes(rdo.getKeyspace()), key);
258-
259261
IndexWriter indexWriter = new IndexWriter(connection, converter);
260262
if (isNew) {
261263
indexWriter.createIndexes(key, rdo.getIndexedData());
@@ -349,11 +351,14 @@ public <T> T delete(Object id, String keyspace, Class<T> type) {
349351
connection.sRem(binKeyspace, binId);
350352
new IndexWriter(connection, converter).removeKeyFromIndexes(asString(keyspace), binId);
351353

352-
RedisPersistentEntity<?> persistentEntity = converter.getMappingContext().getPersistentEntity(type);
353-
if (persistentEntity != null && persistentEntity.isExpiring()) {
354+
if(RedisKeyValueAdapter.this.keepShadowCopy()) {
354355

355-
byte[] phantomKey = ByteUtils.concat(keyToDelete, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
356-
connection.del(phantomKey);
356+
RedisPersistentEntity<?> persistentEntity = converter.getMappingContext().getPersistentEntity(type);
357+
if (persistentEntity != null && persistentEntity.isExpiring()) {
358+
359+
byte[] phantomKey = ByteUtils.concat(keyToDelete, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
360+
connection.del(phantomKey);
361+
}
357362
}
358363
return null;
359364
});
@@ -484,7 +489,7 @@ public void update(PartialUpdate<?> update) {
484489

485490
if (update.isRefreshTtl()) {
486491

487-
if (rdo.getTimeToLive() != null && rdo.getTimeToLive() > 0) {
492+
if (expires(rdo)) {
488493

489494
connection.expire(redisKey, rdo.getTimeToLive());
490495

@@ -498,7 +503,10 @@ public void update(PartialUpdate<?> update) {
498503
} else {
499504

500505
connection.persist(redisKey);
501-
connection.del(ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
506+
507+
if(keepShadowCopy()) {
508+
connection.del(ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
509+
}
502510
}
503511
}
504512

@@ -655,6 +663,16 @@ private <T> T readBackTimeToLiveIfSet(@Nullable byte[] key, @Nullable T target)
655663
return target;
656664
}
657665

666+
/**
667+
* @return {@literal true} if {@link RedisData#getTimeToLive()} has a positive value.
668+
*
669+
* @param data must not be {@literal null}.
670+
* @since 2.3.7
671+
*/
672+
private boolean expires(RedisData data) {
673+
return data.getTimeToLive() != null && data.getTimeToLive() > 0;
674+
}
675+
658676
/**
659677
* Configure usage of {@link KeyExpirationEventMessageListener}.
660678
*

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -706,10 +706,10 @@ void phantomKeyInsertedOnPutWhenShadowCopyIsInDefaultAndKeyspaceNotificationEnab
706706
assertThat(template.hasKey("persons:1:phantom")).isTrue();
707707
}
708708

709-
@Test // DATAREDIS-1955
709+
@Test // GH-1955
710710
void phantomKeyIsDeletedWhenPutWithNegativeTimeToLiveAndOldEntryTimeToLiveWasPositiveAndWhenShadowCopyIsTurnedOn() {
711+
711712
ExpiringPerson rand = new ExpiringPerson();
712-
rand.id = "1";
713713
rand.ttl = 3000L;
714714

715715
adapter.put("1", rand, "persons");
@@ -723,21 +723,21 @@ void phantomKeyIsDeletedWhenPutWithNegativeTimeToLiveAndOldEntryTimeToLiveWasPos
723723
assertThat(template.hasKey("persons:1:phantom")).isFalse();
724724
}
725725

726-
@Test // DATAREDIS-1955
726+
@Test // GH-1955
727727
void updateWithRefreshTtlAndWithoutPositiveTtlShouldDeletePhantomKey() {
728+
728729
ExpiringPerson person = new ExpiringPerson();
729-
person.id = "1";
730730
person.ttl = 100L;
731731

732732
adapter.put("1", person, "persons");
733-
734733
assertThat(template.getExpire("persons:1:phantom")).isPositive();
735734

736735
PartialUpdate<ExpiringPerson> update = new PartialUpdate<>("1", ExpiringPerson.class) //
737-
.refreshTtl(true);
736+
.set("ttl", -1L).refreshTtl(true);
738737

739738
adapter.update(update);
740739

740+
assertThat(template.getExpire("persons:1")).isNotPositive();
741741
assertThat(template.hasKey("persons:1:phantom")).isFalse();
742742
}
743743

0 commit comments

Comments
 (0)