package org.solbase.cache;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.UUID;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.transcoders.SerializingTranscoder;
import net.rubyeye.xmemcached.utils.AddrUtil;
public class MemcacheCache<K, V, Z> extends VersionedCache<K, V, Z> {
/*
* static Process memcacheProcess; static { try { memcacheProcess =
* Runtime.getRuntime().exec("/opt/local/bin/memcached"); Thread
* closeChildThread = new Thread() { public void run() {
* memcacheProcess.destroy(); } };
*
* Runtime.getRuntime().addShutdownHook(closeChildThread);
*
* } catch (IOException e) { e.printStackTrace(); } }
*/
private static final int memcacheSize = (1024 * 1024) - 1024;
private MemcachedClient memcachedClient = null;
public MemcacheCache() {
this(null, null);
}
public MemcacheCache(String hostName, Integer port) {
String memcacheHostName;
String memcachePort;
if (hostName == null) {
memcacheHostName = System.getProperty("solbase.memcache.hostname");
if (memcacheHostName == null && ResourceBundle.getBundle("solbase") != null) {
memcacheHostName = ResourceBundle.getBundle("solbase").getString("memcache.hostname");
}
if (memcacheHostName == null) {
memcacheHostName = "localhost";
}
} else {
memcacheHostName = hostName;
}
if (hostName == null) {
memcachePort = System.getProperty("solbase.memcache.port");
if (memcachePort == null && ResourceBundle.getBundle("solbase") != null) {
memcachePort = ResourceBundle.getBundle("solbase").getString("memcache.port");
}
if (memcachePort == null) {
memcachePort = "11211";
}
} else {
memcachePort = port.toString();
}
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(memcacheHostName + ":" + memcachePort));
builder.setCommandFactory(new BinaryCommandFactory());
builder.setConnectionPoolSize(100);
try {
memcachedClient = builder.build();
memcachedClient.setOpTimeout(30000);
SerializingTranscoder st = new SerializingTranscoder(memcacheSize);
memcachedClient.setTranscoder(st);
} catch (Exception e) {
e.printStackTrace();
}
}
public void resetCacheTime(K key, Long time) throws IOException {
MemcacheCachedObjectWrapper<V, Z> value = getInternal(key);
value.setCacheTime(time);
try {
memcachedClient.set(key.toString() + key.getClass().getName().hashCode(), 0, value);
} catch (Exception ex) {
throw new IOException(ex);
}
}
protected MemcacheCachedObjectWrapper<V, Z> getInternal(K key) throws IOException {
try {
MemcacheCachedObjectWrapper<V, Z> tmp = memcachedClient.get(key.toString() + key.getClass().getName().hashCode());
if (tmp != null) {
if (tmp.getUuids() == null) {
tmp.setValue(deserialize(tmp.getValueBytes()));
tmp.setValueBytes(null);
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream(tmp.getUuids().size() * memcacheSize);
Map<String, byte[]> results = memcachedClient.get(tmp.getUuids());
for (String uuid : tmp.getUuids()) {
byte[] tmpBytes = results.get(uuid);
if (tmpBytes == null) {// part is missing, clean it all
// up
memcachedClient.delete(key.toString() + key.getClass().getName().hashCode());
for (String uuidToRemove : tmp.getUuids()) {
memcachedClient.delete(uuidToRemove);
return null;
}
}
baos.write(tmpBytes);
}
tmp.setValue(deserialize(decompress(baos.toByteArray())));
}
}
return tmp;
} catch (Exception ex) {
throw new IOException(ex);
}
}
public void put(K key, CachedObjectWrapper<V, Z> aValue) throws IOException {
try {
MemcacheCachedObjectWrapper<V, Z> value = new MemcacheCachedObjectWrapper<V, Z>(aValue.getValue(), aValue.getVersionIdentifier(), aValue.getCacheTime());
byte[] serializedBytes = serialize(value.getValue());
if (serializedBytes.length > ((memcacheSize) - 1000)) {
ArrayList<String> uuids = new ArrayList<String>(serializedBytes.length / memcacheSize);
ByteBuffer bb = ByteBuffer.wrap(compress(serializedBytes));
int remaining = 0;
while ((remaining = bb.remaining()) > 0) {
byte[] chunk = new byte[remaining < memcacheSize ? remaining : memcacheSize];
bb.get(chunk);
String uuid = UUID.randomUUID().toString();
uuids.add(uuid);
memcachedClient.set(uuid, 0, chunk);
}
value.setUuids(uuids);
} else {
value.setValueBytes(serializedBytes);
}
value.setValue(null);
memcachedClient.set(key.toString() + key.getClass().getName().hashCode(), 0, value);
} catch (Exception ex) {
throw new IOException(ex);
}
}
public void clear() throws IOException {
try {
memcachedClient.flushAll();
} catch (Exception ex) {
throw new IOException(ex);
}
}
}