Permalink
Browse files

Refactor the packet handling

Instead of having a large switch we should be using a lookup table
to map the com code to the different command handler.

Change-Id: I5bb39de04df0f073ae7e2ff8e64894601d2b44f5
Reviewed-on: http://review.couchbase.org/8871
Reviewed-by: Michael Wiederhold <mike@couchbase.com>
Tested-by: Michael Wiederhold <mike@couchbase.com>
  • Loading branch information...
1 parent bf2c079 commit 83793092f0e82242aa969e02cd495a8256aab4c7 @trondn trondn committed with mikewied Aug 11, 2011
Showing with 847 additions and 335 deletions.
  1. +83 −0 src/main/java/org/couchbase/mock/memcached/ArithmeticCommandExecutor.java
  2. +0 −114 src/main/java/org/couchbase/mock/memcached/BinaryCommand.java
  3. +1 −0 src/main/java/org/couchbase/mock/memcached/BinaryProtocolHandler.java
  4. +0 −99 src/main/java/org/couchbase/mock/memcached/BinaryResponse.java
  5. +34 −0 src/main/java/org/couchbase/mock/memcached/CommandExecutor.java
  6. +1 −0 src/main/java/org/couchbase/mock/memcached/DataStore.java
  7. +38 −0 src/main/java/org/couchbase/mock/memcached/DeleteCommandExecutor.java
  8. +41 −0 src/main/java/org/couchbase/mock/memcached/GetCommandExecutor.java
  9. +1 −1 src/main/java/org/couchbase/mock/memcached/Item.java
  10. +5 −2 src/main/java/org/couchbase/mock/memcached/MemcachedConnection.java
  11. +34 −92 src/main/java/org/couchbase/mock/memcached/MemcachedServer.java
  12. +33 −0 src/main/java/org/couchbase/mock/memcached/NoopCommandExecutor.java
  13. +33 −0 src/main/java/org/couchbase/mock/memcached/StatCommandExecutor.java
  14. +65 −0 src/main/java/org/couchbase/mock/memcached/StoreCommandExecutor.java
  15. +33 −0 src/main/java/org/couchbase/mock/memcached/UnknownCommandExecutor.java
  16. +47 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryArithmeticCommand.java
  17. +30 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryArithmeticResponse.java
  18. +92 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryCommand.java
  19. +28 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryGetCommand.java
  20. +37 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryGetResponse.java
  21. +56 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryResponse.java
  22. +37 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryStoreCommand.java
  23. +31 −0 src/main/java/org/couchbase/mock/memcached/protocol/BinaryStoreResponse.java
  24. +13 −13 src/main/java/org/couchbase/mock/memcached/{ → protocol}/ComCode.java
  25. +60 −0 src/main/java/org/couchbase/mock/memcached/protocol/CommandFactory.java
  26. +13 −13 src/main/java/org/couchbase/mock/memcached/{ → protocol}/ErrorCode.java
  27. +1 −1 src/main/java/org/couchbase/mock/util/JSON.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.couchbase.mock.memcached.protocol.BinaryArithmeticCommand;
+import org.couchbase.mock.memcached.protocol.BinaryArithmeticResponse;
+import org.couchbase.mock.memcached.protocol.BinaryCommand;
+import org.couchbase.mock.memcached.protocol.BinaryResponse;
+import org.couchbase.mock.memcached.protocol.ComCode;
+import org.couchbase.mock.memcached.protocol.ErrorCode;
+
+/**
+ *
+ * @author Trond Norbye <trond.norbye@gmail.com>
+ */
+public class ArithmeticCommandExecutor implements CommandExecutor {
+
+ @Override
+ public void execute(BinaryCommand command, MemcachedServer server, MemcachedConnection client) {
+ BinaryArithmeticCommand cmd = (BinaryArithmeticCommand) command;
+ Item item = server.getDatastore().get(server, cmd.getVBucketId(), cmd.getKey());
+ ComCode cc = cmd.getComCode();
+
+ if (item == null && cmd.create()) {
+ item = new Item(cmd.getKey(), 0, cmd.getExpiration(), Long.toString(cmd.getInitial()).getBytes(), 0);
+ ErrorCode err = server.getDatastore().add(server, cmd.getVBucketId(), item);
+
+ switch (err) {
+ case KEY_EEXISTS:
+ execute(command, server, client);
+ break;
+ case SUCCESS:
+ if (cc == ComCode.INCREMENT || cc == ComCode.DECREMENT) {
+ // return value
+ }
+ break;
+ default:
+ client.sendResponse(new BinaryResponse(command, err));
+ }
+
+ return;
+ }
+
+ long value;
+ try {
+ value = Long.parseLong(new String(item.getValue()));
+ } catch (NumberFormatException ex) {
+ client.sendResponse(new BinaryResponse(command, ErrorCode.DELTA_BADVAL));
+ return;
+ }
+
+ if (cc == ComCode.INCREMENT || cc == ComCode.INCREMENTQ) {
+ value += cmd.getDelta();
+ } else {
+ value -= cmd.getDelta();
+ }
+
+ Item nval = new Item(cmd.getKey(), 0, cmd.getExpiration(), Long.toString(value).getBytes(), item.getCas());
+ ErrorCode err = server.getDatastore().set(server, cmd.getVBucketId(), nval);
+ if (err == ErrorCode.SUCCESS) {
+ if (cc == ComCode.INCREMENT || cc == ComCode.DECREMENT) {
+ // return value
+ client.sendResponse(new BinaryArithmeticResponse(cmd, value, nval.getCas()));
+ }
+ } else {
+ client.sendResponse(new BinaryResponse(command, err));
+ }
+ }
+}
@@ -1,114 +0,0 @@
-/**
- * Copyright 2011 Membase, 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.
- */
-package org.couchbase.mock.memcached;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * @author Trond Norbye
- */
-public class BinaryCommand {
-
- private final ComCode cc;
- private final short keylen;
- private final byte extlen;
- private final short vbucket;
- private final int bodylen;
- private final int opaque;
- private final long cas;
- private final ByteBuffer bodyBuffer;
-
- public BinaryCommand(ByteBuffer header) throws IOException {
- header.rewind();
- if (header.get() != (byte)0x80) {
- // create a better one... this is an illegal command
- throw new IOException();
- }
- cc = ComCode.valueOf(header.get());
- keylen = header.getShort();
- extlen = header.get();
- if (header.get() != 0) {
- throw new IOException(); // illegal datatype
- }
- vbucket = header.getShort();
- bodylen = header.getInt();
- opaque = header.getInt();
- cas = header.getLong();
- if (bodylen > 0) {
- bodyBuffer = ByteBuffer.allocate(bodylen);
- } else {
- bodyBuffer = null;
- }
- }
-
- public ByteBuffer getInputBuffer() {
- return bodyBuffer;
- }
-
- public ComCode getComCode() {
- return cc;
- }
-
- /**
- * @return
- */
- public int getOpaque() {
- return opaque;
- }
-
- public short getVBucketId() {
- return vbucket;
- }
-
- public long getCas() {
- return cas;
- }
-
- public String getKey() {
- return new String(bodyBuffer.array(), extlen, keylen);
- }
-
- public byte[] getValue() {
- byte ret[] = new byte[bodylen - extlen - keylen];
- System.arraycopy(bodyBuffer.array(), extlen + keylen, ret, 0, ret.length);
- return ret;
- }
-
- public Item getItem() {
-
- switch (cc) {
- case ADD:
- case REPLACE:
- case SET:
- case ADDQ:
- case REPLACEQ:
- case SETQ:
- break;
- default:
- throw new RuntimeException("Illegall command to call getItem for");
- }
-
- int flags = bodyBuffer.getInt(0);
- int exptime = bodyBuffer.getInt(4);
-
- return new Item(getKey(), flags, exptime, getValue(), cas);
- }
-
- boolean complete() {
- return bodylen == 0 || !bodyBuffer.hasRemaining();
- }
-}
@@ -16,6 +16,7 @@
package org.couchbase.mock.memcached;
+import org.couchbase.mock.memcached.protocol.BinaryCommand;
import java.io.IOException;
/**
@@ -1,99 +0,0 @@
-/**
- * Copyright 2011 Membase, 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.
- */
-package org.couchbase.mock.memcached;
-
-import java.nio.ByteBuffer;
-
-/**
- * @author Trond Norbye
- *
- */
-public class BinaryResponse {
-
- private ByteBuffer buffer;
- private byte bytes[];
- private ErrorCode errorCode;
- private ComCode comCode;
-
- public BinaryResponse(BinaryCommand command, ErrorCode errorCode) {
- create(command, errorCode, 0);
- }
-
- public BinaryResponse(BinaryCommand command, ErrorCode errorCode, long cas) {
- create(command, errorCode, cas);
- }
-
- public BinaryResponse(BinaryCommand command, Item item) {
- create(command, item);
- }
-
- private void create(BinaryCommand command, ErrorCode errorCode, long cas) {
- this.errorCode = errorCode;
- comCode = command.getComCode();
-
- buffer = ByteBuffer.allocate(24);
- buffer.put((byte) 0x81);
- buffer.put(command.getComCode().cc());
- buffer.putShort(6, errorCode.value());
- buffer.putInt(12, command.getOpaque());
- buffer.putLong(16, cas);
- buffer.rewind();
- }
-
- private void create(BinaryCommand command, Item item) {
- this.errorCode = ErrorCode.SUCCESS;
- comCode = command.getComCode();
-
- short keylen = 0;
- if (command.getComCode() == ComCode.GETK || command.getComCode() == ComCode.GETKQ) {
- keylen = (short) item.getKey().length();
- }
-
- buffer = ByteBuffer.allocate(28 + keylen + item.getValue().length);
-
- buffer.put((byte) 0x81);
- buffer.put(command.getComCode().cc());
- buffer.putShort(keylen);
- buffer.put((byte) 4); // (the flags)
- buffer.putShort(6, errorCode.value());
- buffer.putInt(8, keylen + 4 + item.getValue().length);
- buffer.putInt(12, command.getOpaque());
- buffer.putLong(16, item.getCas());
- buffer.putInt(24, item.getFlags());
- buffer.position(28);
- if (keylen > 0) {
- buffer.put(item.getKey().getBytes());
- }
- buffer.put(item.getValue());
- buffer.rewind();
- }
-
- public ByteBuffer getBuffer() {
- return buffer;
- }
-
- public byte[] getData() {
- return bytes;
- }
-
- public ErrorCode getErrorCode() {
- return errorCode;
- }
-
- public ComCode getComCode() {
- return comCode;
- }
-}
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import org.couchbase.mock.memcached.protocol.BinaryCommand;
+
+/**
+ *
+ * @author Trond Norbye <trond.norbye@gmail.com>
+ */
+interface CommandExecutor {
+ /**
+ * Execute a single command
+ *
+ * @param cmd The incoming command
+ * @param server The server handling the command
+ * @param client The client requesting the command
+ */
+ void execute(BinaryCommand cmd, MemcachedServer server, MemcachedConnection client);
+}
@@ -15,6 +15,7 @@
*/
package org.couchbase.mock.memcached;
+import org.couchbase.mock.memcached.protocol.ErrorCode;
import java.security.AccessControlException;
import java.util.Map;
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import org.couchbase.mock.memcached.protocol.BinaryResponse;
+import org.couchbase.mock.memcached.protocol.ComCode;
+import org.couchbase.mock.memcached.protocol.ErrorCode;
+import org.couchbase.mock.memcached.protocol.BinaryCommand;
+
+/**
+ *
+ * @author Trond Norbye <trond.norbye@gmail.com>
+ */
+public class DeleteCommandExecutor implements CommandExecutor {
+
+ @Override
+ public void execute(BinaryCommand cmd, MemcachedServer server, MemcachedConnection client) {
+ ErrorCode err = server.getDatastore().delete(server, cmd.getVBucketId(),
+ cmd.getKey(), cmd.getCas());
+ if (!(cmd.getComCode() == ComCode.DELETEQ && err == ErrorCode.SUCCESS)) {
+ client.sendResponse(new BinaryResponse(cmd, err));
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 8379309

Please sign in to comment.