-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FMWK-459 Fix requiring id property from entities by AerospikeCache #752
Changes from 23 commits
d99e2a2
a27d434
cc0ebaf
3e301e6
c8c970c
9eefab6
15ba1ca
4c9014e
6bb851b
bd1d7f8
b998979
84310ec
9697cb0
e72f8e1
0b04b9f
d650583
2e14355
703ac9e
35aad25
4bc70aa
d65c93f
ac3fff2
ea4a654
18aaaf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.springframework.data.aerospike.cache; | ||
|
||
import com.aerospike.client.Value; | ||
import lombok.Getter; | ||
|
||
/** | ||
* Wrapper class used for caching with methods that receive either a String or a long number | ||
*/ | ||
public class AerospikeCacheKey { | ||
|
||
@Getter | ||
private final Value value; | ||
|
||
private AerospikeCacheKey(String string) { | ||
this.value = new Value.StringValue(string); | ||
} | ||
|
||
private AerospikeCacheKey(long number) { | ||
this.value = new Value.LongValue(number); | ||
} | ||
|
||
/** | ||
* Instantiate AerospikeCacheKey instance with a String. | ||
* | ||
* @param string String parameter | ||
* @return new instance of AerospikeCacheKey initialized with the given parameter | ||
*/ | ||
public static AerospikeCacheKey of(String string) { | ||
return new AerospikeCacheKey(string); | ||
} | ||
|
||
/** | ||
* Instantiate AerospikeCacheKey instance with a long number. | ||
* | ||
* @param number long number | ||
* @return new instance of AerospikeCacheKey initialized with the given parameter | ||
*/ | ||
public static AerospikeCacheKey of(long number) { | ||
return new AerospikeCacheKey(number); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package org.springframework.data.aerospike.cache; | ||
|
||
/** | ||
* Interface that provides methods used in caching | ||
*/ | ||
public interface AerospikeCacheKeyProcessor { | ||
|
||
/** | ||
* Serialize the given key and calculate hash based on the serialization result. | ||
* | ||
* @param key Object to be serialized and hashed | ||
* @return AerospikeCacheKey instantiated with either a String or a long number | ||
*/ | ||
AerospikeCacheKey serializeAndHash(Object key); | ||
|
||
/** | ||
* Serialize the given key. | ||
* <p> | ||
* The default implementation uses Kryo. | ||
* | ||
* @param key Object to be serialized | ||
* @return byte[] | ||
*/ | ||
byte[] serialize(Object key); | ||
|
||
/** | ||
* Calculate hash based on the given byte array. | ||
* <p> | ||
* The default implementation uses 128 bit Murmur3 hashing. | ||
* | ||
* @param data Byte array to be hashed | ||
* @return AerospikeCacheKey instantiated with either a String or a long number | ||
*/ | ||
AerospikeCacheKey calculateHash(byte[] data); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.springframework.data.aerospike.cache; | ||
|
||
import com.esotericsoftware.kryo.Kryo; | ||
import com.esotericsoftware.kryo.io.ByteBufferOutput; | ||
import lombok.Getter; | ||
import org.apache.commons.codec.digest.MurmurHash3; | ||
import org.objenesis.strategy.StdInstantiatorStrategy; | ||
|
||
import java.util.Arrays; | ||
|
||
public class AerospikeCacheKeyProcessorImpl implements AerospikeCacheKeyProcessor { | ||
|
||
Comment on lines
+11
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like this class is a singleton so why not use a bean by marking this class as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The sense here is this class is an implementation of AerospikeCacheKeyProcessor. If users want to use a different implementation, they can do so by overriding AerospikeCacheKeyProcessor bean |
||
@Getter | ||
private final Kryo kryoInstance = new Kryo(); | ||
|
||
public AerospikeCacheKeyProcessorImpl() { | ||
configureKryo(); | ||
} | ||
|
||
/** | ||
* Configuration for Kryo instance. | ||
* <p> | ||
* Classes of the objects to be cached can be pre-registered if required. Registering in advance is not necessary, | ||
* however it can be done to increase serialization performance. If a class has been pre-registered, the first time | ||
* it is encountered Kryo can just output a numeric reference to it instead of writing fully qualified class name. | ||
*/ | ||
public void configureKryo() { | ||
// setting to false means not requiring registration for all the classes of cached objects in advance | ||
getKryoInstance().setRegistrationRequired(false); | ||
getKryoInstance().setInstantiatorStrategy(new StdInstantiatorStrategy()); | ||
} | ||
|
||
public AerospikeCacheKey serializeAndHash(Object key) { | ||
return calculateHash(serialize(key)); | ||
} | ||
|
||
public byte[] serialize(Object key) { | ||
ByteBufferOutput output = new ByteBufferOutput(1024); // Initial buffer size | ||
kryoInstance.writeClassAndObject(output, key); | ||
output.flush(); | ||
return output.toBytes(); | ||
} | ||
|
||
public AerospikeCacheKey calculateHash(byte[] data) { | ||
return AerospikeCacheKey.of(Arrays.toString(MurmurHash3.hash128(data))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,7 @@ public class AerospikeCacheManager extends AbstractTransactionSupportingCacheMan | |
private final AerospikeConverter aerospikeConverter; | ||
private final AerospikeCacheConfiguration defaultCacheConfiguration; | ||
private final Map<String, AerospikeCacheConfiguration> initialPerCacheConfiguration; | ||
private final AerospikeCacheKeyProcessor cacheKeyProcessor; | ||
|
||
/** | ||
* Create a new {@link AerospikeCacheManager} instance - Specifying a default cache configuration. | ||
|
@@ -55,8 +56,9 @@ public class AerospikeCacheManager extends AbstractTransactionSupportingCacheMan | |
*/ | ||
public AerospikeCacheManager(IAerospikeClient aerospikeClient, | ||
AerospikeConverter aerospikeConverter, | ||
AerospikeCacheConfiguration defaultCacheConfiguration) { | ||
this(aerospikeClient, aerospikeConverter, defaultCacheConfiguration, new LinkedHashMap<>()); | ||
AerospikeCacheConfiguration defaultCacheConfiguration, | ||
AerospikeCacheKeyProcessor cacheKeyProcessor) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding We probably need to update the "Caching with Spring Boot and Aerospike" blog posts: |
||
this(aerospikeClient, aerospikeConverter, defaultCacheConfiguration, new LinkedHashMap<>(), cacheKeyProcessor); | ||
} | ||
|
||
/** | ||
|
@@ -71,7 +73,8 @@ public AerospikeCacheManager(IAerospikeClient aerospikeClient, | |
public AerospikeCacheManager(IAerospikeClient aerospikeClient, | ||
AerospikeConverter aerospikeConverter, | ||
AerospikeCacheConfiguration defaultCacheConfiguration, | ||
Map<String, AerospikeCacheConfiguration> initialPerCacheConfiguration) { | ||
Map<String, AerospikeCacheConfiguration> initialPerCacheConfiguration, | ||
AerospikeCacheKeyProcessor cacheKeyProcessor) { | ||
Assert.notNull(aerospikeClient, "The aerospike client must not be null"); | ||
Assert.notNull(aerospikeConverter, "The aerospike converter must not be null"); | ||
Assert.notNull(defaultCacheConfiguration, "The default cache configuration must not be null"); | ||
|
@@ -80,6 +83,7 @@ public AerospikeCacheManager(IAerospikeClient aerospikeClient, | |
this.aerospikeConverter = aerospikeConverter; | ||
this.defaultCacheConfiguration = defaultCacheConfiguration; | ||
this.initialPerCacheConfiguration = initialPerCacheConfiguration; | ||
this.cacheKeyProcessor = cacheKeyProcessor; | ||
} | ||
|
||
@Override | ||
|
@@ -105,11 +109,12 @@ protected Cache decorateCache(Cache cache) { | |
} | ||
|
||
private AerospikeCache createCache(String name) { | ||
return new AerospikeCache(name, aerospikeClient, aerospikeConverter, defaultCacheConfiguration); | ||
return new AerospikeCache(name, aerospikeClient, aerospikeConverter, defaultCacheConfiguration, | ||
cacheKeyProcessor); | ||
} | ||
|
||
private AerospikeCache createCache(String name, AerospikeCacheConfiguration cacheConfiguration) { | ||
return new AerospikeCache(name, aerospikeClient, aerospikeConverter, cacheConfiguration); | ||
return new AerospikeCache(name, aerospikeClient, aerospikeConverter, cacheConfiguration, cacheKeyProcessor); | ||
} | ||
|
||
private boolean isCacheAlreadyDecorated(Cache cache) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only
String
andlong
? if the purpose is to align with Aerospike supported PK types - "blob" (byte[]
) should be supported as well: https://aerospike.com/docs/reference/limitationsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a wrapper class that receives hash of the cache key. However, we can also support byte array, added it