Skip to content
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

fix: change irrewritable attributes in config from atomic to primitive #352

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/cmd_admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void FlushdbCmd::DoCmd(PClient* client) {
int currentDBIndex = client->GetCurrentDB();
PSTORE.GetBackend(currentDBIndex).get()->Lock();

std::string db_path = g_config.db_path.ToString() + std::to_string(currentDBIndex);
std::string db_path = g_config.db_path + std::to_string(currentDBIndex);
std::string path_temp = db_path;
path_temp.append("_deleting/");
pstd::RenameFile(db_path, path_temp);
Expand All @@ -81,7 +81,7 @@ bool FlushallCmd::DoInitial(PClient* client) { return true; }
void FlushallCmd::DoCmd(PClient* client) {
for (size_t i = 0; i < g_config.databases; ++i) {
PSTORE.GetBackend(i).get()->Lock();
std::string db_path = g_config.db_path.ToString() + std::to_string(i);
std::string db_path = g_config.db_path + std::to_string(i);
std::string path_temp = db_path;
path_temp.append("_deleting/");
pstd::RenameFile(db_path, path_temp);
Expand Down Expand Up @@ -115,7 +115,7 @@ ShutdownCmd::ShutdownCmd(const std::string& name, int16_t arity)
bool ShutdownCmd::DoInitial(PClient* client) {
// For now, only shutdown need check local
if (client->PeerIP().find("127.0.0.1") == std::string::npos &&
client->PeerIP().find(g_config.ip.ToString()) == std::string::npos) {
client->PeerIP().find(g_config.ip) == std::string::npos) {
client->SetRes(CmdRes::kErrOther, kCmdNameShutdown + " should be localhost");
return false;
}
Expand Down
69 changes: 51 additions & 18 deletions src/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

#include <string>
#include <system_error>
#include <vector>

#include "config.h"
#include "pstd/pstd_string.h"
#include "store.h"
Expand Down Expand Up @@ -76,6 +72,43 @@ Status StringValue::SetValue(const std::string& value) {
}

Status BoolValue::SetValue(const std::string& value) {
if (pstd::StringEqualCaseInsensitive(value, "yes")) {
*value_ = true;
} else {
*value_ = false;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在value_还是std::atomic*类型的情况下,还是使用value_->store(true);和value_->store(false);比较好

}
return Status::OK();
}

template <typename T>
Status NumberValue<T>::SetValue(const std::string& value) {
T v;
auto [ptr, ec] = std::from_chars(value.data(), value.data() + value.length(), v);
if (ec != std::errc()) {
return Status::InvalidArgument("Failed to convert to a number.");
}
if (v < value_min_) {
v = value_min_;
}
if (v > value_max_) {
v = value_max_;
}
*value_ = v;
return Status::OK();
}

Status AtomicStringValue::SetValue(const std::string& value) {
auto values = SplitString(value, delimiter_);
if (values.size() != values_.size()) {
return Status::InvalidArgument("The number of parameters does not match.");
}
for (int i = 0; i < values_.size(); i++) {
*values_[i] = std::move(values[i]);
}
return Status::OK();
}

Status AtomicBoolValue::SetValue(const std::string& value) {
if (pstd::StringEqualCaseInsensitive(value, "yes")) {
value_->store(true);
} else {
Expand All @@ -85,7 +118,7 @@ Status BoolValue::SetValue(const std::string& value) {
}

template <typename T>
Status NumberValue<T>::SetValue(const std::string& value) {
Status AtomicNumberValue<T>::SetValue(const std::string& value) {
T v;
auto [ptr, ec] = std::from_chars(value.data(), value.data() + value.length(), v);
if (ec != std::errc()) {
Expand All @@ -102,28 +135,29 @@ Status NumberValue<T>::SetValue(const std::string& value) {
}

PConfig::PConfig() {
// TODO(lihuan): update all affected references
AddBool("daemonize", &CheckYesNo, false, &daemonize);
AddString("ip", false, {&ip});
AddNumberWihLimit<uint16_t>("port", false, &port, PORT_LIMIT_MIN, PORT_LIMIT_MAX);
AddNumber("raft-port-offset", true, &raft_port_offset);
AddNumber("timeout", true, &timeout);
AddAtomicNumber("raft-port-offset", true, &raft_port_offset);
AddAtomicNumber("timeout", true, &timeout);
AddString("db-path", false, {&db_path});
AddStrinWithFunc("loglevel", &CheckLogLevel, false, {&log_level});
AddString("logfile", false, {&log_dir});
AddNumberWihLimit<size_t>("databases", false, &databases, 1, DBNUMBER_MAX);
AddString("requirepass", true, {&password});
AddNumber("maxclients", true, &max_clients);
AddAtomicString("requirepass", true, {&password});
AddAtomicNumber("maxclients", true, &max_clients);
AddNumberWihLimit<uint32_t>("worker-threads", false, &worker_threads_num, 1, THREAD_MAX);
AddNumberWihLimit<uint32_t>("slave-threads", false, &worker_threads_num, 1, THREAD_MAX);
AddNumber("slowlog-log-slower-than", true, &slow_log_time);
AddNumber("slowlog-max-len", true, &slow_log_max_len);
AddNumberWihLimit<size_t>("db-instance-num", true, &db_instance_num, 1, ROCKSDB_INSTANCE_NUMBER_MAX);
AddAtomicNumber("slowlog-log-slower-than", true, &slow_log_time);
AddAtomicNumber("slowlog-max-len", true, &slow_log_max_len);
AddAtomicNumberWihLimit<size_t>("db-instance-num", true, &db_instance_num, 1, ROCKSDB_INSTANCE_NUMBER_MAX);
AddNumberWihLimit<int32_t>("fast-cmd-threads-num", false, &fast_cmd_threads_num, 1, THREAD_MAX);
AddNumberWihLimit<int32_t>("slow-cmd-threads-num", false, &slow_cmd_threads_num, 1, THREAD_MAX);
AddNumber("max-client-response-size", true, &max_client_response_size);
AddString("runid", false, {&run_id});
AddNumber("small-compaction-threshold", true, &small_compaction_threshold);
AddNumber("small-compaction-duration-threshold", true, &small_compaction_duration_threshold);
AddAtomicNumber("max-client-response-size", true, &max_client_response_size);
AddAtomicString("runid", false, {&run_id});
AddAtomicNumber("small-compaction-threshold", true, &small_compaction_threshold);
AddAtomicNumber("small-compaction-duration-threshold", true, &small_compaction_duration_threshold);
AddBool("use-raft", &CheckYesNo, false, &use_raft);

// rocksdb config
Expand All @@ -133,11 +167,10 @@ PConfig::PConfig() {
AddNumber("rocksdb-min-write-buffer-number-to-merge", false, &rocksdb_min_write_buffer_number_to_merge);
AddNumber("rocksdb-write-buffer-size", false, &rocksdb_write_buffer_size);
AddNumber("rocksdb-level0-file-num-compaction-trigger", false, &rocksdb_level0_file_num_compaction_trigger);
AddNumber("rocksdb-number-levels", true, &rocksdb_num_levels);
AddAtomicNumber("rocksdb-number-levels", true, &rocksdb_num_levels);
AddBool("rocksdb-enable-pipelined-write", CheckYesNo, false, &rocksdb_enable_pipelined_write);
AddNumber("rocksdb-level0-slowdown-writes-trigger", false, &rocksdb_level0_slowdown_writes_trigger);
AddNumber("rocksdb-level0-stop-writes-trigger", false, &rocksdb_level0_stop_writes_trigger);
AddNumber("rocksdb-level0-slowdown-writes-trigger", false, &rocksdb_level0_slowdown_writes_trigger);
}

bool PConfig::LoadFromFile(const std::string& file_name) {
Expand Down
152 changes: 115 additions & 37 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ extern PConfig g_config;

class BaseValue {
public:
BaseValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable = false)
: key_(key), custom_check_func_ptr_(check_func_ptr), rewritable_(rewritable) {}
BaseValue(std::string key, CheckFunc check_func_ptr, bool rewritable = false)
: key_(std::move(key)), custom_check_func_ptr_(std::move(check_func_ptr)), rewritable_(rewritable) {}

virtual ~BaseValue() = default;

const std::string& Key() const { return key_; }

virtual std::string Value() const = 0;

Status Set(const std::string& value, bool force);
Status Set(const std::string& value, bool init_stage);

protected:
virtual Status SetValue(const std::string&) = 0;
Expand All @@ -62,8 +62,10 @@ class BaseValue {
class StringValue : public BaseValue {
public:
StringValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable,
const std::vector<AtomicString*>& value_ptr_vec, char delimiter = ' ')
: BaseValue(key, check_func_ptr, rewritable), values_(value_ptr_vec), delimiter_(delimiter) {
std::vector<std::string*> value_ptr_vec, char delimiter = ' ')
: BaseValue(key, std::move(check_func_ptr), rewritable),
values_(std::move(value_ptr_vec)),
delimiter_(delimiter) {
assert(!values_.empty());
}
~StringValue() override = default;
Expand All @@ -73,15 +75,69 @@ class StringValue : public BaseValue {
private:
Status SetValue(const std::string& value) override;

std::vector<AtomicString*> values_;
std::vector<std::string*> values_;
char delimiter_ = 0;
};

template <typename T>
class NumberValue : public BaseValue {
public:
NumberValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, std::atomic<T>* value_ptr,
NumberValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, T* value,
T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max())
: BaseValue(key, check_func_ptr, rewritable), value_(value), value_min_(min), value_max_(max) {
assert(value_ != nullptr);
assert(value_min_ <= value_max_);
};

std::string Value() const override { return std::to_string(*value_); }

private:
Status SetValue(const std::string& value) override;

T* value_;
T value_min_;
T value_max_;
};

class BoolValue : public BaseValue {
public:
BoolValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, bool* value)
: BaseValue(key, std::move(check_func_ptr), rewritable), value_(value) {
assert(value_ != nullptr);
};

std::string Value() const override { return *value_ ? "yes" : "no"; };

private:
Status SetValue(const std::string& value) override;
bool* value_ = nullptr;
};

class AtomicStringValue : public BaseValue {
public:
AtomicStringValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable,
std::vector<AtomicString*> value_ptr_vec, char delimiter = ' ')
: BaseValue(key, std::move(check_func_ptr), rewritable),
values_(std::move(value_ptr_vec)),
delimiter_(delimiter) {
assert(!values_.empty());
}
~AtomicStringValue() override = default;

std::string Value() const override { return MergeString(values_, delimiter_); };

private:
Status SetValue(const std::string& value) override;

std::vector<AtomicString*> values_;
char delimiter_ = 0;
};

template <typename T>
class AtomicNumberValue : public BaseValue {
public:
AtomicNumberValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, std::atomic<T>* value_ptr,
T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max())
: BaseValue(key, check_func_ptr, rewritable), value_(value_ptr), value_min_(min), value_max_(max) {
assert(value_ != nullptr);
assert(value_min_ <= value_max_);
Expand All @@ -97,10 +153,10 @@ class NumberValue : public BaseValue {
T value_max_;
};

class BoolValue : public BaseValue {
class AtomicBoolValue : public BaseValue {
public:
BoolValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, std::atomic<bool>* value_ptr)
: BaseValue(key, check_func_ptr, rewritable), value_(value_ptr) {
AtomicBoolValue(const std::string& key, CheckFunc check_func_ptr, bool rewritable, std::atomic<bool>* value_ptr)
: BaseValue(key, std::move(check_func_ptr), rewritable), value_(value_ptr) {
assert(value_ != nullptr);
};

Expand All @@ -121,7 +177,7 @@ class PConfig {
bool LoadFromFile(const std::string& file_name);
const std::string& ConfigFileName() const { return config_file_name_; }
void Get(const std::string&, std::vector<std::string>*) const;
Status Set(std::string, const std::string&, bool force = false);
Status Set(std::string, const std::string&, bool init_stage = false);

public:
std::atomic_uint32_t timeout = 0;
Expand All @@ -136,41 +192,41 @@ class PConfig {
std::atomic_uint32_t master_port; // replication
AtomicString include_file; // the template config
std::vector<PString> modules; // modules
std::atomic_int32_t fast_cmd_threads_num = 4;
std::atomic_int32_t slow_cmd_threads_num = 4;
int32_t fast_cmd_threads_num = 4;
int32_t slow_cmd_threads_num = 4;
std::atomic_uint64_t max_client_response_size = 1073741824;
std::atomic_uint64_t small_compaction_threshold = 604800;
std::atomic_uint64_t small_compaction_duration_threshold = 259200;

std::atomic_bool daemonize = false;
bool daemonize = false;
AtomicString pid_file = "./pikiwidb.pid";
AtomicString ip = "127.0.0.1";
std::atomic_uint16_t port = 9221;
std::string ip = "127.0.0.1";
uint16_t port = 9221;
std::atomic_uint16_t raft_port_offset = 10;
AtomicString db_path = "./db/";
AtomicString log_dir = "stdout"; // the log directory, differ from redis
AtomicString log_level = "warning";
std::string db_path = "./db/";
std::string log_dir = "stdout"; // the log directory, differ from redis
std::string log_level = "warning";
AtomicString run_id;
std::atomic<size_t> databases = 16;
std::atomic_uint32_t worker_threads_num = 2;
size_t databases = 16;
uint32_t worker_threads_num = 2;
std::atomic_uint32_t slave_threads_num = 2;
std::atomic<size_t> db_instance_num = 3;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这两个是动态可调整嘛? 我在issue里看到说db_instance_num也是只读,这个需要考虑改成普通变量吗
image

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,加载之后不会修改,slave_threads_num 也是

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

像上面的 master_ip 逻辑上应该也不会在加载之后修改,可以对上面的 config 类中的变量逐个考虑一下是否是只读属性

std::atomic_bool use_raft = true;
bool use_raft = true;

std::atomic_uint32_t rocksdb_max_subcompactions = 0;
uint32_t rocksdb_max_subcompactions = 0;
// default 2
std::atomic_int rocksdb_max_background_jobs = 4;
int rocksdb_max_background_jobs = 4;
// default 2
std::atomic<size_t> rocksdb_max_write_buffer_number = 2;
size_t rocksdb_max_write_buffer_number = 2;
// default 2
std::atomic_int rocksdb_min_write_buffer_number_to_merge = 2;
int rocksdb_min_write_buffer_number_to_merge = 2;
// default 64M
std::atomic<size_t> rocksdb_write_buffer_size = 64 << 20;
std::atomic_int rocksdb_level0_file_num_compaction_trigger = 4;
size_t rocksdb_write_buffer_size = 64 << 20;
int rocksdb_level0_file_num_compaction_trigger = 4;
std::atomic_int rocksdb_num_levels = 7;
std::atomic_bool rocksdb_enable_pipelined_write = false;
std::atomic_int rocksdb_level0_slowdown_writes_trigger = 20;
std::atomic_int rocksdb_level0_stop_writes_trigger = 36;
bool rocksdb_enable_pipelined_write = false;
int rocksdb_level0_slowdown_writes_trigger = 20;
int rocksdb_level0_stop_writes_trigger = 36;
std::atomic_uint64_t rocksdb_ttl_second = 604800; // default 86400 * 7
std::atomic_uint64_t rocksdb_periodic_second = 259200; // default 86400 * 3

Expand All @@ -179,26 +235,48 @@ class PConfig {
rocksdb::BlockBasedTableOptions GetRocksDBBlockBasedTableOptions();

private:
inline void AddString(const std::string& key, bool rewritable, std::vector<AtomicString*> values_ptr_vector) {
inline void AddString(const std::string& key, bool rewritable, const std::vector<std::string*>& values_ptr_vector) {
config_map_.emplace(key, std::make_unique<StringValue>(key, nullptr, rewritable, values_ptr_vector));
}
inline void AddStrinWithFunc(const std::string& key, const CheckFunc& checkfunc, bool rewritable,
std::vector<AtomicString*> values_ptr_vector) {
const std::vector<std::string*>& values_ptr_vector) {
Comment on lines +238 to +242
Copy link

@coderabbitai coderabbitai bot Jun 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

AddStringAddStrinWithFunc 方法在添加键值对时没有检查键是否已存在于 config_map_ 中。为了确保没有重复添加相同的键,建议在添加新键之前先检查 config_map_ 中是否已存在该键。

  • src/config.h
    • AddString 方法在添加键值对时没有进行键存在性检查。
    • AddStrinWithFunc 方法在添加键值对时没有进行键存在性检查。

请在这些方法中添加键存在性检查,以避免重复添加相同的键。

Analysis chain

添加了AddStringAddStrinWithFunc两个方法,用于简化配置项的添加。这些方法通过直接操作内部的config_map_来注册新的配置项,使得代码更加简洁。需要检查这些方法的使用是否正确处理了所有潜在的异常情况,例如重复添加相同的键。

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# 检查AddString和AddStrinWithFunc方法的调用情况,确保没有重复添加相同的键。
rg --type cpp "AddString" -A 3

Length of output: 1121



Script:

#!/bin/bash
# Check if config_map_ is checked for existing keys before adding new entries in AddString and AddStrinWithFunc methods.
rg --type cpp "config_map_" -A 5

Length of output: 4153

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些方法只会在PConfig::PConfig()中被调用,可以明确保证没有重复的键,所以不需要额外的检查。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mirthfulLee, thank you for clarifying the usage context of the AddString and AddStrinWithFunc methods within the PConfig::PConfig() constructor. Based on your insight, it seems these methods are used in a controlled manner that ensures no duplicate keys are added. I'll take note of this for future reviews and appreciate your detailed understanding of the codebase's structure.

Analysis chain
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Search for the usage of `AddString` and `AddStrinWithFunc` methods within the `PConfig::PConfig()` constructor to verify the user's claim.
ast-grep --lang cpp --pattern $'class PConfig {
  PConfig() {
    $$$
  }
}'

Length of output: 77


Learnings added
User: mirthfulLee
PR: OpenAtomFoundation/pikiwidb#352
File: src/config.h:238-242
Timestamp: 2024-06-15T08:37:03.282Z
Learning: The `AddString` and `AddStrinWithFunc` methods are only called within the `PConfig::PConfig()` constructor, ensuring no duplicate keys are added.

Note: Learnings are effective only in the context of specific code segments. To apply general coding guidelines, please configure review instructions.

config_map_.emplace(key, std::make_unique<StringValue>(key, checkfunc, rewritable, values_ptr_vector));
}
inline void AddBool(const std::string& key, const CheckFunc& checkfunc, bool rewritable,
std::atomic<bool>* value_ptr) {
inline void AddBool(const std::string& key, const CheckFunc& checkfunc, bool rewritable, bool* value_ptr) {
config_map_.emplace(key, std::make_unique<BoolValue>(key, checkfunc, rewritable, value_ptr));
}
template <typename T>
inline void AddNumber(const std::string& key, bool rewritable, std::atomic<T>* value_ptr) {
inline void AddNumber(const std::string& key, bool rewritable, T* value_ptr) {
config_map_.emplace(key, std::make_unique<NumberValue<T>>(key, nullptr, rewritable, value_ptr));
}
template <typename T>
inline void AddNumberWihLimit(const std::string& key, bool rewritable, std::atomic<T>* value_ptr, T min, T max) {
inline void AddNumberWihLimit(const std::string& key, bool rewritable, T* value_ptr, T min, T max) {
config_map_.emplace(key, std::make_unique<NumberValue<T>>(key, nullptr, rewritable, value_ptr, min, max));
}

// inline functions for add atomic Values
inline void AddAtomicString(const std::string& key, bool rewritable,
const std::vector<AtomicString*>& values_ptr_vector) {
config_map_.emplace(key, std::make_unique<AtomicStringValue>(key, nullptr, rewritable, values_ptr_vector));
}
inline void AddAtomicStrinWithFunc(const std::string& key, const CheckFunc& checkfunc, bool rewritable,
const std::vector<AtomicString*>& values_ptr_vector) {
config_map_.emplace(key, std::make_unique<AtomicStringValue>(key, checkfunc, rewritable, values_ptr_vector));
}
inline void AddAtomicBool(const std::string& key, const CheckFunc& checkfunc, bool rewritable,
std::atomic<bool>* value_ptr) {
config_map_.emplace(key, std::make_unique<AtomicBoolValue>(key, checkfunc, rewritable, value_ptr));
}
template <typename T>
inline void AddAtomicNumber(const std::string& key, bool rewritable, std::atomic<T>* value_ptr) {
config_map_.emplace(key, std::make_unique<AtomicNumberValue<T>>(key, nullptr, rewritable, value_ptr));
}
template <typename T>
inline void AddAtomicNumberWihLimit(const std::string& key, bool rewritable, std::atomic<T>* value_ptr, T min,
T max) {
config_map_.emplace(key, std::make_unique<AtomicNumberValue<T>>(key, nullptr, rewritable, value_ptr, min, max));
}

private:
ConfigParser parser_;
ConfigMap config_map_;
Expand Down
Loading
Loading