Skip to content

Commit 2d09e74

Browse files
authored
Support ttl changes through write policy (#136)
* Added support for LocalDate and LocalDateTime * Support for LocalDate and LocalDateTime - Added a unit test for LocalDateMapper and LocalDateTimeMapper - Changed LocalDateMapper to use EpochDays - Changed LocalDateTimeMapper to preserve full precision of the LocalDateTime down the nanosecond level. * Added LocalTime mapper Added a mapper for LocalTime to round out Java 8 date / time classes. Included a unit test for them. * Fix for #132 -- Dynamically set TTL on individual record. Made 2 changes to the TTL behaviour: 1. If a WritePolicy is explicitly passed to the save method, the settings in this policy are honoured, so neither the TTL nor the SendKey will be altered. 2. Defaulted the AerospikeRecord.ttl() to Integer.MIN_VALUE and changed the logic so this effectively becomes "not set". Without this change a TTL set via an initial policy passed to the Builder (and not via the AerospikeRecord annotation) would not be honoured under any circumstances. * Update AeroMapper.java * Update TestCustomTtl.java * Update AerospikeRecord.java
1 parent 29420e6 commit 2d09e74

File tree

5 files changed

+159
-42
lines changed

5 files changed

+159
-42
lines changed

src/main/java/com/aerospike/mapper/annotations/AerospikeRecord.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414

1515
String shortName() default "";
1616

17-
int ttl() default 0;
17+
/**
18+
* The TTL for the record. As this must be a primitive value <code>Integer.MIN_VALUE</code> is used to indicate that the
19+
* value has not been explicitly set.
20+
*/
21+
int ttl() default Integer.MIN_VALUE;
1822

1923
/**
2024
* Determine whether to add all the bins or not. If true, all bins will be added without having to map them via @AerospikeBin

src/main/java/com/aerospike/mapper/tools/AeroMapper.java

+32-21
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
package com.aerospike.mapper.tools;
22

3-
import com.aerospike.client.*;
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.lang.reflect.Array;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.concurrent.atomic.AtomicBoolean;
10+
import java.util.function.Function;
11+
12+
import javax.validation.constraints.NotNull;
13+
14+
import org.apache.commons.lang3.StringUtils;
15+
16+
import com.aerospike.client.AerospikeException;
417
import com.aerospike.client.AerospikeException.ScanTerminated;
18+
import com.aerospike.client.Bin;
19+
import com.aerospike.client.IAerospikeClient;
20+
import com.aerospike.client.Key;
21+
import com.aerospike.client.Log;
22+
import com.aerospike.client.Operation;
523
import com.aerospike.client.Record;
24+
import com.aerospike.client.Value;
625
import com.aerospike.client.policy.BatchPolicy;
726
import com.aerospike.client.policy.Policy;
827
import com.aerospike.client.policy.QueryPolicy;
@@ -22,17 +41,6 @@
2241
import com.fasterxml.jackson.core.JsonProcessingException;
2342
import com.fasterxml.jackson.databind.ObjectMapper;
2443
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
25-
import org.apache.commons.lang3.StringUtils;
26-
27-
import javax.validation.constraints.NotNull;
28-
import java.io.File;
29-
import java.io.IOException;
30-
import java.io.InputStream;
31-
import java.lang.reflect.Array;
32-
import java.util.ArrayList;
33-
import java.util.List;
34-
import java.util.concurrent.atomic.AtomicBoolean;
35-
import java.util.function.Function;
3644

3745
public class AeroMapper implements IAeroMapper {
3846

@@ -216,22 +224,25 @@ private <T> void save(WritePolicy writePolicy, @NotNull T object, RecordExistsAc
216224
if (recordExistsAction != null) {
217225
writePolicy.recordExistsAction = recordExistsAction;
218226
}
227+
228+
// #132 -- Ensure that if an overriding TTL / sendkey is passed in the policy it is NOT overwritten. Hence
229+
// only if the policy is null do we override these settings.
230+
Integer ttl = entry.getTtl();
231+
Boolean sendKey = entry.getSendKey();
232+
233+
if (ttl != null) {
234+
writePolicy.expiration = ttl;
235+
}
236+
if (sendKey != null) {
237+
writePolicy.sendKey = sendKey;
238+
}
219239
}
220240

221241
String set = entry.getSetName();
222242
if ("".equals(set)) {
223243
// Use the null set
224244
set = null;
225245
}
226-
Integer ttl = entry.getTtl();
227-
Boolean sendKey = entry.getSendKey();
228-
229-
if (ttl != null) {
230-
writePolicy.expiration = ttl;
231-
}
232-
if (sendKey != null) {
233-
writePolicy.sendKey = sendKey;
234-
}
235246
Key key = new Key(entry.getNamespace(), set, Value.get(entry.getKey(object)));
236247

237248
Bin[] bins = entry.getBins(object, writePolicy.recordExistsAction != RecordExistsAction.REPLACE, binNames);

src/main/java/com/aerospike/mapper/tools/ClassCacheEntry.java

+31-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
package com.aerospike.mapper.tools;
22

3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.Constructor;
5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.Method;
7+
import java.lang.reflect.Modifier;
8+
import java.lang.reflect.Parameter;
9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
import java.util.HashMap;
12+
import java.util.HashSet;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.Set;
16+
import java.util.TreeMap;
17+
18+
import javax.validation.constraints.NotNull;
19+
20+
import org.apache.commons.lang3.StringUtils;
21+
322
import com.aerospike.client.AerospikeException;
423
import com.aerospike.client.Bin;
524
import com.aerospike.client.Key;
@@ -11,24 +30,22 @@
1130
import com.aerospike.client.policy.QueryPolicy;
1231
import com.aerospike.client.policy.ScanPolicy;
1332
import com.aerospike.client.policy.WritePolicy;
14-
import com.aerospike.mapper.annotations.*;
33+
import com.aerospike.mapper.annotations.AerospikeBin;
34+
import com.aerospike.mapper.annotations.AerospikeConstructor;
35+
import com.aerospike.mapper.annotations.AerospikeExclude;
36+
import com.aerospike.mapper.annotations.AerospikeGetter;
37+
import com.aerospike.mapper.annotations.AerospikeKey;
38+
import com.aerospike.mapper.annotations.AerospikeOrdinal;
39+
import com.aerospike.mapper.annotations.AerospikeRecord;
40+
import com.aerospike.mapper.annotations.AerospikeSetter;
41+
import com.aerospike.mapper.annotations.ParamFrom;
1542
import com.aerospike.mapper.exceptions.NotAnnotatedClass;
1643
import com.aerospike.mapper.tools.configuration.BinConfig;
1744
import com.aerospike.mapper.tools.configuration.ClassConfig;
1845
import com.aerospike.mapper.tools.configuration.KeyConfig;
1946
import com.aerospike.mapper.tools.utils.ParserUtils;
2047
import com.aerospike.mapper.tools.utils.TypeUtils;
2148
import com.aerospike.mapper.tools.utils.TypeUtils.AnnotatedType;
22-
import org.apache.commons.lang3.StringUtils;
23-
24-
import javax.validation.constraints.NotNull;
25-
import java.lang.annotation.Annotation;
26-
import java.lang.reflect.Constructor;
27-
import java.lang.reflect.Field;
28-
import java.lang.reflect.Method;
29-
import java.lang.reflect.Modifier;
30-
import java.lang.reflect.Parameter;
31-
import java.util.*;
3249

3350
public class ClassCacheEntry<T> {
3451

@@ -773,6 +790,9 @@ public String getSetName() {
773790
}
774791

775792
public Integer getTtl() {
793+
if (ttl == null || ttl == Integer.MIN_VALUE) {
794+
return null;
795+
}
776796
return ttl;
777797
}
778798

src/main/java/com/aerospike/mapper/tools/ReactiveAeroMapper.java

+11-9
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,24 @@ private <T> Mono<T> save(WritePolicy writePolicy, @NotNull T object, RecordExist
210210
if (recordExistsAction != null) {
211211
writePolicy.recordExistsAction = recordExistsAction;
212212
}
213+
214+
// #132 -- Only override the TTL / send key if the policy was not passed in.
215+
Integer ttl = entry.getTtl();
216+
Boolean sendKey = entry.getSendKey();
217+
218+
if (ttl != null) {
219+
writePolicy.expiration = ttl;
220+
}
221+
if (sendKey != null) {
222+
writePolicy.sendKey = sendKey;
223+
}
213224
}
214225

215226
String set = entry.getSetName();
216227
if ("".equals(set)) {
217228
// Use the null set
218229
set = null;
219230
}
220-
Integer ttl = entry.getTtl();
221-
Boolean sendKey = entry.getSendKey();
222-
223-
if (ttl != null) {
224-
writePolicy.expiration = ttl;
225-
}
226-
if (sendKey != null) {
227-
writePolicy.sendKey = sendKey;
228-
}
229231
Key key = new Key(entry.getNamespace(), set, Value.get(entry.getKey(object)));
230232

231233
Bin[] bins = entry.getBins(object, writePolicy.recordExistsAction != RecordExistsAction.REPLACE, binNames);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.aerospike.mapper;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import com.aerospike.client.Key;
8+
import com.aerospike.client.Record;
9+
import com.aerospike.client.policy.WritePolicy;
10+
import com.aerospike.mapper.annotations.AerospikeKey;
11+
import com.aerospike.mapper.annotations.AerospikeRecord;
12+
import com.aerospike.mapper.tools.AeroMapper;
13+
14+
public class TestCustomTtl extends AeroMapperBaseTest {
15+
16+
@AerospikeRecord(namespace = "test", set = "classWithTtl", ttl=300)
17+
public static class ClassWithTtl {
18+
@AerospikeKey
19+
public int id;
20+
public String name;
21+
}
22+
23+
@AerospikeRecord(namespace = "test", set = "classWithTtl")
24+
public static class ClassWithTtlViaPolicy {
25+
@AerospikeKey
26+
public int id;
27+
public String name;
28+
}
29+
30+
@Test
31+
public void testTtl() {
32+
AeroMapper mapper = new AeroMapper.Builder(client)
33+
.build();
34+
35+
ClassWithTtl myRecord = new ClassWithTtl();
36+
myRecord.id = 1;
37+
myRecord.name = "not overridden ttl";
38+
mapper.save(myRecord);
39+
40+
WritePolicy customWritePolicy = new WritePolicy(mapper.getWritePolicy(ClassWithTtl.class));
41+
customWritePolicy.expiration = 100;
42+
myRecord.id = 2;
43+
myRecord.name = "overridden ttl";
44+
mapper.save(customWritePolicy, myRecord);
45+
46+
// To validate the TTL, read the records as raw records rather than via the mapper interface
47+
Record readClient1 = client.get(null, new Key("test", "classWithTtl", 1));
48+
Record readClient2 = client.get(null, new Key("test", "classWithTtl", 2));
49+
50+
assertTrue(readClient1.getTimeToLive() > 290 && readClient1.getTimeToLive() <= 300);
51+
assertTrue(readClient2.getTimeToLive() > 90 && readClient2.getTimeToLive() <= 100);
52+
}
53+
54+
@Test
55+
public void testTtlViaPolicy() {
56+
WritePolicy writePolicy = new WritePolicy();
57+
writePolicy.expiration = 300;
58+
AeroMapper mapper = new AeroMapper.Builder(client)
59+
.withWritePolicy(writePolicy).forClasses(ClassWithTtlViaPolicy.class)
60+
.build();
61+
62+
ClassWithTtlViaPolicy myRecord = new ClassWithTtlViaPolicy();
63+
myRecord.id = 1;
64+
myRecord.name = "not overridden ttl";
65+
mapper.save(myRecord);
66+
67+
WritePolicy customWritePolicy = new WritePolicy(mapper.getWritePolicy(ClassWithTtlViaPolicy.class));
68+
customWritePolicy.expiration = 100;
69+
myRecord.id = 2;
70+
myRecord.name = "overridden ttl";
71+
mapper.save(customWritePolicy, myRecord);
72+
73+
// To validate the TTL, read the records as raw records rather than via the mapper interface
74+
Record readClient1 = client.get(null, new Key("test", "classWithTtl", 1));
75+
Record readClient2 = client.get(null, new Key("test", "classWithTtl", 2));
76+
77+
assertTrue(readClient1.getTimeToLive() > 290 && readClient1.getTimeToLive() <= 300);
78+
assertTrue(readClient2.getTimeToLive() > 90 && readClient2.getTimeToLive() <= 100);
79+
}
80+
}

0 commit comments

Comments
 (0)