acl/app/wizard_demo/pkv/proto/redis_object.cpp

465 lines
11 KiB
C++
Raw Normal View History

2023-07-19 19:07:53 +08:00
//
// Created by shuxin <20><><EFBFBD><EFBFBD>zheng on 2023/7/19.
//
#include "stdafx.h"
#include "redis_object.h"
namespace pkv {
redis_object::redis_object(redis_object* parent) {
dbuf_ = new (1) acl::dbuf_pool();
2023-07-21 16:20:04 +08:00
parent_ = parent ? parent : this;
2023-07-21 14:20:47 +08:00
}
2023-07-24 18:16:09 +08:00
redis_object::~redis_object() {
dbuf_->destroy();
}
2023-07-21 19:12:12 +08:00
const char* redis_object::get_cmd() const {
if (me_ == nullptr) {
return nullptr;
}
if (me_->get_type() == acl::REDIS_RESULT_STRING) {
return me_->get(0);
}
if (objs_.empty() || me_->get_type() != acl::REDIS_RESULT_ARRAY) {
return nullptr;
}
return objs_[0]->get_cmd();
}
2023-07-23 23:18:37 +08:00
const char* redis_object::get_str() const {
if (me_->get_type() == acl::REDIS_RESULT_STRING) {
return me_->get(0);
}
return nullptr;
}
2023-07-19 19:07:53 +08:00
struct status_machine {
/* ״̬<D7B4><CCAC> */
int status;
/* ״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
2023-07-20 19:24:18 +08:00
const char* (redis_object::*func) (const char*, size_t&);
2023-07-19 19:07:53 +08:00
};
static struct status_machine status_tab[] = {
2023-07-20 19:24:18 +08:00
{ redis_s_begin, &redis_object::parse_begin },
{ redis_s_status, &redis_object::parse_status },
{ redis_s_error, &redis_object::parse_error },
2023-07-19 19:07:53 +08:00
{ redis_s_number, &redis_object::parse_number },
{ redis_s_strlen, &redis_object::parse_strlen },
{ redis_s_string, &redis_object::parse_string },
2023-07-20 19:24:18 +08:00
{ redis_s_strend, &redis_object::parse_strend },
{ redis_s_arlen, &redis_object::parse_arlen },
{ redis_s_array, &redis_object::parse_array },
2023-07-19 19:07:53 +08:00
};
2023-07-20 19:24:18 +08:00
const char* redis_object::update(const char *data, size_t& len) {
if (failed() || finish()) {
return data;
}
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
if (obj_) {
return parse_object(data, len);
}
2023-07-19 19:07:53 +08:00
while (len > 0) {
2023-07-20 19:24:18 +08:00
data = (this->*(status_tab[status_].func))(data, len);
if (status_ == redis_s_null || status_ == redis_s_finish) {
break;
}
}
return data;
}
const char* redis_object::parse_object(const char* data, size_t& len) {
assert(cnt_ > 0);
assert(obj_);
data = obj_->update(data, len);
if (obj_->failed()) {
status_ = redis_s_null;
return data;
}
if (!obj_->finish()) {
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
objs_.emplace_back(obj_);
if (objs_.size() == (size_t) cnt_) {
obj_ = nullptr;
cnt_ = 0;
status_ = redis_s_finish;
} else {
obj_ = std::make_shared<redis_object>(this);
2023-07-20 19:24:18 +08:00
}
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_begin(const char* data, size_t& len) {
2023-07-19 19:07:53 +08:00
if (len == 0) {
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
switch (*data) {
2023-07-20 19:24:18 +08:00
case ':': // INTEGER
status_ = redis_s_number;
2023-07-19 19:07:53 +08:00
break;
case '+': // STATUS
status_ = redis_s_status;
break;
2023-07-20 19:24:18 +08:00
case '-': // ERROR
status_ = redis_s_error;
break;
2023-07-19 19:07:53 +08:00
case '$': // STRING
status_ = redis_s_strlen;
break;
case '*': // ARRAY
status_ = redis_s_arlen;
break;
default: // INVALID
status_ = redis_s_null;
break;
}
2023-07-20 19:24:18 +08:00
len--;
data++;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_status(const char* data, size_t& len) {
2023-07-19 19:07:53 +08:00
bool found = false;
2023-07-20 19:24:18 +08:00
data = get_line(data, len, found);
2023-07-19 19:07:53 +08:00
if (!found) {
assert(len == 0);
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
if (buf_.empty()) {
status_ = redis_s_null;
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_STATUS);
me_->set_size(1);
put_data(dbuf_, me_, buf_.c_str(), buf_.length());
2023-07-19 19:07:53 +08:00
buf_.clear();
2023-07-20 19:24:18 +08:00
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_error(const char* data, size_t& len) {
bool found = false;
data = get_line(data, len, found);
if (!found) {
assert(len == 0);
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
if (buf_.empty()) {
status_ = redis_s_null;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_ERROR);
me_->set_size(1);
put_data(dbuf_, me_, buf_.c_str(), buf_.length());
2023-07-19 19:07:53 +08:00
buf_.clear();
2023-07-20 19:24:18 +08:00
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_number(const char* data, size_t& len) {
bool found = false;
data = get_line(data, len, found);
if (!found) {
assert(len == 0);
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
if (buf_.empty()) {
status_ = redis_s_null;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
2023-07-21 14:20:47 +08:00
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_INTEGER);
me_->set_size(1);
put_data(dbuf_, me_, buf_.c_str(), buf_.length());
2023-07-20 19:24:18 +08:00
buf_.clear();
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_strlen(const char* data, size_t& len) {
2023-07-21 14:20:47 +08:00
bool found = false;
2023-07-20 19:24:18 +08:00
cnt_ = 0;
2023-07-21 14:20:47 +08:00
data = get_length(data, len, cnt_, found);
if (status_ == redis_s_null || !found) {
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_STRING);
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
if (cnt_ <= 0) {
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_->set_size((size_t) cnt_);
2023-07-19 19:07:53 +08:00
buf_.clear();
2023-07-20 19:24:18 +08:00
status_ = redis_s_string;
return data;
}
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_string(const char* data, size_t& len) {
2023-07-21 14:20:47 +08:00
assert (me_ != nullptr);
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
data = get_data(data, len, (size_t) cnt_);
if (buf_.size() == (size_t) cnt_) {
status_ = redis_s_strend;
2023-07-21 14:20:47 +08:00
put_data(dbuf_, me_, buf_.c_str(), buf_.length());
2023-07-20 19:24:18 +08:00
buf_.clear();
cnt_ = 0;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_strend(const char* data, size_t& len) {
2023-07-21 14:20:47 +08:00
assert (me_ != nullptr);
2023-07-20 19:24:18 +08:00
2023-07-19 19:07:53 +08:00
bool found = false;
2023-07-20 19:24:18 +08:00
data = get_line(data, len, found);
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
// If the buf_ not empty, some data other '\r\n' got.
if (!buf_.empty()) {
2023-07-19 19:07:53 +08:00
status_ = redis_s_null;
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
if (!found) {
assert(len == 0);
return data;
}
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_arlen(const char* data, size_t& len) {
2023-07-21 14:20:47 +08:00
bool found = false;
2023-07-20 19:24:18 +08:00
cnt_ = 0;
2023-07-21 14:20:47 +08:00
data = get_length(data, len, cnt_, found);
if (status_ == redis_s_null || !found) {
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_ARRAY);
2023-07-20 19:24:18 +08:00
if (cnt_ <= 0) {
status_ = redis_s_finish;
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
me_->set_size((size_t) cnt_);
2023-07-19 19:07:53 +08:00
2023-07-20 19:24:18 +08:00
buf_.clear();
status_ = redis_s_array;
obj_ = std::make_shared<redis_object>(this);
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::parse_array(const char* data, size_t& len) {
2023-07-21 14:20:47 +08:00
assert(me_ != nullptr);
2023-07-20 19:24:18 +08:00
assert(obj_ != nullptr);
return parse_object(data, len);
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::get_data(const char* data, size_t& len, size_t want) {
2023-07-19 19:07:53 +08:00
size_t n = buf_.size();
assert(n < want);
want -= n;
for (size_t i = 0; i < want && len > 0; i++) {
buf_.push_back(*data++);
len--;
}
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
const char* redis_object::get_length(const char* data, size_t& len,
int& res, bool& found) {
2023-07-20 19:24:18 +08:00
data = get_line(data, len, found);
2023-07-19 19:07:53 +08:00
if (!found) {
assert(len == 0);
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
if (buf_.empty()) {
status_ = redis_s_null;
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-21 14:20:47 +08:00
// buf_.push_back('\0'); // The c++11 promise the last char is null.
char* endptr;
2023-07-21 16:20:04 +08:00
res = (int) strtol(buf_.c_str(), &endptr, 10);
2023-07-19 19:07:53 +08:00
buf_.clear();
2023-07-21 14:20:47 +08:00
if (endptr == buf_.c_str() || *endptr != '\0') {
status_ = redis_s_null;
return data;
}
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
2023-07-20 19:24:18 +08:00
const char* redis_object::get_line(const char* data, size_t& len, bool& found) {
2023-07-19 19:07:53 +08:00
while (len > 0) {
switch (*data) {
case '\r':
data++;
len--;
break;
case '\n':
2023-07-20 19:24:18 +08:00
data++;
2023-07-19 19:07:53 +08:00
len--;
found = true;
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
default:
buf_.push_back(*data++);
len--;
break;
}
}
2023-07-20 19:24:18 +08:00
return data;
2023-07-19 19:07:53 +08:00
}
void redis_object::put_data(acl::dbuf_pool* dbuf, acl::redis_result* rr,
2023-07-20 19:24:18 +08:00
const char* data, size_t len) {
2023-07-19 19:07:53 +08:00
char* buf = (char*) dbuf->dbuf_alloc(len + 1);
if (len > 0) {
memcpy(buf, data, len);
}
buf[len] = 0;
rr->put(buf, len);
}
2023-07-20 19:24:18 +08:00
bool redis_object::to_string(acl::string& out) const {
#define USE_UNIX_CRLF
#ifdef USE_UNIX_CRLF
#define CRLF "\n"
#else
#define CRLF "\r\n"
#endif
if (!objs_.empty()) {
out.format_append("*%zd%s", objs_.size(), CRLF);
2023-07-20 22:56:34 +08:00
for (const auto& obj : objs_) {
2023-07-20 19:24:18 +08:00
if (!obj->to_string(out)) {
return false;
}
}
}
2023-07-21 14:20:47 +08:00
if (me_ == nullptr) {
2023-07-20 19:24:18 +08:00
return false;
}
2023-07-21 14:20:47 +08:00
switch (me_->get_type()) {
2023-07-20 19:24:18 +08:00
case acl::REDIS_RESULT_STATUS:
2023-07-21 14:20:47 +08:00
out.format_append("+%s%s", me_->get_status(), CRLF);
2023-07-20 19:24:18 +08:00
break;
case acl::REDIS_RESULT_ERROR:
2023-07-21 14:20:47 +08:00
out.format_append("-%s%s", me_->get_error(), CRLF);
2023-07-20 19:24:18 +08:00
break;
case acl::REDIS_RESULT_INTEGER:
2023-07-21 14:20:47 +08:00
out.format_append(":%lld%s", me_->get_integer64(), CRLF);
2023-07-20 19:24:18 +08:00
break;
case acl::REDIS_RESULT_STRING:
2023-07-21 14:20:47 +08:00
out.format_append("$%zd%s", me_->get_length(), CRLF);
me_->argv_to_string(out, false);
2023-07-20 19:24:18 +08:00
out += CRLF;
break;
2023-07-21 14:20:47 +08:00
//case acl::REDIS_RESULT_ARRAY:
// break;
2023-07-20 19:24:18 +08:00
default:
break;
}
return true;
}
2023-07-21 16:20:04 +08:00
redis_object& redis_object::set_status(const std::string& data,
bool return_parent) {
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_STATUS);
me_->set_size(1);
put_data(dbuf_, me_, data.c_str(), data.length());
return return_parent ? *parent_ : *this;
}
redis_object& redis_object::set_error(const std::string& data,
bool return_parent) {
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_ERROR);
me_->set_size(1);
put_data(dbuf_, me_, data.c_str(), data.length());
return return_parent ? *parent_ : *this;
}
redis_object& redis_object::set_number(int n, bool return_parent) {
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_INTEGER);
me_->set_size(1);
std::string buf = std::to_string(n);
put_data(dbuf_, me_, buf.c_str(), buf.length());
return return_parent ? *parent_ : *this;
}
redis_object& redis_object::set_string(const std::string &data,
bool return_parent) {
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_STRING);
me_->set_size(data.size());
if (!data.empty()) {
put_data(dbuf_, me_, data.c_str(), data.length());
}
return return_parent ? *parent_ : *this;
}
redis_object& redis_object::create_child() {
auto obj = std::make_shared<redis_object>(this);
objs_.emplace_back(obj);
2023-07-21 16:20:04 +08:00
if (me_ == nullptr) {
// The last one is NULL.
me_ = new(dbuf_) acl::redis_result(dbuf_);
me_->set_type(acl::REDIS_RESULT_ARRAY);
}
me_->set_size(objs_.size());
return *obj;
}
2023-07-19 19:07:53 +08:00
} // namespace pkv