-
Notifications
You must be signed in to change notification settings - Fork 472
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: add support of the command JSON.DEBUG MEMORY #2323
Conversation
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.
Another problem is that, should we emit the memory size ( And memory size might larger than str size ) or just export the size on disk?
src/commands/cmd_json.cc
Outdated
std::string path = "$"; | ||
|
||
if (!util::EqualICase(args_[1], "memory")) { | ||
return {Status::RedisExecErr, "The number of arguments is more than expected"}; |
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.
why this is number more than expected?
src/types/redis_json.cc
Outdated
@@ -626,5 +626,17 @@ std::vector<rocksdb::Status> Json::readMulti(const std::vector<Slice> &ns_keys, | |||
} | |||
return statuses; | |||
} | |||
rocksdb::Status Json::DebugMemory(const std::string &user_key, const std::string &path, Optionals<uint64_t> *results) { |
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.
format or adding a space between them?
src/types/json.h
Outdated
if (!origin.empty()) { | ||
// This is only a rough calculation of the size of the string size char, not the entire byte occupied by | ||
// the object | ||
results.emplace_back(origin.as_string().size() * sizeof(std::string::value_type)); |
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.
Could this json_query matches more than 1 element?
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.
There are several issues in this implemetation:
- the result of
as_string().size()
is not equal to the real size, we should at least useto_string()
- but actually
to_string
is also wrong, since it maybe not equal to the result ofcompact_json_string_encoder
. also it would be totally wrong if CBOR format is enabled. - there may be multiple location found from one jsonpath, which is not handled in this impl
- if jsonpath is
$
, no json decoding is required
Thank you for your help. The modifications have been completed, please help me take a look again |
src/types/json.h
Outdated
value, path, | ||
[&results, max_nesting_depth, format](const std::string & /*path*/, const jsoncons::json &origin) { | ||
if (!origin.empty()) { | ||
Status s; |
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.
Is it useful here?
src/types/json.h
Outdated
origin.dump(encoder, ec); | ||
} else if (format == JsonStorageFormat::CBOR) { | ||
jsoncons::cbor::cbor_options options; | ||
options.max_nesting_depth(max_nesting_depth); | ||
jsoncons::cbor::basic_cbor_encoder<jsoncons::string_sink<std::string>> encoder{buffer, options}; | ||
origin.dump(encoder, ec); |
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.
Please use the exception version of dump
and catch it later.
src/types/json.h
Outdated
@@ -217,6 +217,42 @@ struct JsonValue { | |||
return results; | |||
} | |||
|
|||
StatusOr<Optionals<uint64_t>> StrBytes(std::string_view path, JsonStorageFormat format, |
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.
Is optional
useful here? Could we just use vector
?
src/types/json.h
Outdated
@@ -217,6 +217,42 @@ struct JsonValue { | |||
return results; | |||
} | |||
|
|||
StatusOr<Optionals<uint64_t>> StrBytes(std::string_view path, JsonStorageFormat format, |
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.
StatusOr<Optionals<uint64_t>> StrBytes(std::string_view path, JsonStorageFormat format, | |
StatusOr<Optionals<uint64_t>> GetBytes(std::string_view path, JsonStorageFormat format, |
src/types/redis_json.cc
Outdated
Slice rest; | ||
auto s = GetMetadata(GetOptions{}, {kRedisJson}, ns_key, &bytes, &metadata, &rest); | ||
if (!s.ok()) return s; | ||
results->emplace_back(bytes.size()); |
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.
results->emplace_back(bytes.size()); | |
results->emplace_back(rest.size()); |
src/types/json.h
Outdated
@@ -217,6 +217,42 @@ struct JsonValue { | |||
return results; | |||
} | |||
|
|||
StatusOr<std::vector<std::string>> GetBytes(std::string_view path, JsonStorageFormat format, |
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.
Why vector<string>
instead of vector<size_t>
?
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.
Because currently ArrayOfBulkStrings only supports string types, if modified to a template, it cannot meet the writing requirements of std:: initializer_list. Do you suggest that I add another method, std: vector<size_t>?
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.
You can use a loop to dump RESP output. It doesn't matter whether you use ArrayOfBulkStrings or not.
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.
ok thanks
src/types/json.h
Outdated
try { | ||
jsoncons::jsonpath::json_query(value, path, [&](const std::string & /*path*/, const jsoncons::json &origin) { | ||
if (!origin.empty()) { | ||
Status s; |
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.
Is s
really useful here? (I have to ask again)
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.
This function is used to traverse the internal structure of JSON and will loop through the callback function multiple times inside
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.
I mean the variable s
.
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.
i see
src/types/json.h
Outdated
if (format == JsonStorageFormat::JSON) { | ||
jsoncons::json_options options; | ||
options.max_nesting_depth(max_nesting_depth); | ||
jsoncons::compact_json_string_encoder encoder{buffer, options}; | ||
origin.dump(encoder, ec); | ||
} else if (format == JsonStorageFormat::CBOR) { | ||
jsoncons::cbor::cbor_options options; | ||
options.max_nesting_depth(max_nesting_depth); | ||
jsoncons::cbor::basic_cbor_encoder<jsoncons::string_sink<std::string>> encoder{buffer, options}; | ||
origin.dump(encoder, ec); | ||
} |
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.
Please use Dump
and DumpCBOR
.
src/types/json.h
Outdated
if (ec) { | ||
throw std::system_error(ec); | ||
} |
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.
Please remove it.
var result2 = make([]interface{}, 0) | ||
result2 = append(result2, int64(4), int64(6), int64(2)) | ||
require.Equal(t, rdb.Do(ctx, "JSON.DEBUG", "MEMORY", "a", "$..a").Val(), result2) | ||
require.ErrorIs(t, rdb.Do(ctx, "JSON.DEBUG", "MEMORY", "not_exists", "$").Err(), redis.Nil) |
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.
Could you add more test cases? e.g. for a valid $
, or a number/array/object, or a non-existent path.
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.
Okay, I will add all the testcases
src/types/json.h
Outdated
std::vector<std::string> results; | ||
try { | ||
jsoncons::jsonpath::json_query(value, path, [&](const std::string & /*path*/, const jsoncons::json &origin) { | ||
if (!origin.empty()) { |
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.
What's the meaning of this empty check?
Could you think about whether an empty JSON array/object will occupy storage space?
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.
Empty arrays and nulls actually take up space, and the test cases have been supplemented. Please see if there are any areas that can be optimized
src/commands/cmd_json.cc
Outdated
@@ -45,6 +45,14 @@ std::string OptionalsToString(const Connection *conn, Optionals<T> &opts) { | |||
return str; | |||
} | |||
|
|||
std::string SizeToString(const std::vector<std::size_t> &elems) { | |||
std::string result = "*" + std::to_string(elems.size()) + CRLF; |
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.
You can use MultiLen
here.
src/commands/cmd_json.cc
Outdated
auto s = json.DebugMemory(args_[2], path, &results); | ||
|
||
if (s.IsNotFound()) { | ||
*output = conn->NilString(); |
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.
It's wrong. For nonexistent key, the result is 0
.
Please confirm with redis-stack and redis-cli by yourself.
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/types/json.h
Outdated
if (results.size() == 0) { | ||
results.emplace_back(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.
It's wrong.
Please use redis-stack and redis-cli to confirm the correct result for this case.
std::vector<size_t> results; | ||
Status s; | ||
try { | ||
jsoncons::jsonpath::json_query(value, path, [&](const std::string & /*path*/, const jsoncons::json &origin) { |
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.
jsoncons::jsonpath::json_query(value, path, [&](const std::string & /*path*/, const jsoncons::json &origin) { | |
jsoncons::jsonpath::json_query(value, path, [&](const std::string & /*path*/, const jsoncons::json &origin) { | |
if (!s) return; |
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.
Hello, I have two questions I would like to ask. 1. When does the status initialization fail and needs to be returned in advance? 2. Currently, obtaining the byte is still inaccurate, and the actual value should be larger than the encoded string. size(). Does this meet the project's standards?
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's no initialization failure.
We should check it since the lambda function can be executed more than once.
src/commands/cmd_json.cc
Outdated
@@ -647,6 +689,7 @@ REDIS_REGISTER_COMMANDS(MakeCmdAttr<CommandJsonSet>("json.set", 4, "write", 1, 1 | |||
MakeCmdAttr<CommandJsonStrAppend>("json.strappend", -3, "write", 1, 1, 1), | |||
MakeCmdAttr<CommandJsonStrLen>("json.strlen", -2, "read-only", 1, 1, 1), | |||
MakeCmdAttr<CommandJsonMGet>("json.mget", -3, "read-only", 1, -2, 1), | |||
MakeCmdAttr<CommandJsonMSet>("json.mset", -4, "write", 1, -3, 3), ); | |||
MakeCmdAttr<CommandJsonMSet>("json.mset", -4, "write", 1, -3, 3), | |||
MakeCmdAttr<CommandJsonDebug>("json.debug", -3, "read-only", 1, 2, 1)); |
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.
MakeCmdAttr<CommandJsonDebug>("json.debug", -3, "read-only", 1, 2, 1)); | |
MakeCmdAttr<CommandJsonDebug>("json.debug", -3, "read-only", 2, 2, 1)); |
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.
hmm review comment still doesn't get solved yet
Ahh sorry I checked the diff again. It's fixed. |
Quality Gate failedFailed conditions See analysis details on SonarCloud Catch issues before they fail your Quality Gate with our IDE extension SonarLint |
Add support of the command JSON.DEBUG MEMORY
https://redis.io/docs/latest/commands/json.debug-memory/