序
本文次要钻研一下claudb的scripting command
AbstractEvalCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/scripting/AbstractEvalCommand.java
abstract class AbstractEvalCommand implements DBCommand { @Override public RedisToken execute(Database db, Request request) { return script(request).map(script -> execute(request, script)) .getOrElse(error("NOSCRIPT No matching script. Please use EVAL")); } private RedisToken execute(Request request, SafeString script) { int numParams = parseInt(request.getParam(1).toString()); if (numParams + 2 > request.getLength()) { return error("invalid number of arguments"); } List<SafeString> params = request.getParams().stream().skip(2).collect(toList()); List<SafeString> keys = readParams(numParams, params); List<SafeString> argv = readArguments(numParams, params); return LuaInterpreter.buildFor(request).execute(script, keys, argv); } protected abstract Option<SafeString> script(Request request); private List<SafeString> readParams(int numParams, List<SafeString> params) { List<SafeString> keys = new LinkedList<>(); for (int i = 0; i < numParams; i++) { keys.add(params.get(i)); } return keys; } private List<SafeString> readArguments(int numParams, List<SafeString> params) { List<SafeString> argv = new LinkedList<>(); for (int i = numParams; i < params.size(); i++) { argv.add(params.get(i)); } return argv; }}
- AbstractEvalCommand实现了DBCommand接口,其execute办法先通过子类实现的script办法获取SafeString,而后再外部的execute办法执行脚本;execute办法先解析keys、argv,而后通过LuaInterpreter.buildFor(request).execute(script, keys, argv)执行lua脚本
EvalCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/scripting/EvalCommand.java
@Command("eval")@ParamLength(2)public class EvalCommand extends AbstractEvalCommand { @Override protected Option<SafeString> script(Request request) { return Option.some(request.getParam(0)); }}
- EvalCommand继承了AbstractEvalCommand,其script办法取request.getParam(0)
EvalShaCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/scripting/EvalShaCommand.java
@Command("evalsha")@ParamLength(2)public class EvalShaCommand extends AbstractEvalCommand { @Override protected Option<SafeString> script(Request request) { DBServerState server = getServerState(request.getServerContext()); return server.getScript(request.getParam(0)); }}
- EvalShaCommand继承了AbstractEvalCommand,其script办法先通过getServerState(request.getServerContext())获取server,再执行server.getScript(request.getParam(0))
ScriptCommands
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/scripting/ScriptCommands.java
@ParamLength(1)@Command("script")public class ScriptCommands implements DBCommand { @Override public RedisToken execute(Database db, Request request) { return Pattern1.<Request, RedisToken>build() .when(isCommand("load")) .then(this::load) .when(isCommand("exists")) .then(this::exists) .when(isCommand("flush")) .then(this::flush) .otherwise() .then(this::unknownCommand) .apply(request); } private RedisToken unknownCommand(Request request) { return RedisToken.error("Unknown SCRIPT subcommand: " + request.getParam(0)); } private RedisToken load(Request request) { SafeString script = request.getParam(1); return Try.of(() -> digest(script)).map(sha1 -> { DBServerState server = getServerState(request.getServerContext()); server.saveScript(safeString(sha1), script); return RedisToken.string(sha1); }).getOrElse(RedisToken.error("ERR cannot generate sha1 sum for script: " + script)); } private RedisToken exists(Request request) { DBServerState server = getServerState(request.getServerContext()); return integer(server.getScript(request.getParam(1)).isPresent()); } private RedisToken flush(Request request) { getServerState(request.getServerContext()).cleanScripts(); return RedisToken.responseOk(); } private String digest(SafeString script) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("SHA-1"); return new SafeString(digest.digest(script.getBytes())).toHexString(); } private Matcher1<Request> isCommand(String command) { return request -> request.getParam(0).toString().toLowerCase().equals(command); }}
- ScriptCommands实现了DBCommand接口,其execute办法反对load、exists、flush命令;其中load办法通过server.saveScript(safeString(sha1), script)来保留script;其exists办法通过server.getScript(request.getParam(1)).isPresent()来判断script是否存在;其flush办法执行getServerState(request.getServerContext()).cleanScripts()
小结
claudb scripting相干的command有EvalCommand、EvalShaCommand、ScriptCommands
doc
- command/scripting