-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: floyd supports "Within the same Redis database, a single key name can only have one type of data structure" #2609
feat: floyd supports "Within the same Redis database, a single key name can only have one type of data structure" #2609
Conversation
else if (s_.ToString() == ErrTypeMessage) {
res_.SetRes(CmdRes::kMultiKey);
}
// 修改前:
std::string CachePrefixKeyK = PCacheKeyPrefixK + key_;
db_->cache()->SetBitIfKeyExist(CachePrefixKeyK, bit_offset_, on_);
// 修改后
db_->cache()->SetBitIfKeyExist(key_, bit_offset_, on_);
修改前:
// Keys Commands
int32_t Storage::Expire(const Slice& key, int64_t ttl, std::map<DataType, Status>* type_status) {
type_status->clear();
int32_t ret = 0;
bool is_corruption = false;
auto& inst = GetDBInstance(key);
// Strings
Status s = inst->StringsExpire(key, ttl);
if (s.ok()) {
ret++;
} else if (!s.IsNotFound()) {
is_corruption = true;
(*type_status)[DataType::kStrings] = s;
}
// Hash
s = inst->HashesExpire(key, ttl);
if (s.ok()) {
ret++;
} else if (!s.IsNotFound()) {
is_corruption = true;
(*type_status)[DataType::kHashes] = s;
}
// Sets
s = inst->SetsExpire(key, ttl);
if (s.ok()) {
ret++;
} else if (!s.IsNotFound()) {
is_corruption = true;
(*type_status)[DataType::kSets] = s;
}
// Lists
s = inst->ListsExpire(key, ttl);
if (s.ok()) {
ret++;
} else if (!s.IsNotFound()) {
is_corruption = true;
(*type_status)[DataType::kLists] = s;
}
// Zsets
s = inst->ZsetsExpire(key, ttl);
if (s.ok()) {
ret++;
} else if (!s.IsNotFound()) {
is_corruption = true;
(*type_status)[DataType::kZSets] = s;
}
if (is_corruption) {
return -1;
} else {
return ret;
}
}
修改后
// Keys Commands
int32_t Storage::Expire(const Slice& key, int64_t ttl) {
auto& inst = GetDBInstance(key);
Status s = inst->Expire(key, ttl);
if (s.ok()) {
return 1;
} else if (!s.IsNotFound()) {
return -1;
}
return 1;
}
if (!ExpectedMetaValue(Type::kSet, meta_value)) {
return Status::InvalidArgument("WRONGTYPE Operation against a key holding the wrong kind of value");
} |
@@ -71,17 +71,15 @@ static int migrateKeyTTl(net::NetCli *cli, const std::string& key, storage::Data | |||
const std::shared_ptr<DB>& db) { | |||
net::RedisCmdArgsType argv; | |||
std::string send_str; | |||
std::map<storage::DataType, int64_t> type_timestamp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里为啥把timestape弄没了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成了 int64_t type_timestamp = db->storage()->TTL(key);
因为 key 的类型是唯一的
@@ -8,7 +8,6 @@ | |||
#include "rocksdb/env.h" | |||
|
|||
#include "src/redis.h" | |||
#include "src/strings_filter.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strings_filter.h这个文件现在用不到了吧,删掉吧。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/redis_strings.cc
Outdated
Status Redis::Append(const Slice& key, const Slice& value, int32_t* ret) { | ||
std::string old_value; | ||
*ret = 0; | ||
ScopeRecordLock l(lock_mgr_, key); | ||
|
||
BaseKey base_key(key); | ||
Status s = db_->Get(default_read_options_, base_key.Encode(), &old_value); | ||
if (s.ok() && !ExpectedMetaValue(Type::kString, old_value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ScanStringsKeyNum这个函数在遍历的时候没有判断类型,应该得加上。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/redis_zsets.cc
Outdated
@@ -1038,7 +1106,14 @@ Status Redis::ZScore(const Slice& key, const Slice& member, double* score) { | |||
|
|||
|
|||
BaseMetaKey base_meta_key(key); | |||
Status s = db_->Get(read_options, handles_[kZsetsMetaCF], base_meta_key.Encode(), &meta_value); | |||
Status s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | |||
if (s.ok() && !ExpectedMetaValue(Type::kZset, meta_value) && !ExpectedMetaValue(Type::kSet, meta_value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果s.ok()但是metavalue类型是kset,也是不符合预期的吧。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是因为当时遇到一个这样的TCL样例:
test {ZINTERSTORE regression with two sets, intset+hashtable} {
r del seta setb setc
r sadd set1 a
r sadd set2 10
r zinterstore set3 2 set1 set2
} {0}
简单理解就是 zinterstore 是 Zset
命令但是操作 Set
类型也是可以的
/* | ||
* Because the meta data filtering strategy for list | ||
* is integrated into base_filter.h, we delete it here | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ZSetsScoreFilter,ListsDataFilter等复杂数据类型的data columnfamily 的compactionfilter也需要改下,从meta_index读出数据之后,判断类型是否匹配。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pika_migrate_thread.cc
Outdated
key_type = 'z'; | ||
} else if (type_str[0] == "none") { | ||
} else if (type_str == "none") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
floyd 底层不是也支持存储 stream 数据吗?这里不考虑 stream 类型?
src/pika_slot_command.cc
Outdated
return -3; | ||
} | ||
int64_t type_timestamp = db->storage()->TTL(key); | ||
return type_timestamp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return db->storage()->TTL(key);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/base_value_format.h
Outdated
} | ||
virtual ~InternalValue() { | ||
explicit InternalValue(Type type, const rocksdb::Slice& user_value) : type_(type), user_value_(user_value) { | ||
ctime_ = pstd::NowMicros() / 1000000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1000000 改为 1e6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
// Use this constructor in rocksdb::CompactionFilter::Filter(); | ||
explicit ParsedListsMetaValue(const rocksdb::Slice& internal_value_slice) | ||
: ParsedInternalValue(internal_value_slice) { | ||
assert(internal_value_slice.size() >= kListsMetaValueSuffixLength); | ||
// TODO Why need This judgment logic; Mixficsol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
搞清楚,给个回复
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
解析的字段大小必须要大于最小设置的字段值才开始做解析,不然可能会访问到未定义的内存
src/storage/src/redis_sets.cc
Outdated
if (ExpectedStale(meta_value)) { | ||
s = Status::NotFound(); | ||
} else { | ||
return Status::InvalidArgument("WRONGTYPE Operation against a key holding the wrong kind of value"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是酱紫,你把类似的代码中的错误信息都改下,后面补充进:1 期望的类型;2 实际 get 到的类型
这样方便排查问题
src/storage/src/redis_sets.cc
Outdated
if (ExpectedStale(meta_value)) { | ||
s = Status::NotFound(); | ||
} else { | ||
return Status::InvalidArgument("WRONGTYPE Operation against a key holding the wrong kind of value"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
补全下错误信息
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成 switch
src/storage/src/redis_strings.cc
Outdated
while (iter->Valid()) { | ||
auto meta_type = static_cast<enum Type>(static_cast<uint8_t>(iter->value()[0])); | ||
ParsedBaseMetaKey parsed_meta_key(iter->key().ToString()); | ||
if (meta_type == Type::kString) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成 switch
src/storage/src/redis_zsets.cc
Outdated
if (ExpectedStale(meta_value)) { | ||
s = Status::NotFound(); | ||
} else { | ||
return Status::InvalidArgument("WRONGTYPE Operation against a key holding the wrong kind of value"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 上层比较时,只比较 “WRONGTYPE”;
2 constexpr string InvalidType = "WRONGTYPE xxxxx "
3 return Status::InvalidArgument(InvalidType + ", key %s, get type %s, wanna type %s", base_meta_key0, string(metaValue), string(Type::kSet))
src/storage/src/type_iterator.h
Outdated
bool ShouldSkip() override { | ||
std::string user_value; | ||
auto type = static_cast<Type>(static_cast<uint8_t>(raw_iter_->value()[0])); | ||
if (type == Type::kZset || type == Type::kSet || type == Type::kHash || type == Type::kStream) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改为 switch
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
src/storage/src/redis_strings.cc
Outdated
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); | ||
if (s.ok()) { | ||
auto type = static_cast<Type>(static_cast<uint8_t>(meta_value[0])); | ||
if (type == Type::kSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
src/storage/src/base_filter.h
Outdated
*/ | ||
auto type = static_cast<enum Type>(static_cast<uint8_t>(value[0])); | ||
DEBUG("==========================START=========================="); | ||
if (type == Type::kString) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成 switch
@@ -516,7 +517,7 @@ void MgetCmd::DoInitial() { | |||
|
|||
void MgetCmd::Do() { | |||
db_value_status_array_.clear(); | |||
s_ = db_->storage()->MGetWithTTL(keys_, &db_value_status_array_); | |||
s_ = db_->storage()->MGet(keys_, &db_value_status_array_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里原始接口调用的是 MGetWithTTL,为何改了接口
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
因为在之前在Redis层的Mgetwithtll接口会对非法的多key有报错返回值,但是mget命令如果对于没有类型的key值的话,不会有报错,只会返回nil,所以自己重新实现了一个MGet接口去兼容Redis语义
src/pika_slot_command.cc
Outdated
key_type = "s"; | ||
} else if (type_str[0] == "zset") { | ||
} else if (type_str == "zset") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
少了一个stream吧?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/base_filter.h
Outdated
auto type = static_cast<enum RedisType>(static_cast<uint8_t>(meta_value[0])); | ||
if (type != type_) { | ||
return true; | ||
} else if (type == RedisType::kHash || type == RedisType::kSet || type == RedisType::kStream) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是不是还有zset data类型?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/lists_filter.h
Outdated
auto type = static_cast<enum RedisType>(static_cast<uint8_t>(meta_value[0])); | ||
if (type != type_) { | ||
return true; | ||
} else if (type == RedisType::kList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
list的datafilter只有一种类型,所以我理解这里只判断type是否等于type_,其他的else不需要了。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/storage/src/lists_filter.h
Outdated
ParsedListsMetaValue parsed_lists_meta_value(&meta_value); | ||
cur_meta_version_ = parsed_lists_meta_value.Version(); | ||
cur_meta_etime_ = parsed_lists_meta_value.Etime(); | ||
auto type = static_cast<enum RedisType>(static_cast<uint8_t>(meta_value[0])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
有一种情况是:
- 一个list data类型的key记为l1,从meta里获取元信息,发现类型不对,然后直接返回true了。
- compaction iterator继续迭代有发现了一个l2,同属于同一个list。此时它不会去读meta元信息,因为cur_key_等于meta_key_enc,这时它会继续走后边比对时间戳和version的逻辑,但此时的时间戳和version值是不准确的。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -1242,7 +1242,7 @@ int64_t Storage::Scan(const DataType& dtype, int64_t cursor, const std::string& | |||
LOG(WARNING) << "Invalid key_type: " << key_type; | |||
return 0; | |||
} | |||
std::copy(pos, iter_end, std::back_inserter(types)); | |||
std::copy(pos, iter_end - 2, std::back_inserter(types)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个地方为什么减2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是因为之前DataType类型只有all+五种数据类型,然后现在我复用了这个DataType需要加一个none类型,然后-2是因为之前可以直接到迭代器尾端,但是现在得在末端前两个
src/pika_kv.cc
Outdated
@@ -224,19 +222,15 @@ void DelCmd::DoUpdateCache() { | |||
if (s_.ok()) { | |||
std::vector<std::string> v; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里既然只存在一种类型,那直接delete key就好了,没必要用v转换一下
src/pika_list.cc
Outdated
@@ -663,6 +676,10 @@ void BRPopCmd::Do() { | |||
return; | |||
} else if (s_.IsNotFound()) { | |||
continue; | |||
} else if (s_.IsInvalidArgument()) { | |||
// TODO use return or continue; Mixficsol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里确认了 就把注释删了吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
…me can only have one type of data structure" (OpenAtomFoundation#2609) * floyd supports one key for one data structure * Modified the criteria for determining multiple keys
…me can only have one type of data structure" (OpenAtomFoundation#2609) * floyd supports one key for one data structure * Modified the criteria for determining multiple keys
…me can only have one type of data structure" (OpenAtomFoundation#2609) * floyd supports one key for one data structure * Modified the criteria for determining multiple keys
…me can only have one type of data structure" (OpenAtomFoundation#2609) * floyd supports one key for one data structure * Modified the criteria for determining multiple keys
背景
当前
Pika
的一个Key
可以对应多种数据结构,和Redis
不一致解决方案
在
Floyd
现有的设计之上,将之前String
类型所在的Column-Family
用于存放所有的Key
的Meta
信息kMetaCF 字段设计
修改前
String
Hash
List
set
zset
Stream
修改后
我们对每一种数据类型的
Meta
的value
前增加一个字段Type
用于区别每个Key
对应的数据结构以
Set
类型举例String 的 Meta 格式
在解析的时候,先解析头部的第一个字节,然后根据类型判断是否需要继续解析下去