com.spotify.folsom.client.binary.DefaultBinaryMemcacheClient.java Source code

Java tutorial

Introduction

Here is the source code for com.spotify.folsom.client.binary.DefaultBinaryMemcacheClient.java

Source

/*
 * 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 + ")";
    }
}