Skip to content

Commit 9b18e0c

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 8933e02 commit 9b18e0c

File tree

2 files changed

+43
-23
lines changed

2 files changed

+43
-23
lines changed

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

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -235,23 +235,27 @@ public Object put(Object id, Object item, String keyspace) {
235235

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

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

242+
if (expires(rdo)) {
240243
connection.expire(objectKey, rdo.getTimeToLive());
244+
}
245+
246+
if (keepShadowCopy()) { // add phantom key so values can be restored
241247

242-
// add phantom key so values can be restored
243248
byte[] phantomKey = ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
244-
connection.del(phantomKey);
245-
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
246-
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
247-
}
248249

249-
boolean isNoExpire = rdo.getTimeToLive() == null || rdo.getTimeToLive() != null && rdo.getTimeToLive() < 0;
250-
if (isNoExpire && !isNew && keepShadowCopy()) {
251-
connection.del(ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
252-
}
250+
if (expires(rdo)) {
253251

254-
connection.sAdd(toBytes(rdo.getKeyspace()), key);
252+
connection.del(phantomKey);
253+
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
254+
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
255+
} else if (!isNew) {
256+
connection.del(phantomKey);
257+
}
258+
}
255259

256260
IndexWriter indexWriter = new IndexWriter(connection, converter);
257261
if (isNew) {
@@ -346,11 +350,14 @@ public <T> T delete(Object id, String keyspace, Class<T> type) {
346350
connection.sRem(binKeyspace, binId);
347351
new IndexWriter(connection, converter).removeKeyFromIndexes(asString(keyspace), binId);
348352

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

352-
byte[] phantomKey = ByteUtils.concat(keyToDelete, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
353-
connection.del(phantomKey);
355+
RedisPersistentEntity<?> persistentEntity = converter.getMappingContext().getPersistentEntity(type);
356+
if (persistentEntity != null && persistentEntity.isExpiring()) {
357+
358+
byte[] phantomKey = ByteUtils.concat(keyToDelete, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
359+
connection.del(phantomKey);
360+
}
354361
}
355362
return null;
356363
});
@@ -481,7 +488,7 @@ public void update(PartialUpdate<?> update) {
481488

482489
if (update.isRefreshTtl()) {
483490

484-
if (rdo.getTimeToLive() != null && rdo.getTimeToLive() > 0) {
491+
if (expires(rdo)) {
485492

486493
connection.expire(redisKey, rdo.getTimeToLive());
487494

@@ -493,7 +500,10 @@ public void update(PartialUpdate<?> update) {
493500
} else {
494501

495502
connection.persist(redisKey);
496-
connection.del(ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
503+
504+
if(keepShadowCopy()) {
505+
connection.del(ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX));
506+
}
497507
}
498508
}
499509

@@ -650,6 +660,16 @@ private <T> T readBackTimeToLiveIfSet(@Nullable byte[] key, @Nullable T target)
650660
return target;
651661
}
652662

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

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -688,10 +688,10 @@ public void updateShouldAlterGeoIndexCorrectlyOnUpdate() {
688688
assertThat(updatedLocation.getY()).isCloseTo(18D, offset(0.005));
689689
}
690690

691-
@Test // DATAREDIS-1955
691+
@Test // GH-1955
692692
public void phantomKeyIsDeletedWhenPutWithNegativeTimeToLiveAndOldEntryTimeToLiveWasPositiveAndWhenShadowCopyIsTurnedOn() {
693+
693694
ExpiringPerson rand = new ExpiringPerson();
694-
rand.id = "1";
695695
rand.ttl = 3000L;
696696

697697
adapter.put("1", rand, "persons");
@@ -705,21 +705,21 @@ public void phantomKeyIsDeletedWhenPutWithNegativeTimeToLiveAndOldEntryTimeToLiv
705705
assertThat(template.hasKey("persons:1:phantom")).isFalse();
706706
}
707707

708-
@Test // DATAREDIS-1955
708+
@Test // GH-1955
709709
public void updateWithRefreshTtlAndWithoutPositiveTtlShouldDeletePhantomKey() {
710+
710711
ExpiringPerson person = new ExpiringPerson();
711-
person.id = "1";
712712
person.ttl = 100L;
713713

714714
adapter.put("1", person, "persons");
715-
716715
assertThat(template.getExpire("persons:1:phantom")).isPositive();
717716

718717
PartialUpdate<ExpiringPerson> update = new PartialUpdate<>("1", ExpiringPerson.class) //
719-
.refreshTtl(true);
718+
.set("ttl", -1L).refreshTtl(true);
720719

721720
adapter.update(update);
722721

722+
assertThat(template.getExpire("persons:1")).isNotPositive();
723723
assertThat(template.hasKey("persons:1:phantom")).isFalse();
724724
}
725725

0 commit comments

Comments
 (0)