/* * Copyright 2008-2009 LinkedIn, 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 voldemort.client.protocol.pb; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; import voldemort.client.protocol.RequestFormat; import voldemort.client.protocol.pb.VProto.DeleteResponse; import voldemort.client.protocol.pb.VProto.GetAllResponse; import voldemort.client.protocol.pb.VProto.GetResponse; import voldemort.client.protocol.pb.VProto.GetVersionResponse; import voldemort.client.protocol.pb.VProto.PutResponse; import voldemort.client.protocol.pb.VProto.RequestType; import voldemort.server.RequestRoutingType; import voldemort.store.ErrorCodeMapper; import voldemort.store.StoreUtils; import voldemort.utils.ByteArray; import voldemort.versioning.VectorClock; import voldemort.versioning.Version; import voldemort.versioning.Versioned; import com.google.common.collect.Lists; import com.google.protobuf.ByteString; /** * The client side of the protocol buffers request format * * */ public class ProtoBuffClientRequestFormat implements RequestFormat { public final ErrorCodeMapper mapper; public ProtoBuffClientRequestFormat() { this.mapper = new ErrorCodeMapper(); } public void writeDeleteRequest(DataOutputStream output, String storeName, ByteArray key, VectorClock version, RequestRoutingType routingType) throws IOException { StoreUtils.assertValidKey(key); ProtoUtils.writeMessage(output, VProto.VoldemortRequest.newBuilder() .setType(RequestType.DELETE) .setStore(storeName) .setShouldRoute(routingType.equals(RequestRoutingType.ROUTED)) .setRequestRouteType(routingType.getRoutingTypeCode()) .setDelete(VProto.DeleteRequest.newBuilder() .setKey(ByteString.copyFrom(key.get())) .setVersion(ProtoUtils.encodeClock(version))) .build()); } public boolean isCompleteDeleteResponse(ByteBuffer buffer) { return isCompleteResponse(buffer); } public boolean readDeleteResponse(DataInputStream input) throws IOException { DeleteResponse.Builder response = ProtoUtils.readToBuilder(input, DeleteResponse.newBuilder()); if(response.hasError()) throwException(response.getError()); return response.getSuccess(); } public void writeGetRequest(DataOutputStream output, String storeName, ByteArray key, byte[] transforms, RequestRoutingType routingType) throws IOException { StoreUtils.assertValidKey(key); VProto.GetRequest.Builder get = VProto.GetRequest.newBuilder(); get.setKey(ByteString.copyFrom(key.get())); if(transforms != null) { get.setTransforms(ByteString.copyFrom(transforms)); } ProtoUtils.writeMessage(output, VProto.VoldemortRequest.newBuilder() .setType(RequestType.GET) .setStore(storeName) .setShouldRoute(routingType.equals(RequestRoutingType.ROUTED)) .setRequestRouteType(routingType.getRoutingTypeCode()) .setGet(get) .build()); } public boolean isCompleteGetResponse(ByteBuffer buffer) { return isCompleteResponse(buffer); } public List<Versioned<byte[]>> readGetResponse(DataInputStream input) throws IOException { GetResponse.Builder response = ProtoUtils.readToBuilder(input, GetResponse.newBuilder()); if(response.hasError()) throwException(response.getError()); return ProtoUtils.decodeVersions(response.getVersionedList()); } public void writeGetAllRequest(DataOutputStream output, String storeName, Iterable<ByteArray> keys, Map<ByteArray, byte[]> transforms, RequestRoutingType routingType) throws IOException { StoreUtils.assertValidKeys(keys); VProto.GetAllRequest.Builder req = VProto.GetAllRequest.newBuilder(); for(ByteArray key: keys) req.addKeys(ByteString.copyFrom(key.get())); if(transforms != null) { for(Map.Entry<ByteArray, byte[]> transform: transforms.entrySet()) { req.addTransforms(VProto.GetAllRequest.GetAllTransform.newBuilder() .setKey(ByteString.copyFrom(transform.getKey() .get())) .setTransform(ByteString.copyFrom(transform.getValue()))); } } ProtoUtils.writeMessage(output, VProto.VoldemortRequest.newBuilder() .setType(RequestType.GET_ALL) .setStore(storeName) .setShouldRoute(routingType.equals(RequestRoutingType.ROUTED)) .setRequestRouteType(routingType.getRoutingTypeCode()) .setGetAll(req) .build()); } public boolean isCompleteGetAllResponse(ByteBuffer buffer) { return isCompleteResponse(buffer); } public Map<ByteArray, List<Versioned<byte[]>>> readGetAllResponse(DataInputStream input) throws IOException { GetAllResponse.Builder response = ProtoUtils.readToBuilder(input, GetAllResponse.newBuilder()); if(response.hasError()) throwException(response.getError()); Map<ByteArray, List<Versioned<byte[]>>> vals = new HashMap<ByteArray, List<Versioned<byte[]>>>(response.getValuesCount()); for(VProto.KeyedVersions versions: response.getValuesList()) vals.put(ProtoUtils.decodeBytes(versions.getKey()), ProtoUtils.decodeVersions(versions.getVersionsList())); return vals; } @Override public int getExpectedPutRequestSize(String storeName, ByteArray key, byte[] value, byte[] transforms, VectorClock version, RequestRoutingType routingType) { return RequestFormat.SIZE_UNKNOWN; } public void writePutRequest(DataOutputStream output, String storeName, ByteArray key, byte[] value, byte[] transforms, VectorClock version, RequestRoutingType routingType) throws IOException { StoreUtils.assertValidKey(key); VProto.PutRequest.Builder req = VProto.PutRequest.newBuilder() .setKey(ByteString.copyFrom(key.get())) .setVersioned(VProto.Versioned.newBuilder() .setValue(ByteString.copyFrom(value)) .setVersion(ProtoUtils.encodeClock(version))); if(transforms != null) req = req.setTransforms(ByteString.copyFrom(transforms)); ProtoUtils.writeMessage(output, VProto.VoldemortRequest.newBuilder() .setType(RequestType.PUT) .setStore(storeName) .setShouldRoute(routingType.equals(RequestRoutingType.ROUTED)) .setRequestRouteType(routingType.getRoutingTypeCode()) .setPut(req) .build()); } public boolean isCompletePutResponse(ByteBuffer buffer) { return isCompleteResponse(buffer); } public void readPutResponse(DataInputStream input) throws IOException { PutResponse.Builder response = ProtoUtils.readToBuilder(input, PutResponse.newBuilder()); if(response.hasError()) throwException(response.getError()); } public void throwException(VProto.Error error) { throw mapper.getError((short) error.getErrorCode(), error.getErrorMessage()); } public boolean isCompleteGetVersionResponse(ByteBuffer buffer) { return isCompleteResponse(buffer); } public List<Version> readGetVersionResponse(DataInputStream stream) throws IOException { GetVersionResponse.Builder response = ProtoUtils.readToBuilder(stream, GetVersionResponse.newBuilder()); if(response.hasError()) throwException(response.getError()); List<Version> versions = Lists.newArrayListWithCapacity(response.getVersionsCount()); for(VProto.VectorClock version: response.getVersionsList()) versions.add(ProtoUtils.decodeClock(version)); return versions; } public void writeGetVersionRequest(DataOutputStream output, String storeName, ByteArray key, RequestRoutingType routingType) throws IOException { StoreUtils.assertValidKey(key); ProtoUtils.writeMessage(output, VProto.VoldemortRequest.newBuilder() .setType(RequestType.GET_VERSION) .setStore(storeName) .setShouldRoute(routingType.equals(RequestRoutingType.ROUTED)) .setRequestRouteType(routingType.getRoutingTypeCode()) .setGet(VProto.GetRequest.newBuilder() .setKey(ByteString.copyFrom(key.get()))) .build()); } private boolean isCompleteResponse(ByteBuffer buffer) { if((buffer.limit() - buffer.position()) < 4) { // Does not contain the integer ( 4 bytes) return false; } int size = buffer.getInt(); return buffer.remaining() == size; } }