Skip to content

Commit 4a8f129

Browse files
committed
KeyValueMap struct cache
1 parent 70e2715 commit 4a8f129

2 files changed

Lines changed: 153 additions & 23 deletions

File tree

src/main/java/picoded/dstack/struct/cache/StructCache_KeyValueMap.java

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
package picoded.dstack.struct.cache;
22

3+
import java.io.Serializable;
34
// Java imports
45
import java.util.HashSet;
56
import java.util.Set;
67
import java.util.Map;
78
import java.util.concurrent.ConcurrentHashMap;
8-
import java.util.concurrent.ConcurrentMap;
9-
import java.util.concurrent.locks.ReentrantReadWriteLock;
109

1110
// Picoded imports
12-
import picoded.dstack.KeyValueMap;
1311
import picoded.dstack.core.Core_KeyValueMap;
14-
import picoded.core.struct.GenericConvertMap;
1512
import picoded.core.struct.MutablePair;
16-
import picoded.core.struct.GenericConvertHashMap;
1713

1814
// Cache2k implmentation
1915
import org.cache2k.Cache2kBuilder;
@@ -54,11 +50,28 @@ public StructCache_KeyValueMap(String name) {
5450
//
5551
//--------------------------------------------------------------------------
5652

53+
/**
54+
* Serializable class for storing value, expire pairs
55+
* We use this because cache2k requires Serializable values
56+
*/
57+
static public class CacheValue implements Serializable {
58+
private static final long serialVersionUID = 1L;
59+
public String value;
60+
public long expire;
61+
}
62+
63+
static CacheValue cacheValueBuilder(String val, long exp) {
64+
CacheValue ret = new CacheValue();
65+
ret.value = val;
66+
ret.expire = exp;
67+
return ret;
68+
}
69+
5770
/**
5871
* Global static cache map,
5972
* Used to persist all the various cache maps used.
6073
*/
61-
protected volatile static Map<String, Cache<String, String>> globalCacheMap = new ConcurrentHashMap<String, Cache<String, String>>();
74+
protected volatile static Map<String, Cache<String, CacheValue>> globalCacheMap = new ConcurrentHashMap<String, Cache<String, CacheValue>>();
6275

6376
//--------------------------------------------------------------------------
6477
//
@@ -93,12 +106,12 @@ private String cacheName() {
93106
/**
94107
* @return The current cache namespace object
95108
**/
96-
protected Cache<String, String> _valueMap = null;
109+
protected Cache<String, CacheValue> _valueMap = null;
97110

98111
/**
99112
* @return Get the cachemap from global namespace by name
100113
*/
101-
private Cache<String, String> valueMap() {
114+
private Cache<String, CacheValue> valueMap() {
102115
// Return the value map if already initialized
103116
if (_valueMap != null) {
104117
return _valueMap;
@@ -116,14 +129,6 @@ private Cache<String, String> valueMap() {
116129
return _valueMap;
117130
}
118131

119-
/**
120-
* @return Storage map used for the backend operations of one "DataObjectMap"
121-
* identical to valueMap, made to be compliant with Core_DataObjectMap_struct
122-
*/
123-
protected Map<String, String> backendMap() {
124-
return valueMap().asMap();
125-
}
126-
127132
//--------------------------------------------------------------------------
128133
//
129134
// Backend system setup / teardown / maintenance (DStackCommon)
@@ -153,7 +158,9 @@ public void systemSetup() {
153158
}
154159

155160
// Build the cache
156-
_valueMap = StructCacheUtil.setupCache2kMap(new Cache2kBuilder<String, String>(){}, cacheName(), configMap());
161+
Cache2kBuilder<String, CacheValue> builder = new Cache2kBuilder<String, CacheValue>(){};
162+
builder.storeByReference(true);
163+
_valueMap = StructCacheUtil.setupCache2kMap(builder, cacheName(), configMap());
157164

158165
// Add it back to the global cache
159166
globalCacheMap.put(cacheName(), _valueMap);
@@ -183,22 +190,84 @@ public void maintenance() {
183190
//
184191
//--------------------------------------------------------------------------
185192

193+
/**
194+
* [Internal use, to be extended in future implementation]
195+
* Sets the value, with validation
196+
*
197+
* @param key
198+
* @param value, null means removal
199+
* @param expire TIMESTAMP, 0 means no timestamp
200+
*
201+
* @return null
202+
**/
186203
@Override
187204
public String setValueRaw(String key, String value, long expire) {
188-
// TODO Auto-generated method stub
205+
// Handles null removal
206+
if( value == null ) {
207+
valueMap().remove(key);
208+
return null;
209+
}
210+
211+
// Store and configure expiry
212+
valueMap().put(key, cacheValueBuilder(value, expire));
213+
if( expire > 0 ) {
214+
// Note that cache expiry config, may take priority
215+
// so this should not be relied on in itself
216+
valueMap().expireAt(key, expire);
217+
}
189218
return null;
190219
}
191220

221+
/**
222+
* [Internal use, to be extended in future implementation]
223+
* Sets the expire time stamp value, raw without validation
224+
*
225+
* @param key as String
226+
* @param expire TIMESTAMP in milliseconds, 0 means NO expire
227+
*
228+
* @return
229+
**/
192230
@Override
193231
public void setExpiryRaw(String key, long time) {
194-
// TODO Auto-generated method stub
232+
CacheValue cv = valueMap().get(key);
233+
if( cv == null ) {
234+
// Does nothing if cv == null
235+
return;
236+
}
237+
238+
// Set the actual expire value
239+
cv.expire = time;
195240

241+
// Configure cache2k expire values
242+
if( time > 0 ) {
243+
// Note that cache expiry config, may take priority
244+
// so this should not be relied on in itself
245+
valueMap().expireAt(key, time);
246+
}
196247
}
197248

249+
/**
250+
* [Internal use, to be extended in future implementation]
251+
*
252+
* Returns the value and expiry, with validation against the current timestamp
253+
*
254+
* @param key as String
255+
* @param now timestamp, 0 = no timestamp so skip timestamp checks
256+
*
257+
* @return String value, and expiry pair
258+
**/
198259
@Override
199260
public MutablePair<String, Long> getValueExpiryRaw(String key, long now) {
200-
// TODO Auto-generated method stub
201-
return null;
261+
CacheValue cv = valueMap().get(key);
262+
if( cv == null ) {
263+
// Does nothing if cv == null
264+
return null;
265+
}
266+
if( cv.expire > 0 && cv.expire <= System.currentTimeMillis() ) {
267+
// Value should be expired, does nothing
268+
return null;
269+
}
270+
return new MutablePair<String,Long>(cv.value, cv.expire);
202271
}
203272

204273
//--------------------------------------------------------------------------
@@ -209,8 +278,34 @@ public MutablePair<String, Long> getValueExpiryRaw(String key, long now) {
209278

210279
@Override
211280
public Set<String> keySet(String value) {
212-
// TODO Auto-generated method stub
213-
return null;
281+
// Optimized for all
282+
if( value == null ) {
283+
return valueMap().asMap().keySet();
284+
}
285+
286+
// We have to do a search
287+
Set<String> full = valueMap().asMap().keySet();
288+
Set<String> ret = new HashSet<>();
289+
long now = System.currentTimeMillis();
290+
291+
// Lets iterate each key
292+
for(String key : full) {
293+
CacheValue cv = valueMap().get(key);
294+
if( cv == null ) {
295+
// Does nothing if cv == null
296+
continue;
297+
}
298+
if( cv.expire > 0 && cv.expire <= now ) {
299+
// Value should be expired, does nothing
300+
continue;
301+
}
302+
if( cv.value == value ) {
303+
ret.add(key);
304+
}
305+
}
306+
307+
// Return the filtered set
308+
return ret;
214309
}
215310

216311
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package picoded.dstack.struct.cache;
2+
3+
// Target test class
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertFalse;
6+
import static org.junit.Assert.assertNotNull;
7+
import static org.junit.Assert.assertNull;
8+
import static org.junit.Assert.assertTrue;
9+
10+
import java.util.Arrays;
11+
import java.util.HashSet;
12+
13+
// Test Case include
14+
import org.junit.After;
15+
import org.junit.Before;
16+
import org.junit.Test;
17+
18+
// Test depends
19+
import picoded.dstack.*;
20+
import picoded.dstack.jsql.*;
21+
import picoded.dstack.struct.simple.*;
22+
23+
public class StructCache_KeyValueMap_test extends StructSimple_KeyValueMap_test {
24+
25+
// To override for implementation
26+
//-----------------------------------------------------
27+
28+
/// Impomentation constructor
29+
public KeyValueMap implementationConstructor() {
30+
StructCache_KeyValueMap map = new StructCache_KeyValueMap();
31+
map.configMap().put("name", JSqlTestConfig.randomTablePrefix());
32+
return map;
33+
}
34+
35+
}

0 commit comments

Comments
 (0)