聊聊claudb的zset command
序
本文主要研究一下zset command
SortedSetAddCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetAddCommand.java
@Command("zadd")
@ParamLength(3)
@ParamType(DataType.ZSET)
public class SortedSetAddCommand implements DBCommand {
@Override
public RedisToken execute(Database db, Request request) {
try {
DatabaseValue initial = db.getOrDefault(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET);
DatabaseValue result = db.merge(safeKey(request.getParam(0)), parseInput(request),
(oldValue, newValue) -> {
Set<Entry<Double, SafeString>> merge = new SortedSet();
merge.addAll(oldValue.getSortedSet());
merge.addAll(newValue.getSortedSet());
return zset(merge);
});
return integer(changed(initial.getSortedSet(), result.getSortedSet()));
} catch (NumberFormatException e) {
return error("ERR value is not a valid float");
}
}
private int changed(Set<Entry<Double, SafeString>> input, Set<Entry<Double, SafeString>> result) {
return result.size() - input.size();
}
private DatabaseValue parseInput(Request request) {
Set<Entry<Double, SafeString>> set = new SortedSet();
SafeString score = null;
for (SafeString string : request.getParams().stream().skip(1).collect(toList())) {
if (score != null) {
set.add(score(parseFloat(score.toString()), string));
score = null;
} else {
score = string;
}
}
return zset(set);
}
}
- SortedSetAddCommand实现了DBCommand接口,其execute方法先获取initial,然后执行db.merge方法,它先添加oldValue.getSortedSet()、再添加newValue.getSortedSet()
SortedSetCardinalityCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetCardinalityCommand.java
@ReadOnly
@Command("zcard")
@ParamLength(1)
@ParamType(DataType.ZSET)
public class SortedSetCardinalityCommand implements DBCommand {
@Override
public RedisToken execute(Database db, Request request) {
DatabaseValue value = db.getOrDefault(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET);
Set<Entry<Double, SafeString>> set = value.getSortedSet();
return integer(set.size());
}
}
- SortedSetCardinalityCommand实现了DBCommand接口,其execute方法先通过db.getOrDefault获取value,在获取value.getSortedSet()
SortedSetRemoveCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetRemoveCommand.java
@Command("zrem")
@ParamLength(2)
@ParamType(DataType.ZSET)
public class SortedSetRemoveCommand implements DBCommand {
@Override
public RedisToken execute(Database db, Request request) {
List<SafeString> items = request.getParams().stream().skip(1).collect(toList());
List<SafeString> removed = new LinkedList<>();
db.merge(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET,
(oldValue, newValue) -> {
Set<Entry<Double, SafeString>> merge = new SortedSet();
merge.addAll(oldValue.getSortedSet());
for (SafeString item : items) {
if (merge.remove(score(0, item))) {
removed.add(item);
}
}
return zset(merge);
});
return integer(removed.size());
}
}
- SortedSetRemoveCommand实现了DBCommand接口,其execute方法先从request参数提取items,然后执行db.merge,该方法遍历items挨个执行merge.remove(score(0, item))
SortedSetRangeCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetRangeCommand.java
@ReadOnly
@Command("zrange")
@ParamLength(3)
@ParamType(DataType.ZSET)
public class SortedSetRangeCommand implements DBCommand {
private static final String PARAM_WITHSCORES = "WITHSCORES";
@Override
public RedisToken execute(Database db, Request request) {
try {
DatabaseValue value = db.getOrDefault(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET);
NavigableSet<Entry<Double, SafeString>> set = value.getSortedSet();
int from = Integer.parseInt(request.getParam(1).toString());
if (from < 0) {
from = set.size() + from;
}
int to = Integer.parseInt(request.getParam(2).toString());
if (to < 0) {
to = set.size() + to;
}
List<Object> result = emptyList();
if (from <= to) {
Option<SafeString> withScores = request.getOptionalParam(3);
if (withScores.isPresent() && withScores.get().toString().equalsIgnoreCase(PARAM_WITHSCORES)) {
result = set.stream().skip(from).limit((to - from) + 1l)
.flatMap(entry -> Stream.of(entry.getValue(), entry.getKey())).collect(toList());
} else {
result = set.stream().skip(from).limit((to - from) + 1l)
.map(Entry::getValue).collect(toList());
}
}
return convert(result);
} catch (NumberFormatException e) {
return error("ERR value is not an integer or out of range");
}
}
}
- SortedSetRangeCommand实现了DBCommand接口,其execute方法执行db.getOrDefault获取value,然后通过set.stream().skip(from).limit((to - from) + 1l)获取result
SortedSetRangeByScoreCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetRangeByScoreCommand.java
@ReadOnly
@Command("zrangebyscore")
@ParamLength(3)
@ParamType(DataType.ZSET)
public class SortedSetRangeByScoreCommand implements DBCommand {
private static final String EXCLUSIVE = "(";
private static final String MINUS_INFINITY = "-inf";
private static final String INIFITY = "+inf";
private static final String PARAM_WITHSCORES = "WITHSCORES";
private static final String PARAM_LIMIT = "LIMIT";
@Override
public RedisToken execute(Database db, Request request) {
try {
DatabaseValue value = db.getOrDefault(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET);
NavigableSet<Entry<Double, SafeString>> set = value.getSortedSet();
float from = parseRange(request.getParam(1).toString());
float to = parseRange(request.getParam(2).toString());
Options options = parseOptions(request);
Set<Entry<Double, SafeString>> range = set.subSet(
score(from, SafeString.EMPTY_STRING), inclusive(request.getParam(1)),
score(to, SafeString.EMPTY_STRING), inclusive(request.getParam(2)));
List<Object> result = emptyList();
if (from <= to) {
if (options.withScores) {
result = range.stream().flatMap(
entry -> Stream.of(entry.getValue(), entry.getKey())).collect(toList());
} else {
result = range.stream().map(Entry::getValue).collect(toList());
}
if (options.withLimit) {
result = result.stream().skip(options.offset).limit(options.count).collect(toList());
}
}
return convert(result);
} catch (NumberFormatException e) {
return error("ERR value is not an float or out of range");
}
}
private Options parseOptions(Request request) {
Options options = new Options();
for (int i = 3; i < request.getLength(); i++) {
String param = request.getParam(i).toString();
if (param.equalsIgnoreCase(PARAM_LIMIT)) {
options.withLimit = true;
options.offset = parseInt(request.getParam(++i).toString());
options.count = parseInt(request.getParam(++i).toString());
} else if (param.equalsIgnoreCase(PARAM_WITHSCORES)) {
options.withScores = true;
}
}
return options;
}
private boolean inclusive(SafeString param) {
return !param.toString().startsWith(EXCLUSIVE);
}
private float parseRange(String param) {
switch (param) {
case INIFITY:
return Float.MAX_VALUE;
case MINUS_INFINITY:
return Float.MIN_VALUE;
default:
if (param.startsWith(EXCLUSIVE)) {
return Float.parseFloat(param.substring(1));
}
return Float.parseFloat(param);
}
}
private static class Options {
private boolean withScores;
private boolean withLimit;
private int offset;
private int count;
}
}
- SortedSetRangeByScoreCommand实现了DBCommand接口,其execute方法执行db.getOrDefault获取value,然后通过set.subSet(score(from, SafeString.EMPTY_STRING), inclusive(request.getParam(1)),score(to, SafeString.EMPTY_STRING), inclusive(request.getParam(2)))获取range,最后从range提取result
SortedSetReverseRangeCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetReverseRangeCommand.java
@ReadOnly
@Command("zrevrange")
@ParamLength(3)
@ParamType(DataType.ZSET)
public class SortedSetReverseRangeCommand implements DBCommand {
private static final String PARAM_WITHSCORES = "WITHSCORES";
@Override
public RedisToken execute(Database db, Request request) {
try {
DatabaseValue value = db.getOrDefault(safeKey(request.getParam(0)), DatabaseValue.EMPTY_ZSET);
NavigableSet<Entry<Double, SafeString>> set = value.getSortedSet();
int from = Integer.parseInt(request.getParam(2).toString());
if (from < 0) {
from = set.size() + from;
}
int to = Integer.parseInt(request.getParam(1).toString());
if (to < 0) {
to = set.size() + to;
}
List<Object> result = emptyList();
if (from <= to) {
Option<SafeString> withScores = request.getOptionalParam(3);
if (withScores.isPresent() && withScores.get().toString().equalsIgnoreCase(PARAM_WITHSCORES)) {
result = set.stream().skip(from).limit((to - from) + 1l)
.flatMap(item -> Stream.of(item.getValue(), item.getKey())).collect(toList());
} else {
result = set.stream().skip(from).limit((to - from) + 1l)
.map(Entry::getValue).collect(toList());
}
}
reverse(result);
return convert(result);
} catch (NumberFormatException e) {
return error("ERR value is not an integer or out of range");
}
}
}
- SortedSetReverseRangeCommand实现了DBCommand接口,其execute方法执行db.getOrDefault获取value,然后通过set.stream().skip(from).limit((to - from) + 1l)获取result
SortedSetIncrementByCommand
claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/zset/SortedSetIncrementByCommand.java
@Command("zincrby")
@ParamLength(3)
@ParamType(DataType.ZSET)
public class SortedSetIncrementByCommand implements DBCommand {
@Override
public RedisToken execute(Database db, Request request) {
try {
DatabaseKey zkey = safeKey(request.getParam(0));
DatabaseValue value = db.getOrDefault(zkey, DatabaseValue.EMPTY_ZSET);
NavigableSet<Entry<Double, SafeString>> set = value.getSortedSet();
SafeString key = request.getParam(2);
Double increment = Double.parseDouble(request.getParam(1).toString());
Entry<Double, SafeString> newValue = merge(set, key, increment);
SortedSet result = new SortedSet();
result.addAll(set);
result.remove(newValue);
result.add(newValue);
db.put(zkey, zset(result));
return string(newValue.getKey().toString());
} catch (NumberFormatException e) {
return error("ERR value is not an integer or out of range");
}
}
private Entry<Double, SafeString>
merge(NavigableSet<Entry<Double, SafeString>> set, SafeString key, Double increment) {
return score(findByKey(set, key).getKey() + increment, key);
}
private Entry<Double, SafeString> findByKey(NavigableSet<Entry<Double, SafeString>> set, SafeString key) {
// TODO: O(n) search, to fix forget the NavigableSet and use directly the SortedSet to get by key
return set.stream().filter(entry -> entry.getValue().equals(key)).findFirst().orElse(score(0, key));
}
}
- SortedSetIncrementByCommand实现了DBCommand接口,其execute方法执行db.getOrDefault获取value,然后通过merge获取newValue
小结
claudb sorted set相关的command有SortedSetAddCommand、SortedSetCardinalityCommand、SortedSetRemoveCommand、SortedSetRangeCommand、SortedSetRangeByScoreCommand、SortedSetReverseRangeCommand、SortedSetIncrementByCommand
doc
- hadoop系列之深入优化
- Using sqlite with .NET
- Gridview行上下移动自己做的一个小例子(第一种方法)
- Hadoop伪分布式集群安装部署
- sql 表有没有自增列,插入自增列值
- jsp中的JSTL与EL表达式用法及区别(二)
- WPF 给控件添加复制事作
- wpf RoutedUICommand 绑定
- jsp中的JSTL与EL表达式用法及区别(一)
- java线程池模型
- lock小记
- HTML布局的基本要点
- Building a Middle Tier Component using NHibernate and Spring.NET
- Linq 和DefaultView两种方法去掉DataTable 里的重复行
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 全网最详细的一篇Flutter 尺寸限制类容器总结
- 一篇带你看懂Flutter叠加组件Stack
- Flutter 拖拽排序组件 ReorderableListView
- 女神节 | 程序员如何低调而又不失逼格
- Flutter 拖拽控件Draggable看这一篇就够了
- 面试官:你精通多少种语言的Hello World?
- Flutter 裁剪类组件 最全总结
- Flutter Form表单控件超全总结
- 你知道吗,Flutter内置了10多种Button控件
- Flutter 日期时间DatePicker控件及国际化
- 强大的Flutter App升级功能
- 你知道吗,Flutter内置了10多种show
- 还记得第一个看到的Flutter组件吗?
- 150多个Flutter组件详细介绍送给你
- Flutter 学习路线图