package edu.berkeley.thebes.hat.server.antientropy;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import com.google.common.collect.Lists;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Meter;
import edu.berkeley.thebes.hat.common.thrift.DataDependencyRequest;
import edu.berkeley.thebes.hat.server.antientropy.clustering.AntiEntropyServiceRouter;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.berkeley.thebes.common.config.ConfigParameterTypes.PersistenceEngine;
import edu.berkeley.thebes.common.data.DataItem;
import edu.berkeley.thebes.common.data.Version;
import edu.berkeley.thebes.common.persistence.IPersistenceEngine;
import edu.berkeley.thebes.common.thrift.ThriftDataItem;
import edu.berkeley.thebes.common.thrift.ThriftVersion;
import edu.berkeley.thebes.hat.common.data.DataDependency;
import edu.berkeley.thebes.hat.common.thrift.AntiEntropyService;
import edu.berkeley.thebes.hat.server.dependencies.DependencyResolver;
import org.xerial.snappy.Snappy;
public class AntiEntropyServiceHandler implements AntiEntropyService.Iface {
private static Logger logger = LoggerFactory.getLogger(AntiEntropyServiceHandler.class);
DependencyResolver dependencyResolver;
AntiEntropyServiceRouter router;
IPersistenceEngine persistenceEngine;
Meter putRequests = Metrics.newMeter(AntiEntropyServiceHandler.class,
"put-requests",
"requests",
TimeUnit.SECONDS);
Meter ackTransactionPending = Metrics.newMeter(AntiEntropyServiceHandler.class,
"ack-transaction-pending-requests",
"requests",
TimeUnit.SECONDS);
public AntiEntropyServiceHandler(AntiEntropyServiceRouter router,
DependencyResolver dependencyResolver, IPersistenceEngine persistenceEngine) {
this.dependencyResolver = dependencyResolver;
this.router = router;
this.persistenceEngine = persistenceEngine;
}
@Override
public void put(List<String> keys,
List<ThriftDataItem> values) throws TException{
putRequests.mark();
for (int i = 0; i < keys.size(); i ++) {
String key = keys.get(i);
DataItem value = new DataItem(values.get(i));
logger.trace("Received anti-entropy put for key " + key);
if (value.getTransactionKeys() == null || value.getTransactionKeys().isEmpty()) {
persistenceEngine.put_if_newer(key, value);
} else {
dependencyResolver.addPendingWrite(key, value);
}
}
}
@Override
public void ackTransactionPending(ByteBuffer transactionIdList) throws TException {
ackTransactionPending.mark();
List<Version> transactionVersions = Lists.newArrayList();
try {
byte[] uncompressedList = Snappy.uncompress(transactionIdList.array());
ByteArrayInputStream bis = new ByteArrayInputStream(uncompressedList);
DataInputStream dis = new DataInputStream(bis);
while(bis.available() > 0) {
transactionVersions.add(Version.fromLong(dis.readLong()));
}
} catch (IOException e) {
logger.error("Error in deserialization", e);
}
for (Version transactionId : transactionVersions) {
dependencyResolver.ackTransactionPending(transactionId);
}
}
}