package voldemort.server.protocol.admin;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import voldemort.client.protocol.pb.VAdminProto.UpdatePartitionEntriesRequest;
import voldemort.server.StoreRepository;
import voldemort.server.VoldemortConfig;
import voldemort.server.storage.KeyLockHandle;
import voldemort.store.ErrorCodeMapper;
import voldemort.store.StorageEngine;
import voldemort.store.metadata.MetadataStore;
import voldemort.utils.ByteArray;
import voldemort.utils.NetworkClassLoader;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Versioned;
/**
* This class implements a streaming interface into a voldemort server, that
* resolves based on timestamp.
*
* Specifically, the policy implemented is "overwrite if later". That is, if
* (and only if), the streamed in version's timestamp is greater than the
* timestamps of ALL" versions on storage, the key is overwritten atomically
* with the streamed version. Else, the key is unmodified.
*
* NOTE: This class does not do any buffering like
* {@link BufferedUpdatePartitionEntriesStreamRequestHandler} since this is
* mainly intended to be used for streaming values in from external sources.
*
*/
public class TimeBasedUpdatePartitionEntriesStreamRequestHandler extends
UpdatePartitionEntriesStreamRequestHandler {
public TimeBasedUpdatePartitionEntriesStreamRequestHandler(UpdatePartitionEntriesRequest request,
ErrorCodeMapper errorCodeMapper,
VoldemortConfig voldemortConfig,
StorageEngine<ByteArray, byte[], byte[]> storageEngine,
StoreRepository storeRepository,
NetworkClassLoader networkClassLoader,
MetadataStore metadataStore) {
super(request,
errorCodeMapper,
voldemortConfig,
storageEngine,
storeRepository,
networkClassLoader,
metadataStore);
}
@Override
protected void processEntry(ByteArray key, Versioned<byte[]> value) throws IOException {
KeyLockHandle<byte[]> handle = null;
try {
handle = storageEngine.getAndLock(key);
// determine if there is a version already with a greater ts.
boolean foundGreaterTs = false;
VectorClock streamedClock = (VectorClock) value.getVersion();
for(Versioned<byte[]> versioned: handle.getValues()) {
VectorClock storedClock = (VectorClock) versioned.getVersion();
if(storedClock.getTimestamp() >= streamedClock.getTimestamp()) {
foundGreaterTs = true;
break;
}
}
if(!foundGreaterTs) {
// if what we are trying to write is the greatest version,
// write it in and let go of lock
List<Versioned<byte[]>> streamedVals = new ArrayList<Versioned<byte[]>>(1);
streamedVals.add(value);
handle.setValues(streamedVals);
storageEngine.putAndUnlock(key, handle);
} else {
// back off and let go of lock, if found a version that is
// greater than what we are trying to write in
storageEngine.releaseLock(handle);
}
} catch(Exception e) {
logger.error("Error in time based update entries", e);
throw new IOException(e);
} finally {
if(handle != null && !handle.isClosed()) {
storageEngine.releaseLock(handle);
}
}
}
@Override
protected String getHandlerName() {
return "TimeBasedUpdateEntries";
}
}