-
Notifications
You must be signed in to change notification settings - Fork 300
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: Added SELECT redis command #482
base: develop
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
#include <storages/redis/impl/redis_stats.hpp> | ||
#include <storages/redis/impl/tcp_socket.hpp> | ||
#include <userver/storages/redis/impl/reply.hpp> | ||
#include <userver/utils/scope_guard.hpp> | ||
|
||
#include "command_control_impl.hpp" | ||
|
||
|
@@ -141,7 +142,7 @@ class Redis::RedisImpl : public std::enable_shared_from_this<Redis::RedisImpl> { | |
~RedisImpl(); | ||
|
||
void Connect(const ConnectionInfo::HostVector& host_addrs, int port, | ||
const Password& password); | ||
const Password& password, std::optional<size_t> database_index); | ||
void Disconnect(); | ||
|
||
bool AsyncCommand(const CommandPtr& command); | ||
|
@@ -228,6 +229,7 @@ class Redis::RedisImpl : public std::enable_shared_from_this<Redis::RedisImpl> { | |
void ProcessCommand(const CommandPtr& command); | ||
|
||
void Authenticate(); | ||
void SelectDatabase(); | ||
void SendReadOnly(); | ||
void FreeCommands(); | ||
|
||
|
@@ -246,7 +248,8 @@ class Redis::RedisImpl : public std::enable_shared_from_this<Redis::RedisImpl> { | |
static bool WatchCommandTimerEnabled( | ||
const CommandsBufferingSettings& commands_buffering_settings); | ||
|
||
bool Connect(const std::string& host, int port, const Password& password); | ||
bool Connect(const std::string& host, int port, const Password& password, | ||
std::optional<size_t> database_index); | ||
|
||
Redis* redis_obj_; | ||
engine::ev::ThreadControl ev_thread_control_; | ||
|
@@ -267,6 +270,7 @@ class Redis::RedisImpl : public std::enable_shared_from_this<Redis::RedisImpl> { | |
uint16_t port_ = 0; | ||
std::string server_; | ||
Password password_{std::string()}; | ||
std::optional<size_t> database_index_; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not optional and 0 by default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
std::atomic<size_t> commands_size_ = 0; | ||
size_t sent_count_ = 0; | ||
size_t cmd_counter_ = 0; | ||
|
@@ -331,8 +335,9 @@ Redis::~Redis() { | |
} | ||
|
||
void Redis::Connect(const ConnectionInfo::HostVector& host_addrs, int port, | ||
const Password& password) { | ||
impl_->Connect(host_addrs, port, password); | ||
const Password& password, | ||
std::optional<size_t> database_index) { | ||
impl_->Connect(host_addrs, port, password, database_index); | ||
} | ||
|
||
bool Redis::AsyncCommand(const CommandPtr& command) { | ||
|
@@ -440,17 +445,19 @@ void Redis::RedisImpl::Detach() { | |
} | ||
|
||
void Redis::RedisImpl::Connect(const ConnectionInfo::HostVector& host_addrs, | ||
int port, const Password& password) { | ||
int port, const Password& password, | ||
std::optional<size_t> database_index) { | ||
for (const auto& host : host_addrs) | ||
if (Connect(host, port, password)) return; | ||
if (Connect(host, port, password, database_index)) return; | ||
|
||
LOG_ERROR() << "error async connect to Redis server (host addrs =" | ||
<< host_addrs << ", port=" << port << ")"; | ||
SetState(State::kInitError); | ||
} | ||
|
||
bool Redis::RedisImpl::Connect(const std::string& host, int port, | ||
const Password& password) { | ||
const Password& password, | ||
std::optional<size_t> database_index) { | ||
UASSERT(context_ == nullptr); | ||
UASSERT(state_ == State::kInit); | ||
|
||
|
@@ -461,6 +468,7 @@ bool Redis::RedisImpl::Connect(const std::string& host, int port, | |
log_extra_.Extend("redis_server", GetServer()); | ||
log_extra_.Extend("server_id", GetServerId().GetId()); | ||
password_ = password; | ||
database_index_ = database_index; | ||
LOG_INFO() << log_extra_ << "Async connect to Redis server=" << GetServer(); | ||
context_ = redisAsyncConnect(host.c_str(), port); | ||
|
||
|
@@ -1038,19 +1046,13 @@ bool Redis::RedisImpl::InitSecureConnection() { | |
|
||
void Redis::RedisImpl::Authenticate() { | ||
if (password_.GetUnderlying().empty()) { | ||
if (send_readonly_) | ||
SendReadOnly(); | ||
else | ||
SetState(State::kConnected); | ||
SendReadOnly(); | ||
} else { | ||
ProcessCommand(PrepareCommand( | ||
CmdArgs{"AUTH", password_.GetUnderlying()}, | ||
[this](const CommandPtr&, ReplyPtr reply) { | ||
if (*reply && reply->data.IsStatus()) { | ||
if (send_readonly_) | ||
SendReadOnly(); | ||
else | ||
SetState(State::kConnected); | ||
SendReadOnly(); | ||
} else { | ||
if (*reply) { | ||
if (reply->IsUnknownCommandError()) { | ||
|
@@ -1077,12 +1079,17 @@ void Redis::RedisImpl::Authenticate() { | |
} | ||
|
||
void Redis::RedisImpl::SendReadOnly() { | ||
if (!send_readonly_) { | ||
SelectDatabase(); | ||
return; | ||
} | ||
|
||
LOG_DEBUG() << "Send READONLY command to slave " | ||
<< GetServerId().GetDescription() << " in cluster mode"; | ||
ProcessCommand(PrepareCommand(CmdArgs{"READONLY"}, [this](const CommandPtr&, | ||
ReplyPtr reply) { | ||
if (*reply && reply->data.IsStatus()) { | ||
SetState(State::kConnected); | ||
SelectDatabase(); | ||
} else { | ||
if (*reply) { | ||
LOG_LIMITED_ERROR() | ||
|
@@ -1099,6 +1106,47 @@ void Redis::RedisImpl::SendReadOnly() { | |
})); | ||
} | ||
|
||
void Redis::RedisImpl::SelectDatabase() { | ||
if (!database_index_) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better yet, if database index equals 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
SetState(RedisState::kConnected); | ||
return; | ||
} | ||
|
||
ProcessCommand(PrepareCommand( | ||
CmdArgs{"SELECT", *database_index_}, | ||
[this](const CommandPtr&, ReplyPtr reply) { | ||
if (*reply && reply->data.IsStatus()) { | ||
SetState(RedisState::kConnected); | ||
LOG_INFO() << log_extra_ | ||
<< "Selected redis logical database with index " | ||
<< *database_index_; | ||
return; | ||
} | ||
|
||
const utils::ScopeGuard auto_disconnect([this]() { Disconnect(); }); | ||
|
||
if (!*reply) { | ||
LOG_LIMITED_ERROR() | ||
<< "SELECT failed with status " << reply->status << " (" | ||
<< reply->status_string << ") " << log_extra_; | ||
return; | ||
} | ||
|
||
if (reply->IsUnknownCommandError()) { | ||
LOG_WARNING() << log_extra_ | ||
<< "SELECT failed: unknown command `SELECT` - " | ||
"possible when connecting to Sentinel instead " | ||
"of Redis master or slave instance"; | ||
return; | ||
} | ||
|
||
LOG_LIMITED_ERROR() | ||
<< log_extra_ | ||
<< "SELECT failed: response type=" << reply->data.GetTypeString() | ||
<< " msg=" << reply->data.ToDebugString(); | ||
})); | ||
} | ||
|
||
void Redis::RedisImpl::OnRedisReply(redisAsyncContext* c, void* r, | ||
void* privdata) noexcept { | ||
auto* impl = static_cast<Redis::RedisImpl*>(c->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.
New connections always use database index 0 so it is not really an optional:
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