mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 02:15:45 +02:00
chore: let resp parser provide more useful logs (#4273)
* chore: let resp parser provide more useful logs 1. More warning logs around bad BAD_ARRAYLEN messages 2. Lift the restriction around big bulk strings and log a warning instead. 3. Pull helio Probably fixes #4213 --------- Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
03d679ac31
commit
bf4f45a7c2
5 changed files with 34 additions and 13 deletions
2
helio
2
helio
|
@ -1 +1 @@
|
||||||
Subproject commit ff9b6cd35bf082a9d48cf0904b0e8557cf31b6d2
|
Subproject commit 32e8c4ec830e8d4224d8a13a11c1607f357da80f
|
|
@ -11,6 +11,7 @@
|
||||||
namespace facade {
|
namespace facade {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
constexpr static long kMaxBulkLen = 256 * (1ul << 20); // 256MB.
|
||||||
|
|
||||||
auto RedisParser::Parse(Buffer str, uint32_t* consumed, RespExpr::Vec* res) -> Result {
|
auto RedisParser::Parse(Buffer str, uint32_t* consumed, RespExpr::Vec* res) -> Result {
|
||||||
DCHECK(!str.empty());
|
DCHECK(!str.empty());
|
||||||
|
@ -218,7 +219,11 @@ auto RedisParser::ParseLen(Buffer str, int64_t* res) -> ResultConsumed {
|
||||||
const char* s = reinterpret_cast<const char*>(str.data());
|
const char* s = reinterpret_cast<const char*>(str.data());
|
||||||
const char* pos = reinterpret_cast<const char*>(memchr(s, '\n', str.size()));
|
const char* pos = reinterpret_cast<const char*>(memchr(s, '\n', str.size()));
|
||||||
if (!pos) {
|
if (!pos) {
|
||||||
Result r = str.size() < 32 ? INPUT_PENDING : BAD_ARRAYLEN;
|
Result r = INPUT_PENDING;
|
||||||
|
if (str.size() >= 32) {
|
||||||
|
LOG(WARNING) << "Unexpected format " << string_view{s, str.size()};
|
||||||
|
r = BAD_ARRAYLEN;
|
||||||
|
}
|
||||||
return {r, 0};
|
return {r, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,10 +232,16 @@ auto RedisParser::ParseLen(Buffer str, int64_t* res) -> ResultConsumed {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the first character and 2 last ones (\r\n).
|
// Skip the first character and 2 last ones (\r\n).
|
||||||
bool success = absl::SimpleAtoi(std::string_view{s + 1, size_t(pos - 1 - s)}, res);
|
string_view len_token{s + 1, size_t(pos - 1 - s)};
|
||||||
unsigned consumed = pos - s + 1;
|
bool success = absl::SimpleAtoi(len_token, res);
|
||||||
|
|
||||||
return ResultConsumed{success ? OK : BAD_ARRAYLEN, consumed};
|
unsigned consumed = pos - s + 1;
|
||||||
|
if (success && *res >= -1) {
|
||||||
|
return ResultConsumed{OK, consumed};
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(WARNING) << "Failed to parse len " << len_token;
|
||||||
|
return ResultConsumed{BAD_ARRAYLEN, consumed};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RedisParser::ConsumeArrayLen(Buffer str) -> ResultConsumed {
|
auto RedisParser::ConsumeArrayLen(Buffer str) -> ResultConsumed {
|
||||||
|
@ -247,8 +258,8 @@ auto RedisParser::ConsumeArrayLen(Buffer str) -> ResultConsumed {
|
||||||
len *= 2;
|
len *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < -1 || len > max_arr_len_) {
|
if (len > max_arr_len_) {
|
||||||
LOG_IF(WARNING, len > max_arr_len_) << "Multibulk len is too large " << len;
|
LOG(WARNING) << "Multibulk len is too large " << len;
|
||||||
|
|
||||||
return {BAD_ARRAYLEN, res.second};
|
return {BAD_ARRAYLEN, res.second};
|
||||||
}
|
}
|
||||||
|
@ -310,15 +321,14 @@ auto RedisParser::ParseArg(Buffer str) -> ResultConsumed {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < -1 || len > kMaxBulkLen)
|
|
||||||
return {BAD_ARRAYLEN, res.second};
|
|
||||||
|
|
||||||
if (len == -1) { // Resp2 NIL
|
if (len == -1) { // Resp2 NIL
|
||||||
cached_expr_->emplace_back(RespExpr::NIL);
|
cached_expr_->emplace_back(RespExpr::NIL);
|
||||||
cached_expr_->back().u = Buffer{};
|
cached_expr_->back().u = Buffer{};
|
||||||
HandleFinishArg();
|
HandleFinishArg();
|
||||||
} else {
|
} else {
|
||||||
DVLOG(1) << "String(" << len << ")";
|
DVLOG(1) << "String(" << len << ")";
|
||||||
|
LOG_IF(WARNING, len > kMaxBulkLen) << "Large bulk len: " << len;
|
||||||
|
|
||||||
cached_expr_->emplace_back(RespExpr::STRING);
|
cached_expr_->emplace_back(RespExpr::STRING);
|
||||||
cached_expr_->back().u = Buffer{};
|
cached_expr_->back().u = Buffer{};
|
||||||
bulk_len_ = len;
|
bulk_len_ = len;
|
||||||
|
|
|
@ -22,8 +22,6 @@ namespace facade {
|
||||||
*/
|
*/
|
||||||
class RedisParser {
|
class RedisParser {
|
||||||
public:
|
public:
|
||||||
constexpr static long kMaxBulkLen = 256 * (1ul << 20); // 256MB.
|
|
||||||
|
|
||||||
enum Result : uint8_t {
|
enum Result : uint8_t {
|
||||||
OK,
|
OK,
|
||||||
INPUT_PENDING,
|
INPUT_PENDING,
|
||||||
|
|
|
@ -170,7 +170,7 @@ TEST_F(RedisParserTest, Empty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RedisParserTest, LargeBulk) {
|
TEST_F(RedisParserTest, LargeBulk) {
|
||||||
std::string_view prefix("*1\r\n$1024\r\n");
|
string_view prefix("*1\r\n$1024\r\n");
|
||||||
|
|
||||||
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(prefix));
|
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(prefix));
|
||||||
ASSERT_EQ(prefix.size(), consumed_);
|
ASSERT_EQ(prefix.size(), consumed_);
|
||||||
|
@ -191,6 +191,18 @@ TEST_F(RedisParserTest, LargeBulk) {
|
||||||
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(part1));
|
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(part1));
|
||||||
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(half));
|
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(half));
|
||||||
ASSERT_EQ(RedisParser::OK, Parse("\r\n"));
|
ASSERT_EQ(RedisParser::OK, Parse("\r\n"));
|
||||||
|
|
||||||
|
prefix = "*1\r\n$270000000\r\n";
|
||||||
|
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(prefix));
|
||||||
|
ASSERT_EQ(prefix.size(), consumed_);
|
||||||
|
string chunk(1000000, 'a');
|
||||||
|
for (unsigned i = 0; i < 270; ++i) {
|
||||||
|
ASSERT_EQ(RedisParser::INPUT_PENDING, Parse(chunk));
|
||||||
|
ASSERT_EQ(chunk.size(), consumed_);
|
||||||
|
}
|
||||||
|
ASSERT_EQ(RedisParser::OK, Parse("\r\n"));
|
||||||
|
ASSERT_THAT(args_, ElementsAre(ArgType(RespExpr::STRING)));
|
||||||
|
EXPECT_EQ(270000000, args_[0].GetBuf().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RedisParserTest, NILs) {
|
TEST_F(RedisParserTest, NILs) {
|
||||||
|
|
|
@ -877,6 +877,7 @@ void ServerFamily::Init(util::AcceptServer* acceptor, std::vector<facade::Listen
|
||||||
absl::GetFlag(FLAGS_s3_ec2_metadata), absl::GetFlag(FLAGS_s3_sign_payload));
|
absl::GetFlag(FLAGS_s3_ec2_metadata), absl::GetFlag(FLAGS_s3_sign_payload));
|
||||||
#else
|
#else
|
||||||
LOG(ERROR) << "Compiled without AWS support";
|
LOG(ERROR) << "Compiled without AWS support";
|
||||||
|
exit(1);
|
||||||
#endif
|
#endif
|
||||||
} else if (IsGCSPath(flag_dir)) {
|
} else if (IsGCSPath(flag_dir)) {
|
||||||
auto gcs = std::make_shared<detail::GcsSnapshotStorage>();
|
auto gcs = std::make_shared<detail::GcsSnapshotStorage>();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue