1、发布与订阅
发布与订阅功能有PUBLISH、SUBSCRIBE、PSUBSCRIBE(正则订阅,订阅某个模式)等命令组成。例如SUBSCRIBE "news.it"、PUBLISH "news.it" "hello"、PSUBSCRIBE "news.[ie]t"等。
struct redisServer{
// 保存所有频道的订阅关系,Map>
dict *pubsub channels;
// 保存所有模式的订阅关系
list *pubsub patterns;
};
频道的订阅是一个频道名字—客户端链表的字典,模式的订阅是一个链表,每个节点都是一个pubsub.Pattern结构。当某个客户端退订模式、将消息发送给某个模式时,需要遍历模式的链表list *pubsub patterns。
typedef struct pubsubPattern{
// 订阅模式的客户端
redisClient *client;
// 被订阅的模式
robj *pattern;
} pubsubPattern;
还有一些查看订阅信息的命令,PUBSUB CHANNELS [pattern]返回服务器被订阅的频道;PUBSUB NUMSUB [channel-1 channel-2 … channel-n]返回这些频道的订阅者数量;PUBSUB NUMPAT返回订阅模式的数量,即链表的长度。
2、事务
Redis通过MULTI、WATCH、EXEC等命令实现事务,用单线程的方式执行事务,事务执行时不执行其他客户端的请求。MULTI开始事务,EXEC提交事务。执行事务时,EXEC、DISCARD、WATCH、MULTI命令立即执行,否则将命令放入事务队列,向客户端返回QUEUED回复。EXEC时,服务器遍历客户端的十五队列,执行所有命令,返回所有结果。每个Redis客户端有自己的事务状态,保存在redisClient.mstate里,mstate包含一个事务队列和一个已入队命令的计数器。
WATCH命令是一个乐观锁,可以在EXEC执行前,监视任意数量的键,如果EXEC执行时有一个被修改了,服务器拒绝执行事务,redisDb.watched_keys字典表示正在被监视的键,是一个Map<监视的键,List
原子性:Redis不支持事务回滚机制,因为与Redis简单高效的设计主旨不符。即使事务队列的某个命令执行时错误,事务也会继续执行;
一致性:事务中有不存在的命令,服务器拒绝执行事务;执行中发生错误(类型错误),服务器不会中断执行,执行完所有命令,返回所有结果,其中包含了错误信息;
隔离性:单线程保证了隔离性;
耐久性:由持久化模式决定,只有使用AOF并且appendfsync为always时才具有耐久性;
3、排序
SORT命令对列表键、集合键或者有序集合键进行排序;
SORT
SORT
ASC、DESC升序降序排序,利用快速排序;
使用BY选项,SORT可以指定某些字符串键,或者某些哈希键的域作为元素权重来排序;如下,MSET可以同时设置多个键值对,'*'表示fruits中的一个元素;
LIMIT
GET,例如SORT students ALPHA GET *-name获取每个学生名字+“-name”的键;
STORE,将排序结果保存在某个键里,SORT students ALPHA STORE sorted_students;
4、二进制位数组
提供了SETBIT,GETBIT,BITCOUNT,BITOP四个命令,位图用字符串表示;
SETBIT bit 0 1,将键bit的第0位(从右往左)设置为1;
GETBIT bit 0,获取键bit第0位;
BITCOUNT bit,统计1的数量,用到了variable-precision SWAR算法,就是Integer.bitCount()使用的算法。先计算相邻两位的1的个数,记在这两位上,再计算4位、8位,依次类推;
public static int bitCount(int i) {
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
BITOP,进行&,|,^操作, BITOP AND[OR, XOR] result x y,将计算结果保存在result里;也可以用BITOP NOT not-result x取反;