package com.thinkaurelius.titan.diskstorage.hazelcast;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import com.hazelcast.config.ClasspathXmlConfig;
import com.hazelcast.config.Config;
import com.hazelcast.config.FileSystemXmlConfig;
import com.hazelcast.config.SerializerConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.nio.serialization.ByteArraySerializer;
import com.hazelcast.transaction.TransactionContext;
import com.hazelcast.transaction.TransactionOptions;
import com.thinkaurelius.titan.diskstorage.PermanentStorageException;
import com.thinkaurelius.titan.diskstorage.StaticBuffer;
import com.thinkaurelius.titan.diskstorage.StorageException;
import com.thinkaurelius.titan.diskstorage.common.AbstractStoreTransaction;
import com.thinkaurelius.titan.diskstorage.common.LocalStoreManager;
import com.thinkaurelius.titan.diskstorage.common.NoOpStoreTransaction;
import com.thinkaurelius.titan.diskstorage.keycolumnvalue.*;
import com.thinkaurelius.titan.diskstorage.util.StaticArrayBuffer;
import com.thinkaurelius.titan.graphdb.configuration.GraphDatabaseConfiguration;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractHazelcastStoreManager extends LocalStoreManager implements StoreManager {
private static final Logger logger = LoggerFactory.getLogger(AbstractHazelcastStoreManager.class);
public static final String CONFIG_FILE_KEY = "config-file";
public static final String CLASSPATH_FILE_KEY = "config-file";
public static final String CLASSPATH_FILE_DEFAULT = "hazelcast.xml";
protected final HazelcastInstance manager;
protected final StoreFeatures features = getDefaultFeatures();
protected final long lockExpireMS;
public AbstractHazelcastStoreManager(Configuration config) throws StorageException {
super(config);
Config conf;
if (config.containsKey(CONFIG_FILE_KEY)) {
try {
conf = new FileSystemXmlConfig(config.getString(CONFIG_FILE_KEY));
} catch (IOException e) {
throw new PermanentStorageException("Could not load configuration file", e);
}
} else {
conf = new ClasspathXmlConfig(config.getString(CLASSPATH_FILE_KEY, CLASSPATH_FILE_DEFAULT));
}
SerializerConfig sc = new SerializerConfig();
sc.setImplementation(new StaticBufferSerializer()).setTypeClass(StaticBuffer.class);
conf.getSerializationConfig().addSerializerConfig(sc);
manager = Hazelcast.newHazelcastInstance(conf);
lockExpireMS = config.getLong(GraphDatabaseConfiguration.LOCK_EXPIRE_MS,
GraphDatabaseConfiguration.LOCK_EXPIRE_MS_DEFAULT);
if (transactional)
logger.warn("Hazelcast does not support multiple transactions per thread");
}
@Override
public StoreTransaction beginTransaction(StoreTxConfig txConfig) throws StorageException {
if (transactional) {
TransactionOptions txo = new TransactionOptions();
txo.setTimeout(lockExpireMS, TimeUnit.MILLISECONDS);
return new HazelCastTransaction(manager.newTransactionContext(txo), txConfig);
} else {
return new NoOpStoreTransaction(txConfig);
}
}
@Override
public StoreFeatures getFeatures() {
return features;
}
@Override
public String getName() {
return getClass().getSimpleName() + ":" + directory.toString();
}
private StoreFeatures getDefaultFeatures() {
StoreFeatures features = new StoreFeatures();
features.supportsOrderedScan = false;
features.supportsUnorderedScan = true;
features.supportsBatchMutation = false;
features.supportsMultiQuery = false;
features.supportsTransactions = true;
features.supportsConsistentKeyOperations = false;
features.supportsLocking = false;
features.isDistributed = false;
features.isKeyOrdered = false;
features.hasLocalKeyPartition = false;
return features;
}
private static class HazelCastTransaction extends AbstractStoreTransaction {
private final TransactionContext context;
public HazelCastTransaction(TransactionContext context, StoreTxConfig txConfig) {
super(txConfig);
this.context = context;
this.context.beginTransaction();
}
@Override
public void commit() {
context.commitTransaction();
}
@Override
public void rollback() {
context.rollbackTransaction();
}
}
private static class StaticBufferSerializer implements ByteArraySerializer<StaticBuffer> {
@Override
public byte[] write(StaticBuffer o) throws IOException {
return o.as(StaticBuffer.ARRAY_FACTORY);
}
@Override
public StaticBuffer read(byte[] bytes) throws IOException {
return new StaticArrayBuffer(bytes);
}
@Override
public int getTypeId() {
return 1;
}
@Override
public void destroy() {
//Do nothing
}
}
}