背景
从节点收到 Bitop 这样的命令之后,要再次读取后面的 key 对应的内容进行运算,但是没法保证从节点使用这两个 key 读取到的内容就和 master 读到的内容一样,会导致 slave 得到的运算结果和 master 不一致(结果存进 dest_key,会导致主从的dest_key不一致)
命令:Bitop
命令介绍:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
1 | redis> SET key1 "foobar" |
修改方案
binlog 改成了一条 set 的 binlog,写成了: set key result_to_dest (注: result_to_dest就是后面使用后面的key得到的运算结果,也就是存到了第一个 key 中的内容)
修改代码前后对比
include/pika_bit.h +126
修改前:
修改后:
这里新增了 Bitop 拷贝构造函数和 DoBinlog 函数,以及需要新加的 value_to_dest 这个最终要写到 binlog 里面的参数,这里写了拷贝构造函数是因为使用默认的拷贝构造会导致多个 bitop 命令并发的时候,他们都用了同一个set 命令的实例,会有线程安全问题。DoBinlog 函数就是让程序执行 DoBinlog 的时候不使用基类 Cmd 的DoBinlog 而是使用子类覆写的 Binlog,current_key() 这个函数把需要锁的 key 传过来。
src/pika_bit.cc +211
修改前:
修改后:
这里在 Bitop 方法里面新增了 value_to_dest 这个参数,并且实现了 DoBinlog 这个函数,这里PikaCmdArgsType 的这个参数 set_args 本质是一个 std::vector<std::string>
,这里我们把命令” set “,存储目标 “ dest_key “,运算结果” value_to_dest “放到这个 vector 里面,这里相当于 bitop 计算出来后的值当做 set 命令的 value, set_cmd_ 这个是一个指向 SetCmd 类的一个智能指针,然后进行初始化流程,最后调用基类 Cmd 的DoBinlog 完成流程
src/storage/include/storage/storage.h +223
修改前:
修改后:
src/storage/src/redis_strings.cc +291
修改前:
修改后:
这里多个 value_to_dest 参数,把 BitOpOperate 计算出来的值传给 value_to_dest
src/storage/src/redis_strings.h +35
修改前:
修改后:
相关 PR: #1658
相关 Issue: #1638