/* * Copyright 2013 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. */ package org.couchbase.mock.control.handlers; import com.google.gson.Gson; import com.google.gson.JsonElement; import java.security.AccessControlException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gson.JsonObject; import org.couchbase.mock.CouchbaseMock; import org.couchbase.mock.control.CommandStatus; import org.couchbase.mock.memcached.*; import org.jetbrains.annotations.NotNull; /** * Handler for various out-of-band key manipulations * @author Mark Nunberg <mnunberg@haskalah.org> */ public final class PersistenceCommandHandler extends KeyCommandHandler { private String error = null; private void executeReal(JsonObject payload, Command command) { final String value; long cas = 0; boolean onMaster; JsonElement eOnReplicas; Storage masterStore; List<Storage> stores = new ArrayList<Storage>(); onMaster = payload.get("OnMaster").getAsBoolean(); if (payload.has("CAS")) { cas = payload.get("CAS").getAsLong(); } if (payload.has("Value")) { value = payload.get("Value").getAsString(); } else { value = ""; } masterStore = vbi.getOwner().getStorage(); if (onMaster) { stores.add(masterStore); } // Figure out which replicas to affect eOnReplicas = payload.get("OnReplicas"); if (eOnReplicas.isJsonArray()) { // An array of indices to use: for (JsonElement ix : eOnReplicas.getAsJsonArray()) { MemcachedServer mc = vbi.getReplicas().get(ix.getAsInt()); Storage s = mc.getStorage(); if (!stores.contains(s)) { stores.add(s); } } } else { int maxReplicas = eOnReplicas.getAsInt(); int replicasSelected = 0; for (MemcachedServer server : vbi.getReplicas()) { if (replicasSelected == maxReplicas) { break; } if (!server.isActive()) { continue; } stores.add(server.getStorage()); replicasSelected++; } } Item source = masterStore.getCached(keySpec); Item newItem; if (source == null) { assert value != null; assert value.getBytes() != null; source = new Item(keySpec, 0, 0, value.getBytes(), null, cas); } if (cas < 0) { cas = (source.getCas() + 1) * 2; } if (cas != 0) { newItem = new Item( source.getKeySpec(), source.getFlags(), source.getExpiryTime(), value.getBytes(), source.getXattr(), cas); } else { newItem = new Item(source); } if (stores.size() == 0) { System.err.println("No stores available for key"); } for (Storage curStore : stores) { switch (command) { case PERSIST: case ENDURE: curStore.putPersisted(newItem); if (command == Command.PERSIST) { break; } // ENDURE fallthrough case CACHE: curStore.putCached(newItem); break; case PURGE: case UNPERSIST: curStore.removePersisted(keySpec); if (command == Command.UNPERSIST) { break; } case UNCACHE: curStore.removeCached(keySpec); break; default: throw new RuntimeException("Unrecognized command"); } } } @NotNull @Override public CommandStatus execute(@NotNull CouchbaseMock mock, @NotNull Command command, @NotNull JsonObject payload) { super.execute(mock, command, payload); try { executeReal(payload, command); } catch (AccessControlException e) { error = e.getMessage(); } return getResponse(); } @NotNull @Override protected CommandStatus getResponse() { if (error == null) { return super.getResponse(); } return new CommandStatus().fail(error); } }