OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library memcache_raw_impl; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'package:fixnum/fixnum.dart'; |
| 10 import 'package:memcache/memcache_raw.dart' as raw; |
| 11 |
| 12 import '../../api/errors.dart'; |
| 13 import '../protobuf_api/rpc/rpc_service.dart'; |
| 14 import '../protobuf_api/internal/memcache_service.pb.dart' as pb; |
| 15 import '../protobuf_api/memcache_service.dart'; |
| 16 |
| 17 class RawMemcacheRpcImpl implements raw.RawMemcache { |
| 18 final MemcacheServiceClientRPCStub _clientRPCStub; |
| 19 |
| 20 RawMemcacheRpcImpl(RPCService rpcService, String ticket) |
| 21 : _clientRPCStub = new MemcacheServiceClientRPCStub(rpcService, ticket); |
| 22 |
| 23 bool _sameKey(a, b) { |
| 24 if (a.length != b.length) return false; |
| 25 for (int i = 0; i < a.length; i++) { |
| 26 if (a[i] != b[i]) return false; |
| 27 } |
| 28 return true; |
| 29 } |
| 30 |
| 31 Future<List<raw.GetResult>> get(List<raw.GetOperation> batch) { |
| 32 var request = new pb.MemcacheGetRequest(); |
| 33 batch.forEach((operation) => request.key.add(operation.key)); |
| 34 return _clientRPCStub.Get(request).then((pb.MemcacheGetResponse response) { |
| 35 if (response.item.length > request.key.length) { |
| 36 throw ProtocolError.INVALID_RESPONSE; |
| 37 } |
| 38 // The response from the memcache service only have the items which |
| 39 // where actually found. In most cases the items found are returned |
| 40 // in the same order as the keys in the request. The loop below is |
| 41 // optimized for this case to degenerate into linear time by remembering |
| 42 // the last index. |
| 43 var result = []; |
| 44 int responseItemIdx = 0; |
| 45 int remaining = response.item.length; |
| 46 for (int i = 0; i < batch.length; i++) { |
| 47 bool found = false; |
| 48 for (int j = 0; |
| 49 remaining > 0 && !found && j < response.item.length; |
| 50 j++) { |
| 51 if (_sameKey(batch[i].key, response.item[responseItemIdx].key)) { |
| 52 // Value found for key. |
| 53 result.add(new raw.GetResult( |
| 54 raw.Status.NO_ERROR, |
| 55 null, |
| 56 response.item[responseItemIdx].flags, |
| 57 null, |
| 58 response.item[responseItemIdx].value)); |
| 59 found = true; |
| 60 remaining--; |
| 61 } |
| 62 responseItemIdx = (responseItemIdx + 1) % response.item.length; |
| 63 } |
| 64 if (!found) { |
| 65 // This key had no value found. |
| 66 result.add(new raw.GetResult(raw.Status.KEY_NOT_FOUND, |
| 67 null, |
| 68 0, |
| 69 null, |
| 70 null)); |
| 71 } |
| 72 } |
| 73 return result; |
| 74 }); |
| 75 } |
| 76 |
| 77 Future<List<raw.SetResult>> set(List<raw.SetOperation> batch) { |
| 78 var request = new pb.MemcacheSetRequest(); |
| 79 batch.forEach((operation) { |
| 80 var item = new pb.MemcacheSetRequest_Item(); |
| 81 item.key = operation.key; |
| 82 item.value = operation.value; |
| 83 switch (operation.operation) { |
| 84 case raw.SetOperation.SET: |
| 85 item.setPolicy = pb.MemcacheSetRequest_SetPolicy.SET; |
| 86 break; |
| 87 case raw.SetOperation.ADD: |
| 88 item.setPolicy = pb.MemcacheSetRequest_SetPolicy.ADD; |
| 89 break; |
| 90 case raw.SetOperation.REPLACE: |
| 91 item.setPolicy = pb.MemcacheSetRequest_SetPolicy.REPLACE; |
| 92 break; |
| 93 default: |
| 94 throw new UnsupportedError('Unsupported set operation $operation'); |
| 95 } |
| 96 request.item.add(item); |
| 97 }); |
| 98 return _clientRPCStub.Set(request).then((pb.MemcacheSetResponse response) { |
| 99 if (response.setStatus.length != request.item.length) { |
| 100 throw ProtocolError.INVALID_RESPONSE; |
| 101 } |
| 102 var result = []; |
| 103 response.setStatus.forEach((status) { |
| 104 switch (status) { |
| 105 case pb.MemcacheSetResponse_SetStatusCode.STORED: |
| 106 result.add(new raw.SetResult(raw.Status.NO_ERROR, null)); |
| 107 break; |
| 108 case pb.MemcacheSetResponse_SetStatusCode.NOT_STORED: |
| 109 result.add(new raw.SetResult(raw.Status.NOT_STORED, null)); |
| 110 break; |
| 111 case pb.MemcacheSetResponse_SetStatusCode.EXISTS: |
| 112 result.add(new raw.SetResult(raw.Status.KEY_EXISTS, null)); |
| 113 break; |
| 114 case pb.MemcacheSetResponse_SetStatusCode.ERROR: |
| 115 result.add(new raw.SetResult(raw.Status.ERROR, null)); |
| 116 break; |
| 117 default: |
| 118 throw new UnsupportedError('Unsupported set status $status'); |
| 119 } |
| 120 }); |
| 121 return result; |
| 122 }); |
| 123 } |
| 124 |
| 125 Future<List<raw.RemoveResult>> remove(List<raw.RemoveOperation> batch) { |
| 126 var request = new pb.MemcacheDeleteRequest(); |
| 127 batch.forEach((operation) { |
| 128 var item = new pb.MemcacheDeleteRequest_Item(); |
| 129 item.key = operation.key; |
| 130 request.item.add(item); |
| 131 }); |
| 132 return _clientRPCStub.Delete(request) |
| 133 .then((pb.MemcacheDeleteResponse response) { |
| 134 var result = []; |
| 135 response.deleteStatus.forEach((status) { |
| 136 if (status == pb.MemcacheDeleteResponse_DeleteStatusCode.DELETED) { |
| 137 result.add( |
| 138 new raw.RemoveResult(raw.Status.NO_ERROR, null)); |
| 139 } else if (status == |
| 140 pb.MemcacheDeleteResponse_DeleteStatusCode.NOT_FOUND) { |
| 141 result.add( |
| 142 new raw.RemoveResult(raw.Status.KEY_NOT_FOUND, null)); |
| 143 } else { |
| 144 throw new UnsupportedError('Unsupported delete status $status'); |
| 145 } |
| 146 }); |
| 147 return result; |
| 148 }); |
| 149 } |
| 150 |
| 151 Future<List<raw.IncrementResult>> increment( |
| 152 List<raw.IncrementOperation> batch) { |
| 153 if (batch.length == 1) { |
| 154 var request = new pb.MemcacheIncrementRequest(); |
| 155 request.key = batch[0].key; |
| 156 request.delta = new Int64(batch[0].delta); |
| 157 request.direction = |
| 158 batch[0].direction == raw.IncrementOperation.INCREMENT |
| 159 ? pb.MemcacheIncrementRequest_Direction.INCREMENT |
| 160 : pb.MemcacheIncrementRequest_Direction.DECREMENT; |
| 161 request.initialValue = new Int64(batch[0].initialValue); |
| 162 return _clientRPCStub.Increment(request) |
| 163 .then((pb.MemcacheIncrementResponse response) { |
| 164 raw.Status status; |
| 165 String message; |
| 166 switch (response.incrementStatus) { |
| 167 case pb.MemcacheIncrementResponse_IncrementStatusCode.OK: |
| 168 status = raw.Status.NO_ERROR; |
| 169 break; |
| 170 case pb.MemcacheIncrementResponse_IncrementStatusCode.NOT_CHANGED: |
| 171 status = raw.Status.NO_ERROR; |
| 172 break; |
| 173 case pb.MemcacheIncrementResponse_IncrementStatusCode.ERROR: |
| 174 status = raw.Status.ERROR; |
| 175 message = 'Increment failed'; |
| 176 break; |
| 177 default: |
| 178 throw new UnsupportedError( |
| 179 'Unsupported increment status ${response.incrementStatus}'); |
| 180 } |
| 181 int newValue = response.newValue.toInt(); |
| 182 if (newValue < 0) newValue = 0x10000000000000000 + newValue; |
| 183 var result = new raw.IncrementResult(status, message, newValue); |
| 184 return [result]; |
| 185 }); |
| 186 } else { |
| 187 throw new UnsupportedError('Unsupported batch increment'); |
| 188 } |
| 189 } |
| 190 |
| 191 Future clear() { |
| 192 var request = new pb.MemcacheFlushRequest(); |
| 193 |
| 194 return _clientRPCStub.FlushAll(request).then((_) => null); |
| 195 } |
| 196 } |
OLD | NEW |