001/*
002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.redis;
020
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import redis.clients.jedis.exceptions.JedisDataException;
026import redis.clients.jedis.exceptions.JedisException;
027
028/**
029 * Abstract implementation of a {@link RedisExecutor}.
030 * <p>
031 * This base implementation collects the loaded scripts to be able to re-load them if the server has been restarted and
032 * has lost them.
033 *
034 * @since 8.10
035 */
036public abstract class RedisAbstractExecutor implements RedisExecutor {
037
038    private static final String ERROR_PREFIX_NOSCRIPT = "NOSCRIPT";
039
040    protected Map<String, String> scripts = new HashMap<>();
041
042    @Override
043    public String scriptLoad(String script) throws JedisException {
044        String sha1 = execute(jedis -> jedis.scriptLoad(script));
045        scripts.put(sha1, script);
046        return sha1;
047    }
048
049    @Override
050    public Object evalsha(String sha1, List<String> keys, List<String> args) throws JedisException {
051        try {
052            return execute(jedis -> jedis.evalsha(sha1, keys, args));
053        } catch (JedisDataException e) {
054            if (!e.getMessage().startsWith(ERROR_PREFIX_NOSCRIPT)) {
055                throw e;
056            }
057            // re-load the script
058            String script = scripts.get(new String(sha1));
059            if (script == null) {
060                throw e;
061            }
062            execute(jedis -> jedis.scriptLoad(script));
063            // retry once
064            return execute(jedis -> jedis.evalsha(sha1, keys, args));
065        }
066    }
067
068    @Override
069    public Object evalsha(byte[] sha1, List<byte[]> keys, List<byte[]> args) throws JedisException {
070        try {
071            return execute(jedis -> jedis.evalsha(sha1, keys, args));
072        } catch (JedisDataException e) {
073            if (!e.getMessage().startsWith(ERROR_PREFIX_NOSCRIPT)) {
074                throw e;
075            }
076            // re-load the script
077            String script = scripts.get(new String(sha1));
078            if (script == null) {
079                throw e;
080            }
081            execute(jedis -> jedis.scriptLoad(script));
082            // retry once
083            return execute(jedis -> jedis.evalsha(sha1, keys, args));
084        }
085    }
086
087}