Skip to content

Commit

Permalink
Merge pull request #107 from Netflix/feature/ascii_meta_arith_basics
Browse files Browse the repository at this point in the history
Adding a basic Meta arithmetic implementation to support incr/decr operations via ASCII
  • Loading branch information
tharanga authored May 4, 2021
2 parents d67511c + fcaad7d commit c70c69b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
10 changes: 8 additions & 2 deletions evcache-client/test/com/netflix/evcache/test/EVCacheTestDI.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
import java.util.concurrent.TimeUnit;

import com.netflix.evcache.*;
import com.netflix.evcache.operation.EVCacheItem;
import com.netflix.evcache.operation.EVCacheItemMetaData;
import com.netflix.evcache.pool.EVCacheClient;
import com.netflix.evcache.pool.ServerGroup;
import com.netflix.evcache.util.KeyHasher;
Expand Down Expand Up @@ -57,6 +55,7 @@ public EVCacheTestDI() {
propertiesToSet.putIfAbsent(appName + ".throttle.percent", "0");
propertiesToSet.putIfAbsent(appName + ".log.operation", "1000");
propertiesToSet.putIfAbsent(appName + ".EVCacheClientPool.validate.input.queue", "true");
propertiesToSet.putIfAbsent("evcache.use.binary.protocol", "false");
}

protected Properties getProps() {
Expand Down Expand Up @@ -419,6 +418,13 @@ private void doFunctionalTests(boolean isHashingEnabled) throws Exception {
latch = evCache.delete(key5, EVCacheLatch.Policy.ALL);
latch.await(1000, TimeUnit.MILLISECONDS);

// test expiry
String key6 = Long.toString(System.currentTimeMillis());
assertEquals(evCache.incr(key6, 1, 10, 5), 10);
Thread.sleep(5000);
assertNull(evCache.get(key6));


assertNull(evCache.get(key1));
assertNull(evCache.get(key2));
assertNull(evCache.get(key3));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import net.spy.memcached.protocol.ascii.MetaDebugOperationImpl;
import net.spy.memcached.protocol.ascii.MetaGetOperation;
import net.spy.memcached.protocol.ascii.MetaGetOperationImpl;
import net.spy.memcached.protocol.ascii.MetaArithmeticOperationImpl;
import net.spy.memcached.ops.Mutator;
import net.spy.memcached.ops.MutatorOperation;
import net.spy.memcached.ops.OperationCallback;


public class EVCacheAsciiOperationFactory extends AsciiOperationFactory {

Expand All @@ -23,5 +28,9 @@ public ExecCmdOperation execCmd(String cmd, ExecCmdOperation.Callback cb) {
return new ExecCmdOperationImpl(cmd, cb);
}

public MutatorOperation mutate(Mutator m, String key, long by, long def,
int exp, OperationCallback cb) {
return new MetaArithmeticOperationImpl(m, key, by, def, exp, cb);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package net.spy.memcached.protocol.ascii;

import net.spy.memcached.KeyUtil;
import net.spy.memcached.ops.Mutator;
import net.spy.memcached.ops.MutatorOperation;
import net.spy.memcached.ops.OperationCallback;
import net.spy.memcached.ops.OperationStatus;
import net.spy.memcached.ops.OperationState;
import net.spy.memcached.ops.StatusCode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;

/**
* Operation for Meta Arithmetic commands of memcached.
*/
public class MetaArithmeticOperationImpl extends EVCacheOperationImpl implements
MutatorOperation {

private static final Logger log = LoggerFactory.getLogger(MetaArithmeticOperationImpl.class);
private static final OperationStatus NOT_FOUND = new OperationStatus(false,
"NOT_FOUND", StatusCode.ERR_NOT_FOUND);

// TODO : Move to a Builder as we expand this to support better isolation guarantees
// Request
private static final String META_ARITHMETIC_OP = "ma";
private static final String AUTO_CREATE = "N%d";
private static final String MUTATOR_MODE ="M%c";
private static final char INCR = '+';
private static final char DECR = '-';
private static final String DEFAULT = "J%d";
private static final String DELTA = "D%d";
private static final char FLAG_VALUE = 'v';
// Response
private static final String VALUE_RETURN = "VA";


private final Mutator mutator;
private final String key;
private final long amount;
private final long def;
private final int exp;
private boolean readingValue;
public static final int OVERHEAD = 32;

public MetaArithmeticOperationImpl(Mutator m, String k, long amt, long defaultVal,
int expiry, OperationCallback c) {
super(c);
mutator = m;
key = k;
amount = amt;
def = defaultVal;
exp = expiry;
readingValue = false;
}

@Override
public void handleLine(String line) {
log.debug("Result: %s", line);
OperationStatus found = null;
if (line.startsWith(VALUE_RETURN)) {
// TODO : We may need to tokenize this when more flags are supplied to the request.
this.readingValue = true;
// Ask state machine to read the next line which has the response
this.setReadType(OperationReadType.LINE);
return;
} else if (readingValue) {
// TODO : Tokenize if multiple values are in this line, as of now, it's just the result.
found = new OperationStatus(true, line, StatusCode.SUCCESS);
} else {
// TODO: Other NF/NS/EX and also OK are treated as errors, this will change as we extend the meta API
found = NOT_FOUND;
}
getCallback().receivedStatus(found);
transitionState(OperationState.COMPLETE);
}

@Override
public void initialize() {
int size = KeyUtil.getKeyBytes(key).length + OVERHEAD;
ByteBuffer b = ByteBuffer.allocate(size);

setArguments(b, META_ARITHMETIC_OP, key, String.format(AUTO_CREATE, exp),
String.format(MUTATOR_MODE, (mutator == Mutator.incr ? INCR : DECR)),
String.format(DEFAULT,def), String.format(DELTA,amount), FLAG_VALUE);
b.flip();
setBuffer(b);
}

public Collection<String> getKeys() {
return Collections.singleton(key);
}

public long getBy() {
return amount;
}

public long getDefault() {
return def;
}

public int getExpiration() {
return exp;
}

public Mutator getType() {
return mutator;
}

@Override
public String toString() {
return "Cmd: " + mutator.name() + " Key: " + key + " Amount: " + amount +
" Default: " + def + " Expiry: " + exp;
}
}

0 comments on commit c70c69b

Please sign in to comment.