Permalink
Browse files

Implement TOUCH command

Change-Id: I1c1dce9e64273cb34f755bef7a5a0a77e6bf9eb1
Reviewed-on: http://review.couchbase.org/11985
Tested-by: Sergey Avseyev <sergey.avseyev@gmail.com>
Reviewed-by: Trond Norbye <trond.norbye@gmail.com>
  • Loading branch information...
1 parent 9e5a083 commit 1f2d5ae7b70be6f73f0161162f369f1e7c7e9e82 @avsej avsej committed with trondn Dec 30, 2011
@@ -17,6 +17,7 @@
import org.couchbase.mock.memcached.protocol.ErrorCode;
import java.security.AccessControlException;
+import java.util.Date;
import java.util.Map;
import org.couchbase.mock.Bucket.BucketType;
@@ -62,7 +63,8 @@ public void setOwnership(int vbucket, MemcachedServer server) {
public ErrorCode add(MemcachedServer server, short vBucketId, Item item) {
// I don't give a shit about atomicy right now..
Map<String, Item> map = getMap(server, vBucketId);
- if (map.get(item.getKey()) != null || item.getCas() != 0) {
+ Item old = lookup(map, item.getKey());
+ if (old != null || item.getCas() != 0) {
return ErrorCode.KEY_EEXISTS;
}
@@ -74,7 +76,7 @@ public ErrorCode add(MemcachedServer server, short vBucketId, Item item) {
public ErrorCode replace(MemcachedServer server, short vBucketId, Item item) {
// I don't give a shit about atomicy right now..
Map<String, Item> map = getMap(server, vBucketId);
- Item old = map.get(item.getKey());
+ Item old = lookup(map, item.getKey());
if (old == null) {
return ErrorCode.KEY_ENOENT;
}
@@ -103,7 +105,7 @@ public ErrorCode set(MemcachedServer server, short vBucketId, Item item) {
ErrorCode delete(MemcachedServer server, short vBucketId, String key, long cas) {
// I don't give a shit about atomicy right now..
Map<String, Item> map = getMap(server, vBucketId);
- Item i = map.get(key);
+ Item i = lookup(map, key);
if (i == null) {
return ErrorCode.KEY_ENOENT;
}
@@ -116,12 +118,25 @@ ErrorCode delete(MemcachedServer server, short vBucketId, String key, long cas)
Item get(MemcachedServer server, short vBucketId, String key) {
Map<String, Item> map = getMap(server, vBucketId);
- return map.get(key);
+ return lookup(map, key);
}
void flush(MemcachedServer server) {
for (VBucket b : vBucketMap) {
b.flush(server);
}
}
+
+ private Item lookup(Map<String, Item> map, String key) {
+ Item ii = map.get(key);
+ if (ii != null) {
+ long now = new Date().getTime();
+ if (ii.getExptime() == 0 || (now - ii.getMtime() < ii.getExptimeInMillis())) {
+ return ii;
+ } else {
+ map.remove(key);
+ }
+ }
+ return null;
+ }
}
@@ -19,6 +19,7 @@
import org.couchbase.mock.memcached.protocol.ComCode;
import org.couchbase.mock.memcached.protocol.ErrorCode;
import org.couchbase.mock.memcached.protocol.BinaryCommand;
+import org.couchbase.mock.memcached.protocol.BinaryGetCommand;
import org.couchbase.mock.memcached.protocol.BinaryGetResponse;
/**
@@ -28,14 +29,25 @@
public class GetCommandExecutor implements CommandExecutor {
@Override
- public void execute(BinaryCommand cmd, MemcachedServer server, MemcachedConnection client) {
- Item item = server.getDatastore().get(server, cmd.getVBucketId(), cmd.getKey());
+ public void execute(BinaryCommand command, MemcachedServer server, MemcachedConnection client) {
+ BinaryGetCommand cmd = (BinaryGetCommand) command;
+ DataStore datastore = server.getDatastore();
+ Item item = datastore.get(server, cmd.getVBucketId(), cmd.getKey());
+ ComCode cc = cmd.getComCode();
+
if (item == null) {
- if (cmd.getComCode() != ComCode.GETKQ && cmd.getComCode() != ComCode.GETQ) {
+ if (cc != ComCode.GETKQ && cc != ComCode.GETQ && cc != ComCode.GATQ) {
client.sendResponse(new BinaryGetResponse(cmd, ErrorCode.KEY_ENOENT));
}
} else {
- client.sendResponse(new BinaryGetResponse(cmd, item));
+ if (cc == ComCode.TOUCH || cc == ComCode.GAT || cc == ComCode.GATQ) {
+ item.setExptime(cmd.getExpiration());
+ }
+ if (cc == ComCode.TOUCH) {
+ client.sendResponse(new BinaryGetResponse(cmd, ErrorCode.SUCCESS));
+ } else {
+ client.sendResponse(new BinaryGetResponse(cmd, item));
+ }
}
}
}
@@ -16,6 +16,8 @@
package org.couchbase.mock.memcached;
+import java.util.Date;
+
/**
*
* @author Trond Norbye
@@ -26,6 +28,7 @@
private int exptime;
private byte[] value;
private long cas;
+ private long mtime;
public Item(String key, int flags, int exptime, byte[] value, long cas) {
this.key = key;
@@ -39,6 +42,18 @@ public int getExptime() {
return exptime;
}
+ public int getExptimeInMillis() {
+ return exptime * 1000;
+ }
+
+ public void setExptime(int e) {
+ exptime = e;
+ }
+
+ public long getMtime() {
+ return mtime;
+ }
+
public int getFlags() {
return flags;
}
@@ -56,6 +71,7 @@ public long getCas() {
}
void setCas(long l) {
+ mtime = new Date().getTime();
cas = l;
}
@@ -109,6 +109,9 @@ public MemcachedServer(BucketType type, String hostname, int port, DataStore dat
executors[ComCode.GETQ.cc()] = executors[ComCode.GET.cc()];
executors[ComCode.GETK.cc()] = executors[ComCode.GET.cc()];
executors[ComCode.GETKQ.cc()] = executors[ComCode.GET.cc()];
+ executors[ComCode.TOUCH.cc()] = executors[ComCode.GET.cc()];
+ executors[ComCode.GAT.cc()] = executors[ComCode.GET.cc()];
+ executors[ComCode.GATQ.cc()] = executors[ComCode.GET.cc()];
executors[ComCode.INCREMENT.cc()] = new ArithmeticCommandExecutor();
executors[ComCode.INCREMENTQ.cc()] = executors[ComCode.INCREMENT.cc()];
executors[ComCode.DECREMENT.cc()] = executors[ComCode.INCREMENT.cc()];
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Couchbase, Inc..
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+package org.couchbase.mock.memcached.protocol;
+
+import java.net.ProtocolException;
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Sergey Avseyev <sergey.avseyev@gmail.com>
+ */
+public class BinaryGetCommand extends BinaryCommand {
+
+ public BinaryGetCommand(ByteBuffer header) throws ProtocolException {
+ super(header);
+ }
+
+ public int getExpiration() {
+ return bodyBuffer.getInt(0);
+ }
+}
@@ -20,19 +20,23 @@
* @author Trond Norbye
*/
public enum ComCode {
- GET(0x00), SET(0x01), ADD(0x02), REPLACE(0x03), DELETE(0x04), INCREMENT(
- 0x05), DECREMENT(0x06), QUIT(0x07), FLUSH(0x08), GETQ(0x09), NOOP(
- 0x0a), VERSION(0x0b), GETK(0x0c), GETKQ(0x0d), APPEND(0x0e), PREPEND(
- 0x0f), STAT(0x10), SETQ(0x11), ADDQ(0x12), REPLACEQ(0x13), DELETEQ(
- 0x14), INCREMENTQ(0x15), DECREMENTQ(0x16), QUITQ(0x17), FLUSHQ(0x18), APPENDQ(
- 0x19), PREPENDQ(0x1a), VERBOSITY(0x1b), SASL_LIST_MECHS(0x20),
- SASL_AUTH(0x21), SASL_STEP(0x22), RGET(0x30), RSET(0x31), RSETQ(0x32),
- RAPPEND(0x33), RAPPENDQ(0x34), RPREPEND(0x35), RPREPENDQ(0x36),
- RDELETE(0x37), RDELETEQ (0x38), RINCR(0x39), RINCRQ(0x3a), RDECR(0x3b),
- RDECRQ(0x3c), SET_VBUCKET(0x3d), GET_VBUCKET(0x3e), DEL_VBUCKET(0x3f),
- TAP_CONNECT(0x40), TAP_MUTATION(0x41), TAP_DELETE(0x42), TAP_FLUSH(0x43),
- TAP_OPAQUE(0x44), TAP_VBUCKET_SET(0x45), LAST_RESERVED(0xef),
- SCRUB(0xf0), ILLEGAL(0xff);
+ GET(0x00), SET(0x01), ADD(0x02), REPLACE(0x03),
+ DELETE(0x04), INCREMENT(0x05), DECREMENT(0x06), QUIT(0x07),
+ FLUSH(0x08), GETQ(0x09), NOOP(0x0a), VERSION(0x0b),
+ GETK(0x0c), GETKQ(0x0d), APPEND(0x0e), PREPEND(0x0f),
+ STAT(0x10), SETQ(0x11), ADDQ(0x12), REPLACEQ(0x13),
+ DELETEQ(0x14), INCREMENTQ(0x15), DECREMENTQ(0x16), QUITQ(0x17),
+ FLUSHQ(0x18), APPENDQ(0x19), PREPENDQ(0x1a), VERBOSITY(0x1b),
+ TOUCH(0x1c), GAT(0x1d), GATQ(0x1e), SASL_LIST_MECHS(0x20),
+ SASL_AUTH(0x21), SASL_STEP(0x22), RGET(0x30), RSET(0x31),
+ RSETQ(0x32), RAPPEND(0x33), RAPPENDQ(0x34), RPREPEND(0x35),
+ RPREPENDQ(0x36), RDELETE(0x37), RDELETEQ (0x38), RINCR(0x39),
+ RINCRQ(0x3a), RDECR(0x3b), RDECRQ(0x3c), SET_VBUCKET(0x3d),
+ GET_VBUCKET(0x3e), DEL_VBUCKET(0x3f), TAP_CONNECT(0x40), TAP_MUTATION(0x41),
+ TAP_DELETE(0x42), TAP_FLUSH(0x43), TAP_OPAQUE(0x44), TAP_VBUCKET_SET(0x45),
+ LAST_RESERVED(0xef), SCRUB(0xf0), ILLEGAL(0xff);
+
+
private final byte value;
@@ -100,6 +104,12 @@ static ComCode valueOf(byte cc) {
return APPENDQ;
case 0x1a:
return PREPENDQ;
+ case 0x1c:
+ return TOUCH;
+ case 0x1d:
+ return GAT;
+ case 0x1e:
+ return GATQ;
case 0x20:
return SASL_LIST_MECHS;
case 0x21:
@@ -175,6 +185,12 @@ static String toString(ComCode cc) {
return "sasl_auth";
case SASL_STEP:
return "sasl_step";
+ case TOUCH:
+ return "touch";
+ case GAT:
+ return "gat";
+ case GATQ:
+ return "gatq";
default:
return "unknown";
@@ -53,6 +53,15 @@ public static BinaryCommand create(ByteBuffer header) throws ProtocolException {
case DECREMENTQ:
return new BinaryArithmeticCommand(header);
+ case GET:
+ case GETQ:
+ case GETK:
+ case GETKQ:
+ case GAT:
+ case GATQ:
+ case TOUCH:
+ return new BinaryGetCommand(header);
+
default:
return new BinaryCommand(header);
}

0 comments on commit 1f2d5ae

Please sign in to comment.