blob: 17538f0065841ab10019423ef26cba2504b3ba94 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datastore.ramcloud;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07002
3import java.io.File;
Yuta HIGUCHId47eac32014-04-07 13:44:47 -07004import java.nio.ByteBuffer;
5import java.nio.ByteOrder;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07006import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.Iterator;
10import java.util.List;
11import java.util.concurrent.ConcurrentHashMap;
12
Jonathan Hart6df90172014-04-03 10:13:11 -070013import net.onrc.onos.core.datastore.IKVClient;
14import net.onrc.onos.core.datastore.IKVTable;
Jonathan Harta99ec672014-04-03 11:30:34 -070015import net.onrc.onos.core.datastore.IKVTable.IKVEntry;
Jonathan Hart6df90172014-04-03 10:13:11 -070016import net.onrc.onos.core.datastore.IKVTableID;
17import net.onrc.onos.core.datastore.IMultiEntryOperation;
Jonathan Harta99ec672014-04-03 11:30:34 -070018import net.onrc.onos.core.datastore.IMultiEntryOperation.STATUS;
Jonathan Hart6df90172014-04-03 10:13:11 -070019import net.onrc.onos.core.datastore.ObjectDoesntExistException;
20import net.onrc.onos.core.datastore.ObjectExistsException;
21import net.onrc.onos.core.datastore.WrongVersionException;
Jonathan Hart6df90172014-04-03 10:13:11 -070022import net.onrc.onos.core.datastore.internal.IModifiableMultiEntryOperation;
23import net.onrc.onos.core.datastore.ramcloud.RCTable.Entry;
24import net.onrc.onos.core.datastore.utils.ByteArrayUtil;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070025
26import org.apache.commons.configuration.Configuration;
27import org.apache.commons.configuration.ConfigurationException;
28import org.apache.commons.configuration.PropertiesConfiguration;
29import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
31
32import edu.stanford.ramcloud.JRamCloud;
33import edu.stanford.ramcloud.JRamCloud.MultiReadObject;
34import edu.stanford.ramcloud.JRamCloud.MultiWriteObject;
35import edu.stanford.ramcloud.JRamCloud.MultiWriteRspObject;
36import edu.stanford.ramcloud.JRamCloud.RejectRules;
37import edu.stanford.ramcloud.JRamCloud.RejectRulesException;
38import edu.stanford.ramcloud.JRamCloud.TableEnumerator2;
39
Yuta HIGUCHId082b962014-06-02 11:42:22 -070040/**
41 * RAMCloud implementation of datastore IKVClient.
42 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070043public class RCClient implements IKVClient {
Yuta HIGUCHId150ece2014-04-29 16:25:36 -070044
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070045 private static final Logger log = LoggerFactory.getLogger(RCClient.class);
46
Yuta HIGUCHId150ece2014-04-29 16:25:36 -070047 private static final String DEFAULT_LOCATOR = "zk:localhost:2181";
48 private static final String DEFAULT_CLUSTERNAME = "ONOS-RC";
49
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070050 private static final String DB_CONFIG_FILE = "conf/ramcloud.conf";
Yuta HIGUCHId082b962014-06-02 11:42:22 -070051 private static final Configuration CONFIG = getConfiguration();
52 private static final String CLUSTER_NAME = getClusterName(CONFIG);
53 private static final String LOCATOR = getLocator(CONFIG);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070054
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070055 // FIXME These constants should be defined by JRamCloud
Yuta HIGUCHId082b962014-06-02 11:42:22 -070056 /**
57 * Constant defined in RAMCloud's Status.h.
58 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070059 public static final int STATUS_OK = 0;
60
Yuta HIGUCHIe316d5c2014-04-19 13:37:38 -070061 /**
62 * Maximum number of Multi-Read operations which can be executed in
63 * one RPC call.
64 *
65 * There are multiple factors which determines this limit.
66 * - RAMCloud RPC size limit of 8MB.
67 * - JNI implementation store the RPC result on stack.
68 * (Increasing the stack-size limit will help relaxing this limit.)
69 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070070 public static final int MAX_MULTI_READS = Math.max(1, Integer
Yuta HIGUCHI0fe749a2014-05-27 09:35:16 -070071 .parseInt(System.getProperty("ramcloud.max_multi_reads", "400")));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070072
Yuta HIGUCHIe316d5c2014-04-19 13:37:38 -070073 /**
74 * Maximum number of Multi-Write operations which can be executed in
75 * one RPC call.
76 *
77 * There are multiple factors which determines this limit.
78 * - RAMCloud RPC size limit of 8MB.
79 * - JNI implementation store the RPC result on stack.
80 * (Increasing the stack-size limit will help relaxing this limit.)
81 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070082 public static final int MAX_MULTI_WRITES = Math.max(1, Integer
Yuta HIGUCHI0fe749a2014-05-27 09:35:16 -070083 .parseInt(System.getProperty("ramcloud.max_multi_writes", "800")));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070084
Ray Milkey5c9f2db2014-04-09 10:31:21 -070085 private static final ThreadLocal<JRamCloud> TLS_RC_CLIENT = new ThreadLocal<JRamCloud>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070086 @Override
87 protected JRamCloud initialValue() {
Yuta HIGUCHId082b962014-06-02 11:42:22 -070088 return new JRamCloud(LOCATOR, CLUSTER_NAME);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070089 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070090 };
91
92 /**
93 * @return JRamCloud instance intended to be used only within the
Ray Milkey269ffb92014-04-03 14:43:30 -070094 * SameThread.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070095 * @note Do not store the returned instance in a member variable, etc. which
Ray Milkey269ffb92014-04-03 14:43:30 -070096 * may be accessed later by another thread.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070097 */
98 static JRamCloud getJRamCloudClient() {
Ray Milkey5c9f2db2014-04-09 10:31:21 -070099 return TLS_RC_CLIENT.get();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700100 }
101
102 // Currently RCClient is state-less
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700103 private static final RCClient THE_INSTANCE = new RCClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700104
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700105 /**
106 * Default constructor.
107 */
108 protected RCClient() {
109 log.info("locator: {}, cluster name: {}", LOCATOR, CLUSTER_NAME);
110 }
111
112 /**
113 * Gets a DataStoreClient implemented on RAMCloud.
114 *
115 * @return RCClient
116 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700117 public static RCClient getClient() {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700118 return THE_INSTANCE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700119 }
120
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700121 /**
122 * Gets the {@link Configuration} instance.
123 *
124 * @return Configuration
125 */
126 private static final Configuration getConfiguration() {
127 final File configFile = new File(
128 System.getProperty("ramcloud.config.path",
129 DB_CONFIG_FILE));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700130 return getConfiguration(configFile);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700131 }
132
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700133 /**
134 * Gets the {@link Configuration} instance from properties file.
135 *
136 * @param configFile properties file
137 * @return Configuration
138 */
139 private static final Configuration getConfiguration(final File configFile) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700140 if (configFile == null) {
141 throw new IllegalArgumentException("Need to specify a configuration file or storage directory");
142 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700143
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700144 if (!configFile.isFile()) {
145 throw new IllegalArgumentException("Location of configuration must be a file");
146 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700147
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700148 try {
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700149 PropertiesConfiguration conf = new PropertiesConfiguration();
150 // stop parsing commas in property value
151 conf.setDelimiterParsingDisabled(true);
152 conf.load(configFile);
153 return conf;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700154 } catch (ConfigurationException e) {
155 throw new IllegalArgumentException("Could not load configuration at: " + configFile, e);
156 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700157 }
158
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700159 /**
160 * Gets the RAMCloud external storage locator from configuration file.
161 *
162 * @param configuration input
163 * @return RAMCloud external storage locator string
164 */
165 private static String getLocator(final Configuration configuration) {
Yuta HIGUCHId150ece2014-04-29 16:25:36 -0700166
167 final String locator = configuration.getString("ramcloud.locator");
168 if (locator != null) {
169 return locator;
170 }
171
172 // TODO Stop reading obsolete coordinatorIp, etc. once we're ready.
173 final String coordinatorIp = configuration.getString("ramcloud.coordinatorIp");
174 if (coordinatorIp == null) {
175 return DEFAULT_LOCATOR;
176 }
177
178 final String coordinatorPort = configuration.getString("ramcloud.coordinatorPort");
179 if (coordinatorPort == null) {
180 return DEFAULT_LOCATOR;
181 }
182
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700183 final String coordinatorURL = coordinatorIp + "," + coordinatorPort;
184 return coordinatorURL;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700185 }
186
Yuta HIGUCHId082b962014-06-02 11:42:22 -0700187 /**
188 * Gets the RAMCloud clusterName from configuration file.
189 *
190 * @param configuration input
191 * @return RAMCloud clusterName
192 */
193 private static String getClusterName(final Configuration configuration) {
194 return configuration.getString("ramcloud.clusterName",
195 DEFAULT_CLUSTERNAME);
Yuta HIGUCHId150ece2014-04-29 16:25:36 -0700196 }
197
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700198 @Override
199 public IMultiEntryOperation createOp(IKVTableID tableId, byte[] key, byte[] value) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700200 return RCMultiEntryOperation.create(tableId, key, value);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700201 }
202
203 /**
204 * @param tableId RCTableID instance
205 */
206 @Override
207 public long create(IKVTableID tableId, byte[] key, byte[] value)
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700208 throws ObjectExistsException {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700209
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700210 RCTableID rcTableId = (RCTableID) tableId;
211 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700212
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700213 RejectRules rules = new RejectRules();
214 rules.rejectIfExists();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700215
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700216 try {
217 return rcClient.write(rcTableId.getTableID(), key, value, rules);
218 } catch (JRamCloud.ObjectExistsException e) {
219 throw new ObjectExistsException(rcTableId, key, e);
220 } catch (JRamCloud.RejectRulesException e) {
221 log.error("Unexpected RejectRulesException", e);
222 return JRamCloud.VERSION_NONEXISTENT;
223 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700224 }
225
226 @Override
227 public IMultiEntryOperation forceCreateOp(IKVTableID tableId, byte[] key, byte[] value) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700228 return RCMultiEntryOperation.forceCreate(tableId, key, value);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700229 }
230
231 @Override
232 public long forceCreate(IKVTableID tableId, byte[] key, byte[] value) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700233 RCTableID rcTableId = (RCTableID) tableId;
234 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700235
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700236 long updatedVersion = rcClient.write(rcTableId.getTableID(), key, value);
237 return updatedVersion;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700238 }
239
240 @Override
241 public IMultiEntryOperation readOp(IKVTableID tableId, byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700242 return RCMultiEntryOperation.read(tableId, key);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700243 }
244
245 @Override
246 public IKVEntry read(IKVTableID tableId, byte[] key)
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700247 throws ObjectDoesntExistException {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700248
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700249 RCTableID rcTableId = (RCTableID) tableId;
250 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700251
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700252 RejectRules rules = new RejectRules();
253 rules.rejectIfDoesntExists();
254 try {
255 JRamCloud.Object rcObj = rcClient.read(rcTableId.getTableID(), key, rules);
256 return new Entry(rcObj.key, rcObj.value, rcObj.version);
257 } catch (JRamCloud.ObjectDoesntExistException e) {
258 throw new ObjectDoesntExistException(rcTableId, key, e);
259 } catch (JRamCloud.RejectRulesException e) {
260 log.error("Unexpected RejectRulesException", e);
261 return null;
262 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700263 }
264
265 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 public IMultiEntryOperation updateOp(IKVTableID tableId, byte[] key, byte[] value, long version) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700267 return RCMultiEntryOperation.update(tableId, key, value, version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700268 }
269
270 @Override
271 public long update(IKVTableID tableId, byte[] key, byte[] value,
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 long version) throws ObjectDoesntExistException,
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700273 WrongVersionException {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700274
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700275 RCTableID rcTableId = (RCTableID) tableId;
276 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700277
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700278 RejectRules rules = new RejectRules();
279 rules.rejectIfDoesntExists();
280 rules.rejectIfNeVersion(version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700281
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700282 try {
283 return rcClient.write(rcTableId.getTableID(), key, value, rules);
284 } catch (JRamCloud.ObjectDoesntExistException e) {
285 throw new ObjectDoesntExistException(rcTableId, key, e);
286 } catch (JRamCloud.WrongVersionException e) {
287 throw new WrongVersionException(rcTableId, key, version, e);
288 } catch (JRamCloud.RejectRulesException e) {
289 log.error("Unexpected RejectRulesException", e);
290 return JRamCloud.VERSION_NONEXISTENT;
291 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700292 }
293
294
295 @Override
296 public long update(IKVTableID tableId, byte[] key, byte[] value)
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700297 throws ObjectDoesntExistException {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700298
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700299 RCTableID rcTableId = (RCTableID) tableId;
300 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700301
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700302 RejectRules rules = new RejectRules();
303 rules.rejectIfDoesntExists();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700305 try {
306 return rcClient.write(rcTableId.getTableID(), key, value, rules);
307 } catch (JRamCloud.ObjectDoesntExistException e) {
308 throw new ObjectDoesntExistException(rcTableId, key, e);
309 } catch (JRamCloud.RejectRulesException e) {
310 log.error("Unexpected RejectRulesException", e);
311 return JRamCloud.VERSION_NONEXISTENT;
312 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700313 }
314
315 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 public IMultiEntryOperation deleteOp(IKVTableID tableId, byte[] key, byte[] value, long version) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700317 return RCMultiEntryOperation.delete(tableId, key, value, version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700318 }
319
320 @Override
321 public long delete(IKVTableID tableId, byte[] key, long version)
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700322 throws ObjectDoesntExistException, WrongVersionException {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700323
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700324 RCTableID rcTableId = (RCTableID) tableId;
325 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700326
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700327 RejectRules rules = new RejectRules();
328 rules.rejectIfDoesntExists();
329 rules.rejectIfNeVersion(version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700330
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700331 try {
332 return rcClient.remove(rcTableId.getTableID(), key, rules);
333 } catch (JRamCloud.ObjectDoesntExistException e) {
334 throw new ObjectDoesntExistException(rcTableId, key, e);
335 } catch (JRamCloud.WrongVersionException e) {
336 throw new WrongVersionException(rcTableId, key, version, e);
337 } catch (JRamCloud.RejectRulesException e) {
338 log.error("Unexpected RejectRulesException", e);
339 return JRamCloud.VERSION_NONEXISTENT;
340 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700341 }
342
343 @Override
344 public IMultiEntryOperation forceDeleteOp(IKVTableID tableId, byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700345 return RCMultiEntryOperation.forceDelete(tableId, key);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700346 }
347
348 @Override
349 public long forceDelete(IKVTableID tableId, byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700350 RCTableID rcTableId = (RCTableID) tableId;
351 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700352 final long removedVersion = rcClient.remove(rcTableId.getTableID(), key);
353 return removedVersion;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700354 }
355
356 @Override
357 public Iterable<IKVEntry> getAllEntries(IKVTableID tableId) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700358 return new RCTableEntryIterable((RCTableID) tableId);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700359 }
360
361 static class RCTableEntryIterable implements Iterable<IKVEntry> {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700362 private final RCTableID tableId;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700363
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700364 public RCTableEntryIterable(final RCTableID tableId) {
365 this.tableId = tableId;
366 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700367
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700368 @Override
369 public Iterator<IKVEntry> iterator() {
370 return new RCClient.RCTableIterator(tableId);
371 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700372 }
373
374 public static class RCTableIterator implements Iterator<IKVEntry> {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700375 private final RCTableID tableId;
376 protected final TableEnumerator2 enumerator;
377 private JRamCloud.Object last;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700378
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700379 public RCTableIterator(final RCTableID tableId) {
380 this.tableId = tableId;
381 this.enumerator = getJRamCloudClient().new TableEnumerator2(tableId.getTableID());
382 this.last = null;
383 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700384
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700385 @Override
386 public boolean hasNext() {
387 return this.enumerator.hasNext();
388 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700389
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700390 @Override
391 public RCTable.Entry next() {
392 last = enumerator.next();
393 return new RCTable.Entry(last.key, last.value, last.version);
394 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700395
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700396 @Override
397 public void remove() {
398 if (last != null) {
399 getJRamCloudClient();
400 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700401
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700402 RejectRules rules = new RejectRules();
403 rules.rejectIfNeVersion(last.version);
404 try {
405 rcClient.remove(tableId.getTableID(), last.key, rules);
406 } catch (RejectRulesException e) {
407 log.trace("remove failed", e);
408 }
409 last = null;
410 }
411 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700412 }
413
414 @Override
415 public boolean multiRead(final Collection<IMultiEntryOperation> ops) {
416
Ray Milkey269ffb92014-04-03 14:43:30 -0700417 if (ops.size() <= MAX_MULTI_READS && ops instanceof ArrayList) {
Ray Milkey7f1567c2014-04-08 13:53:32 -0700418 @SuppressWarnings({ "unchecked", "rawtypes" })
Ray Milkey269ffb92014-04-03 14:43:30 -0700419 final ArrayList<RCMultiEntryOperation> arrays = (ArrayList) ops;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700420 return multiReadInternal(arrays);
421 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700422
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700423 boolean failExists = false;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700424
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700425 ArrayList<RCMultiEntryOperation> req = new ArrayList<>();
426 Iterator<IMultiEntryOperation> it = ops.iterator();
427 while (it.hasNext()) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700428
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700429 req.add((RCMultiEntryOperation) it.next());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700430
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700431 if (req.size() >= MAX_MULTI_READS) {
432 // dispatch multiRead
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700433 failExists |= multiReadInternal(req);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700434 req.clear();
435 }
436 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700437
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700438 if (!req.isEmpty()) {
439 // dispatch multiRead
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700440 failExists |= multiReadInternal(req);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700441 req.clear();
442 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700443
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700444 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700445 }
446
447 @Override
448 public boolean multiWrite(final List<IMultiEntryOperation> ops) {
449
Ray Milkey269ffb92014-04-03 14:43:30 -0700450 if (ops.size() <= MAX_MULTI_WRITES && ops instanceof ArrayList) {
Ray Milkey7f1567c2014-04-08 13:53:32 -0700451 @SuppressWarnings({ "unchecked", "rawtypes" })
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 final ArrayList<RCMultiEntryOperation> arrays = (ArrayList) ops;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700453 return multiWriteInternal(arrays);
454 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700455
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700456 boolean failExists = false;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700457
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700458 ArrayList<RCMultiEntryOperation> req = new ArrayList<>();
459 Iterator<IMultiEntryOperation> it = ops.iterator();
460 while (it.hasNext()) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700461
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700462 req.add((RCMultiEntryOperation) it.next());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700463
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700464 if (req.size() >= MAX_MULTI_WRITES) {
465 // dispatch multiWrite
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700466 failExists |= multiWriteInternal(req);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700467 req.clear();
468 }
469 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700470
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700471 if (!req.isEmpty()) {
472 // dispatch multiWrite
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700473 failExists |= multiWriteInternal(req);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700474 req.clear();
475 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700476
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700477 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700478 }
479
480 @Override
481 public boolean multiDelete(final Collection<IMultiEntryOperation> ops) {
482
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700483 // TODO implement multiRemove JNI, etc. if we need performance
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700484
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700485 boolean failExists = false;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700486 JRamCloud rcClient = getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700487
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700488 for (IMultiEntryOperation iop : ops) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 RCMultiEntryOperation op = (RCMultiEntryOperation) iop;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700490 switch (op.getOperation()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700491 case DELETE:
492 RejectRules rules = new RejectRules();
493 rules.rejectIfDoesntExists();
494 rules.rejectIfNeVersion(op.getVersion());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700495
Ray Milkey269ffb92014-04-03 14:43:30 -0700496 try {
497 final long removedVersion = rcClient.remove(op.tableId.getTableID(), op.entry.getKey(), rules);
498 op.entry.setVersion(removedVersion);
499 op.status = STATUS.SUCCESS;
500 } catch (JRamCloud.ObjectDoesntExistException | JRamCloud.WrongVersionException e) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700501 log.error("Failed to remove key:" +
502 ByteArrayUtil.toHexStringBuilder(op.entry.getKey(), "") +
503 " from tableID:" + op.tableId, e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700504 failExists = true;
505 op.status = STATUS.FAILED;
506 } catch (JRamCloud.RejectRulesException e) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700507 log.error("Failed to remove key:" +
508 ByteArrayUtil.toHexStringBuilder(op.entry.getKey(), "") +
509 " from tableID:" + op.tableId, e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 failExists = true;
511 op.status = STATUS.FAILED;
512 }
513 break;
514
515 case FORCE_DELETE:
516 final long removedVersion = rcClient.remove(op.tableId.getTableID(), op.entry.getKey());
517 if (removedVersion != VERSION_NONEXISTENT) {
518 op.entry.setVersion(removedVersion);
519 op.status = STATUS.SUCCESS;
520 } else {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700521 log.error("Failed to remove key:{} from tableID:{}",
522 ByteArrayUtil.toHexStringBuilder(op.entry.getKey(), ""),
523 op.tableId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 failExists = true;
525 op.status = STATUS.FAILED;
526 }
527 break;
528
529 default:
530 log.error("Invalid operation {} specified on multiDelete", op.getOperation());
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700531 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700532 op.status = STATUS.FAILED;
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 break;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700534 }
535 }
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700536 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700537 }
538
539 private boolean multiReadInternal(final ArrayList<RCMultiEntryOperation> ops) {
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700540 boolean failExists = false;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700541 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700542
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700543 final int reqs = ops.size();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700544
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700545 MultiReadObject multiReadObjects = new MultiReadObject(reqs);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700546
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700547 // setup multi-read operation objects
548 for (int i = 0; i < reqs; ++i) {
549 IMultiEntryOperation op = ops.get(i);
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 multiReadObjects.setObject(i, ((RCTableID) op.getTableId()).getTableID(), op.getKey());
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700551 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700552
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700553 // execute
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700554 JRamCloud.Object[] results = rcClient.multiRead(multiReadObjects.tableId,
555 multiReadObjects.key, multiReadObjects.keyLength, reqs);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700556 if (results.length != reqs) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700557 log.error("multiRead returned unexpected number of results. " +
558 "(requested:{}, returned:{})", reqs, results.length);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700559 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700560 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700561
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700562 for (int i = 0; i < results.length; ++i) {
563 IModifiableMultiEntryOperation op = ops.get(i);
564 if (results[i] == null) {
Yuta HIGUCHIf148aac2014-05-05 14:59:06 -0700565 // Logging as error gets too noisy when doing speculative read.
566 log.trace("MultiRead error {}, {}", op.getTableId(), op);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700567 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700568 op.setStatus(STATUS.FAILED);
569 continue;
570 }
571 assert (Arrays.equals(results[i].key, op.getKey()));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700572
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700573 op.setValue(results[i].value, results[i].version);
574 if (results[i].version == JRamCloud.VERSION_NONEXISTENT) {
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700575 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700576 op.setStatus(STATUS.FAILED);
577 } else {
578 op.setStatus(STATUS.SUCCESS);
579 }
580 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700581
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700582 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700583 }
584
585 private boolean multiWriteInternal(final ArrayList<RCMultiEntryOperation> ops) {
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700586 boolean failExists = false;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700587 JRamCloud rcClient = RCClient.getJRamCloudClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700588
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700589 final int reqs = ops.size();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700590
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700591 MultiWriteObject multiWriteObjects = new MultiWriteObject(reqs);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700592
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700593 for (int i = 0; i < reqs; ++i) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700594
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700595 IModifiableMultiEntryOperation op = ops.get(i);
596 RejectRules rules = new RejectRules();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700597
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700598 switch (op.getOperation()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 case CREATE:
600 rules.rejectIfExists();
601 break;
602 case FORCE_CREATE:
603 // no reject rule
604 break;
605 case UPDATE:
606 rules.rejectIfDoesntExists();
607 rules.rejectIfNeVersion(op.getVersion());
608 break;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700609
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 default:
611 log.error("Invalid operation {} specified on multiWriteInternal", op.getOperation());
612 failExists = true;
613 op.setStatus(STATUS.FAILED);
614 return failExists;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700615 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700616 multiWriteObjects.setObject(i,
617 ((RCTableID) op.getTableId()).getTableID(), op.getKey(),
618 op.getValue(), rules);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700619 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700620
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700621 MultiWriteRspObject[] results = rcClient.multiWrite(multiWriteObjects.tableId,
622 multiWriteObjects.key, multiWriteObjects.keyLength,
623 multiWriteObjects.value, multiWriteObjects.valueLength, ops.size(),
624 multiWriteObjects.rules);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700625 if (results.length != reqs) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700626 log.error("multiWrite returned unexpected number of results. " +
627 "(requested:{}, returned:{})", reqs, results.length);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700628 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700629 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700630
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700631 for (int i = 0; i < results.length; ++i) {
632 IModifiableMultiEntryOperation op = ops.get(i);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700633
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700634 if (results[i] != null
635 && results[i].getStatus() == RCClient.STATUS_OK) {
636 op.setStatus(STATUS.SUCCESS);
637 op.setVersion(results[i].getVersion());
638 } else {
639 op.setStatus(STATUS.FAILED);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700640 failExists = true;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700641 }
642 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700643
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700644 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700645 }
646
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700647 private static final ConcurrentHashMap<String, RCTable> TABLES =
648 new ConcurrentHashMap<>();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700649
650 @Override
651 public IKVTable getTable(final String tableName) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700652 RCTable table = TABLES.get(tableName);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700653 if (table == null) {
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700654 RCTable newTable = new RCTable(tableName);
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700655 RCTable existingTable = TABLES
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700656 .putIfAbsent(tableName, newTable);
657 if (existingTable != null) {
658 return existingTable;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700659 } else {
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700660 return newTable;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700661 }
662 }
663 return table;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700664 }
665
666 @Override
667 public void dropTable(IKVTable table) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700668 JRamCloud rcClient = RCClient.getJRamCloudClient();
669 rcClient.dropTable(table.getTableId().getTableName());
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700670 TABLES.remove(table.getTableId().getTableName());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700671 }
672
673 static final long VERSION_NONEXISTENT = JRamCloud.VERSION_NONEXISTENT;
674
675 @Override
Ray Milkey7531a342014-04-11 15:08:12 -0700676 public long getVersionNonexistant() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700677 return VERSION_NONEXISTENT;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700678 }
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700679
680 @Override
681 public void createCounter(final IKVTableID tableId, final byte[] key,
682 final long initialValue)
683 throws ObjectExistsException {
684
685 ByteBuffer valueBytes = ByteBuffer.allocate(8)
686 .order(ByteOrder.LITTLE_ENDIAN).putLong(initialValue);
687 valueBytes.flip();
688 final long version = create(tableId, key, valueBytes.array());
689 if (log.isTraceEnabled()) {
690 log.trace("Created counter {}-{}={}@{}",
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700691 tableId, ByteArrayUtil.toHexStringBuilder(key, ":"),
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700692 initialValue, version);
693 }
694 }
695
696 @Override
697 public void setCounter(final IKVTableID tableId, final byte[] key,
698 final long value) {
699
700 ByteBuffer valueBytes = ByteBuffer.allocate(8)
701 .order(ByteOrder.LITTLE_ENDIAN).putLong(value);
702 valueBytes.flip();
703
704 final long version = forceCreate(tableId, key, valueBytes.array());
705 if (log.isTraceEnabled()) {
706 log.trace("set counter {}-{}={}@{}",
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700707 tableId, ByteArrayUtil.toHexStringBuilder(key, ":"),
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700708 value, version);
709 }
710 }
711
712 @Override
713 public long incrementCounter(final IKVTableID tableId, final byte[] key,
714 final long incrementValue) {
715
716 RCTableID rcTableId = (RCTableID) tableId;
717 JRamCloud rcClient = RCClient.getJRamCloudClient();
718
719 try {
720 return rcClient.increment(rcTableId.getTableID(), key, incrementValue);
721 } catch (JRamCloud.ObjectDoesntExistException e) {
722 log.warn("Counter {}-{} was not present",
723 tableId,
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700724 ByteArrayUtil.toHexStringBuilder(key, ":"));
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700725 try {
726 // creating counter initialized to 0
727 createCounter(rcTableId, key, 0L);
728 } catch (ObjectExistsException e1) {
729 // someone concurrently created it
730 log.debug("Counter {}-{} seemed to be concurrently created.",
731 tableId,
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700732 ByteArrayUtil.toHexStringBuilder(key, ":"));
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700733 }
734 try {
735 return rcClient.increment(rcTableId.getTableID(), key, incrementValue);
736 } catch (edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException e1) {
737 log.error("Should never happen");
738 throw new IllegalStateException("Created counter disappeared.");
739 }
740 }
741 }
742
743 @Override
744 public void destroyCounter(final IKVTableID tableId, final byte[] key) {
745
746 RCTableID rcTableId = (RCTableID) tableId;
747 JRamCloud rcClient = RCClient.getJRamCloudClient();
748
749 rcClient.remove(rcTableId.getTableID(), key);
750 }
751
752 @Override
753 public long getCounter(IKVTableID tableId, byte[] key)
754 throws ObjectDoesntExistException {
755
756 IKVEntry entry = read(tableId, key);
757 ByteBuffer counter = ByteBuffer.wrap(entry.getValue()).order(ByteOrder.LITTLE_ENDIAN);
758 return counter.getLong();
759 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700760}