Java tutorial
/* * Copyright (c) 2014-2015 Spotify AB * * 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 com.spotify.folsom.client.binary; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.spotify.folsom.BinaryMemcacheClient; import com.spotify.folsom.ConnectionChangeListener; import com.spotify.folsom.GetResult; import com.spotify.folsom.MemcacheStatus; import com.spotify.folsom.Metrics; import com.spotify.folsom.RawMemcacheClient; import com.spotify.folsom.Transcoder; import com.spotify.folsom.client.MemcacheEncoder; import com.spotify.folsom.client.OpCode; import com.spotify.folsom.client.TransformerUtil; import com.spotify.folsom.client.Utils; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; /** * The default implementation of {@link com.spotify.folsom.BinaryMemcacheClient} * * @param <V> The value type for all operations */ public class DefaultBinaryMemcacheClient<V> implements BinaryMemcacheClient<V> { private final RawMemcacheClient rawMemcacheClient; private final Metrics metrics; private final Transcoder<V> valueTranscoder; private final TransformerUtil<V> transformerUtil; private final Charset charset; public DefaultBinaryMemcacheClient(final RawMemcacheClient rawMemcacheClient, final Metrics metrics, final Transcoder<V> valueTranscoder, final Charset charset) { this.rawMemcacheClient = rawMemcacheClient; this.metrics = metrics; this.valueTranscoder = valueTranscoder; this.charset = charset; this.transformerUtil = new TransformerUtil<>(valueTranscoder); } /* * @see com.spotify.folsom.BinaryMemcacheClient#set(java.lang.String, V, int) */ @Override public ListenableFuture<MemcacheStatus> set(final String key, final V value, final int ttl) { return setInternal(OpCode.SET, key, value, ttl); } /* * @see com.spotify.folsom.BinaryMemcacheClient#set(java.lang.String, V, int, long) */ @Override public ListenableFuture<MemcacheStatus> set(final String key, final V value, final int ttl, final long cas) { return casSetInternal(OpCode.SET, key, value, ttl, cas); } /* * @see com.spotify.folsom.BinaryMemcacheClient#add(java.lang.String, V, int) */ @Override public ListenableFuture<MemcacheStatus> add(final String key, final V value, final int ttl) { return setInternal(OpCode.ADD, key, value, ttl); } /* * @see com.spotify.folsom.BinaryMemcacheClient#replace(java.lang.String, V, int) */ @Override public ListenableFuture<MemcacheStatus> replace(final String key, final V value, final int ttl) { return setInternal(OpCode.REPLACE, key, value, ttl); } private ListenableFuture<MemcacheStatus> setInternal(final byte opcode, final String key, final V value, final int ttl) { return casSetInternal(opcode, key, value, ttl, 0); } /* * @see com.spotify.folsom.BinaryMemcacheClient#add(java.lang.String, V, int, long) */ @Override public ListenableFuture<MemcacheStatus> add(final String key, final V value, final int ttl, final long cas) { return casSetInternal(OpCode.ADD, key, value, ttl, cas); } /* * @see com.spotify.folsom.BinaryMemcacheClient#replace(java.lang.String, V, int, long) */ @Override public ListenableFuture<MemcacheStatus> replace(final String key, final V value, final int ttl, final long cas) { return casSetInternal(OpCode.REPLACE, key, value, ttl, cas); } private ListenableFuture<MemcacheStatus> casSetInternal(final byte opcode, final String key, final V value, final int ttl, final long cas) { checkNotNull(value); final byte[] valueBytes = valueTranscoder.encode(value); SetRequest request = new SetRequest(opcode, key, charset, valueBytes, ttl, cas); ListenableFuture<MemcacheStatus> future = rawMemcacheClient.send(request); metrics.measureSetFuture(future); return future; } /* * @see com.spotify.folsom.BinaryMemcacheClient#get(java.lang.String) */ @Override public ListenableFuture<V> get(final String key) { return getAndTouch(key, -1); } /* * @see com.spotify.folsom.BinaryMemcacheClient#getAndTouch(java.lang.String, int) */ @Override public ListenableFuture<V> getAndTouch(final String key, final int ttl) { return transformerUtil.unwrap(casGetAndTouch(key, ttl)); } /* * @see com.spotify.folsom.BinaryMemcacheClient#get(java.util.List) */ @Override public ListenableFuture<List<V>> get(final List<String> keys) { return getAndTouch(keys, -1); } /* * @see com.spotify.folsom.BinaryMemcacheClient#casGet(java.lang.String) */ @Override public ListenableFuture<GetResult<V>> casGet(final String key) { return getInternal(key, -1); } private ListenableFuture<GetResult<V>> getInternal(final String key, final int ttl) { final byte opCode = ttl > -1 ? OpCode.GAT : OpCode.GET; GetRequest request = new GetRequest(key, charset, opCode, ttl); final ListenableFuture<GetResult<byte[]>> future = rawMemcacheClient.send(request); metrics.measureGetFuture(future); return transformerUtil.decode(future); } @Override public ListenableFuture<List<GetResult<V>>> casGet(List<String> keys) { return multiget(keys, -1); } private ListenableFuture<List<GetResult<V>>> multiget(List<String> keys, int ttl) { final int size = keys.size(); if (size == 0) { return Futures.immediateFuture(Collections.<GetResult<V>>emptyList()); } final List<List<String>> keyPartition = Lists.partition(keys, MemcacheEncoder.MAX_MULTIGET_SIZE); final List<ListenableFuture<List<GetResult<byte[]>>>> futureList = new ArrayList<>(keyPartition.size()); for (final List<String> part : keyPartition) { MultigetRequest request = MultigetRequest.create(part, charset, ttl); futureList.add(rawMemcacheClient.send(request)); } final ListenableFuture<List<GetResult<byte[]>>> future = Utils.transform(Futures.allAsList(futureList), Utils.<GetResult<byte[]>>flatten()); metrics.measureMultigetFuture(future); return transformerUtil.decodeList(future); } /* * @see com.spotify.folsom.BinaryMemcacheClient#getAndTouch(java.util.List, int) */ @Override public ListenableFuture<List<V>> getAndTouch(final List<String> keys, final int ttl) { return transformerUtil.unwrapList(multiget(keys, ttl)); } /* * @see com.spotify.folsom.BinaryMemcacheClient#casGetAndTouch(java.lang.String, int) */ @Override public ListenableFuture<GetResult<V>> casGetAndTouch(final String key, final int ttl) { return getInternal(key, ttl); } /* * @see com.spotify.folsom.BinaryMemcacheClient#touch(java.lang.String, int) */ @Override public ListenableFuture<MemcacheStatus> touch(final String key, final int ttl) { TouchRequest request = new TouchRequest(key, charset, ttl); ListenableFuture<MemcacheStatus> future = rawMemcacheClient.send(request); metrics.measureTouchFuture(future); return future; } /* * @see com.spotify.folsom.BinaryMemcacheClient#delete(java.lang.String) */ @Override public ListenableFuture<MemcacheStatus> delete(final String key) { DeleteRequest request = new DeleteRequest(key, charset); final ListenableFuture<MemcacheStatus> future = rawMemcacheClient.send(request); metrics.measureDeleteFuture(future); return future; } /* * @see com.spotify.folsom.BinaryMemcacheClient#incr(java.lang.String, long, long, int) */ @Override public ListenableFuture<Long> incr(final String key, final long by, final long initial, final int ttl) { return incrInternal(OpCode.INCREMENT, key, by, initial, ttl); } private ListenableFuture<Long> incrInternal(final byte opcode, final String key, final long by, final long initial, final int ttl) { final ListenableFuture<Long> future = rawMemcacheClient .send(new IncrRequest(key, charset, opcode, by, initial, ttl)); metrics.measureIncrDecrFuture(future); return future; } /* * @see com.spotify.folsom.BinaryMemcacheClient#decr(java.lang.String, long, long, int) */ @Override public ListenableFuture<Long> decr(final String key, final long by, final long initial, final int ttl) { return incrInternal(OpCode.DECREMENT, key, by, initial, ttl); } /* * @see com.spotify.folsom.BinaryMemcacheClient#append(java.lang.String, V) */ @Override public ListenableFuture<MemcacheStatus> append(final String key, final V value) { return casSetInternal(OpCode.APPEND, key, value, 0, 0); } /* * @see com.spotify.folsom.BinaryMemcacheClient#append(java.lang.String, V, long) */ @Override public ListenableFuture<MemcacheStatus> append(final String key, final V value, final long cas) { return casSetInternal(OpCode.APPEND, key, value, 0, cas); } /* * @see com.spotify.folsom.BinaryMemcacheClient#prepend(java.lang.String, V) */ @Override public ListenableFuture<MemcacheStatus> prepend(final String key, final V value) { return casSetInternal(OpCode.PREPEND, key, value, 0, 0); } /* * @see com.spotify.folsom.BinaryMemcacheClient#prepend(java.lang.String, V, long) */ @Override public ListenableFuture<MemcacheStatus> prepend(final String key, final V value, final long cas) { return casSetInternal(OpCode.PREPEND, key, value, 0, cas); } /* * @see com.spotify.folsom.BinaryMemcacheClient#noop() */ @Override public ListenableFuture<Void> noop() { return rawMemcacheClient.send(new NoopRequest()); } /* * @see com.spotify.folsom.BinaryMemcacheClient#shutdown() */ @Override public void shutdown() { rawMemcacheClient.shutdown(); } @Override public void registerForConnectionChanges(ConnectionChangeListener listener) { rawMemcacheClient.registerForConnectionChanges(listener); } @Override public void unregisterForConnectionChanges(ConnectionChangeListener listener) { rawMemcacheClient.registerForConnectionChanges(listener); } /* * @see com.spotify.folsom.BinaryMemcacheClient#isConnected() */ @Override public boolean isConnected() { return rawMemcacheClient.isConnected(); } @Override public int numTotalConnections() { return rawMemcacheClient.numTotalConnections(); } @Override public int numActiveConnections() { return rawMemcacheClient.numActiveConnections(); } @Override public String toString() { return "BinaryMemcacheClient(" + rawMemcacheClient + ")"; } }