layout | title | categories | parent | weight |
---|---|---|---|---|
post |
Cache Interface |
SBP |
data-access-patterns.html |
100 |
{% summary page %}This pattern explains how to implement a cache interface using the Map API.{% endsummary %}
{% tip %}
Author: Shay Hassidim
Recently tested with GigaSpaces version: XAP 9.6
Last Update: Feb 2014
{% toc minLevel=1|maxLevel=1|type=flat|separator=pipe %} {% endtip %}
GigaSpaces XAP provides a powerful IMDG with advanced data access options. Many times a simple key/value interface required to access the IMDG. The Map API or the GigaSpace API can be used in such a case. A simple wrapper around the GigaSpace API described here exposing a HashMap
interface.
The implementation includes two classes. The Data
class that model the data within the space and the CacheService
class that wraps the GigaSpace
API using standard Map
API (put
,get
, remove
..).
The CacheService
support inserting data using a key/value and also via region/key/value. A region allows you to mark entries with a "tag" that groups these for better management. When constructing a CacheService
you may indicate if you would like to have the data cached also at the client side. In such a case , the client will have a copy of the data maintained for fast data access avoiding any remote calls or serialization activity. Once the client application constructs the CacheService
all cached data will be pre-loaded into the client side. Make sure the client will have sufficient heap size configured (Xmx
) to accommodate all entries.
The Data Space Class holds the key , value and region data within a simple POJO properties. The @SpaceId
annotation indicates the key field specified as the Space class ID field.
{% highlight java %} import com.gigaspaces.annotation.pojo.SpaceId; import com.gigaspaces.annotation.pojo.SpaceIndex;
public class Data { public Data(){}
String key;
Object value;
String region;
@SpaceIndex
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region= region;
}
@SpaceId(autoGenerate=false)
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
{% endhighlight %}
The Data
class can be modified to support better serialization for the value object. You may store the value object in binary format or compressed format.
To store the value object in a binary format the getValue
should have the following:
{% highlight java %}
@SpaceStorageType(storageType=StorageType.BINARY)
public Object getValue() {
return value;
}
{% endhighlight %}
To store the value object in a compressed format the getValue
should have the following:
{% highlight java %}
@SpaceStorageType(storageType=StorageType.COMPRESSED)
public Object getValue() {
return value;
}
{% endhighlight %}
The CacheService
leveraging the GigaSpace
interface implementing the standard put
,get
,putAll
,getAll
,remove
,etc. methods:
{% highlight java %}
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openspaces.core.GigaSpace; import org.openspaces.core.GigaSpaceConfigurer; import org.openspaces.core.space.UrlSpaceConfigurer; import org.openspaces.core.space.cache.LocalViewSpaceConfigurer;
import com.gigaspaces.client.ReadByIdsResult; import com.gigaspaces.query.IdQuery; import com.gigaspaces.query.IdsQuery; import com.j_spaces.core.client.SQLQuery;
public class CacheService { private GigaSpace spaceView; private GigaSpace space; boolean localView;
public CacheService(String url) throws Exception {
init(url, false);
}
public CacheService(String url, boolean clientCache) throws Exception {
init(url, clientCache);
}
public void init(String url, boolean clientCache) throws Exception {
this.localView = clientCache;
UrlSpaceConfigurer urlConfigurer = new UrlSpaceConfigurer(url);
space = new GigaSpaceConfigurer(urlConfigurer).gigaSpace();
if (localView) {
LocalViewSpaceConfigurer localViewConfigurer = new LocalViewSpaceConfigurer(
urlConfigurer).addViewQuery(new SQLQuery<Data>(Data.class,
""));
// Create local view:
spaceView = new GigaSpaceConfigurer(localViewConfigurer)
.gigaSpace();
} else {
spaceView = space;
}
}
public void put(String key, Object value) throws Exception {
put(null, key, value);
}
public void put(String region, String key, Object value) throws Exception {
Data d = new Data();
d.setKey(key);
d.setValue(value);
d.setRegion(region);
space.write(d);
}
public Object get(String region, String key) throws Exception {
Data templ = new Data();
templ.setKey(key);
templ.setRegion(region);
Data d = spaceView.read(templ);
if (d != null)
return d.getValue();
else
return null;
}
public void clear() {
space.clear(new Data());
}
public Object get(String key) throws Exception {
Data d = spaceView.readById(Data.class, key);
if (d != null)
return d.getValue();
else
return null;
}
public void remove(String region, String key) throws Exception {
Data templ = new Data();
templ.setKey(key);
templ.setRegion(region);
space.clear(templ);
}
public void remove(String key) throws Exception {
IdQuery<Data> idquery = new IdQuery<Data>(Data.class, key);
space.clear(idquery);
}
public boolean containsKey(String key) {
IdQuery<Data> idquery = new IdQuery<Data>(Data.class, key);
int count = spaceView.count(idquery);
return (count > 0);
}
public int size() throws Exception {
return spaceView.count(new Data());
}
public int size(String region) throws Exception {
Data templ = new Data();
templ.setRegion(region);
return spaceView.count(templ);
}
public Map<String, Object> getAll(List<String> keys) {
Map<String, Object> map = new HashMap<String, Object>();
String keysArray[] = new String[keys.size()];
keys.toArray(keysArray);
IdsQuery<Data> idsquery = new IdsQuery<Data>(Data.class, keysArray);
ReadByIdsResult<Data> result= spaceView.readByIds(idsquery);
Iterator<Data> iter = result.iterator();
while (iter.hasNext())
{
Data data = iter.next();
map.put(data.getKey(), data.getValue());
}
return map;
}
public void putAll(String region, Map<String, Object> map) {
Data d[] = new Data[map.size()];
int count = 0;
Iterator<String> keys = map.keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
Object val = map.get(key);
d[count] = new Data();
d[count].setKey(key);
d[count].setValue(val);
d[count].setRegion(region);
count++;
}
space.writeMultiple(d);
}
public void putAll(Map<String, Object> map) {
putAll(null, map);
}
public Collection<Object> values() {
SQLQuery<Data> query = null;
Set<Object> values = new HashSet<Object>();
if (localView)
query = new SQLQuery<Data>(Data.class, "");
else
query = new SQLQuery<Data>(Data.class, "").setProjections("value");
Data d[] = spaceView.readMultiple(query);
for (int i = 0; i < d.length; i++) {
values.add(d[i].getValue());
}
return values;
}
public Set<String> keySet() throws Exception {
SQLQuery<Data> query = null;
if (localView)
query = new SQLQuery<Data>(Data.class, "");
else
query = new SQLQuery<Data>(Data.class, "").setProjections("key");
Data d[] = spaceView.readMultiple(query);
Set<String> keys = new HashSet<String>();
for (int i = 0; i < d.length; i++) {
keys.add(d[i].getKey());
}
return keys;
}
}
{% endhighlight %}
See example how the CacheService
can be used accessing IMDG called 'mySpace':
{% highlight java %}
CacheService cacheService = new CacheService("jini////mySpace");
cacheService.put("key1", "value1"); cacheService.put("region1" , "key2", "value2");
cacheService.remove("key1");
cacheService.clear();
Map<String, Object> map = new HashMap<String, Object>(); map.put("key1", "value"); map.put("key2", "value"); map.put("key3", "value"); cacheService.putAll(map); {% endhighlight %}