/** * Copyright 2018 Nikita Koksharov * * 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.fr.third.org.redisson; import java.util.Collections; import java.util.concurrent.TimeUnit; import com.fr.third.org.redisson.api.RBucket; import com.fr.third.org.redisson.api.RFuture; import com.fr.third.org.redisson.client.codec.Codec; import com.fr.third.org.redisson.client.protocol.RedisCommands; import com.fr.third.org.redisson.api.RBucket; import com.fr.third.org.redisson.api.RFuture; import com.fr.third.org.redisson.client.codec.Codec; import com.fr.third.org.redisson.client.protocol.RedisCommands; import com.fr.third.org.redisson.command.CommandAsyncExecutor; /** * * @author Nikita Koksharov * * @param value type */ public class RedissonBucket extends RedissonExpirable implements RBucket { public RedissonBucket(CommandAsyncExecutor connectionManager, String name) { super(connectionManager, name); } public RedissonBucket(Codec codec, CommandAsyncExecutor connectionManager, String name) { super(codec, connectionManager, name); } @Override public boolean compareAndSet(V expect, V update) { return get(compareAndSetAsync(expect, update)); } @Override public RFuture compareAndSetAsync(V expect, V update) { if (expect == null && update == null) { return trySetAsync(null); } if (expect == null) { return trySetAsync(update); } if (update == null) { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, "if redis.call('get', KEYS[1]) == ARGV[1] then " + "redis.call('del', KEYS[1]); " + "return 1 " + "else " + "return 0 end", Collections.singletonList(getName()), encode(expect)); } return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, "if redis.call('get', KEYS[1]) == ARGV[1] then " + "redis.call('set', KEYS[1], ARGV[2]); " + "return 1 " + "else " + "return 0 end", Collections.singletonList(getName()), encode(expect), encode(update)); } @Override public V getAndSet(V newValue) { return get(getAndSetAsync(newValue)); } @Override public RFuture getAndSetAsync(V newValue) { if (newValue == null) { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_OBJECT, "local v = redis.call('get', KEYS[1]); " + "redis.call('del', KEYS[1]); " + "return v", Collections.singletonList(getName())); } return commandExecutor.writeAsync(getName(), codec, RedisCommands.GETSET, getName(), encode(newValue)); } @Override public V get() { return get(getAsync()); } @Override public RFuture getAsync() { return commandExecutor.readAsync(getName(), codec, RedisCommands.GET, getName()); } @Override public V getAndDelete() { return get(getAndDeleteAsync()); } @Override public RFuture getAndDeleteAsync() { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_OBJECT, "local currValue = redis.call('get', KEYS[1]); " + "redis.call('del', KEYS[1]); " + "return currValue; ", Collections.singletonList(getName())); } @Override public long size() { return get(sizeAsync()); } @Override public RFuture sizeAsync() { return commandExecutor.readAsync(getName(), codec, RedisCommands.STRLEN, getName()); } @Override public void set(V value) { get(setAsync(value)); } @Override public RFuture setAsync(V value) { if (value == null) { return commandExecutor.writeAsync(getName(), RedisCommands.DEL_VOID, getName()); } return commandExecutor.writeAsync(getName(), codec, RedisCommands.SET, getName(), encode(value)); } @Override public void set(V value, long timeToLive, TimeUnit timeUnit) { get(setAsync(value, timeToLive, timeUnit)); } @Override public RFuture setAsync(V value, long timeToLive, TimeUnit timeUnit) { if (value == null) { throw new IllegalArgumentException("Value can't be null"); } return commandExecutor.writeAsync(getName(), codec, RedisCommands.PSETEX, getName(), timeUnit.toMillis(timeToLive), encode(value)); } @Override public RFuture trySetAsync(V value) { if (value == null) { return commandExecutor.readAsync(getName(), codec, RedisCommands.NOT_EXISTS, getName()); } return commandExecutor.writeAsync(getName(), codec, RedisCommands.SETNX, getName(), encode(value)); } @Override public RFuture trySetAsync(V value, long timeToLive, TimeUnit timeUnit) { if (value == null) { throw new IllegalArgumentException("Value can't be null"); } return commandExecutor.writeAsync(getName(), codec, RedisCommands.SETPXNX, getName(), encode(value), "PX", timeUnit.toMillis(timeToLive), "NX"); } @Override public boolean trySet(V value, long timeToLive, TimeUnit timeUnit) { return get(trySetAsync(value, timeToLive, timeUnit)); } @Override public boolean trySet(V value) { return get(trySetAsync(value)); } }