This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 2b954568 Fix server cannot start without the configuration file (#1804)
2b954568 is described below
commit 2b9545688142df85048bc8bc04c0589cb96f9cc1
Author: hulk <[email protected]>
AuthorDate: Sun Oct 15 23:11:53 2023 +0800
Fix server cannot start without the configuration file (#1804)
Co-authored-by: Twice <[email protected]>
---
src/config/config.cc | 2 +-
src/config/config.h | 1 +
src/server/namespace.cc | 23 +++++++++++++---
src/server/namespace.h | 1 +
.../integration/cli_options/cli_options_test.go | 2 +-
tests/gocase/unit/config/config_test.go | 12 +++++++++
tests/gocase/unit/namespace/namespace_test.go | 30 +++++++++++++++++++++
tests/gocase/util/server.go | 31 +++++++++++++++-------
8 files changed, 87 insertions(+), 15 deletions(-)
diff --git a/src/config/config.cc b/src/config/config.cc
index ad922dd6..d3549e59 100644
--- a/src/config/config.cc
+++ b/src/config/config.cc
@@ -844,7 +844,7 @@ Status Config::Set(Server *svr, std::string key, const
std::string &value) {
}
Status Config::Rewrite(const std::map<std::string, std::string> &tokens) {
- if (path_.empty()) {
+ if (!HasConfigFile()) {
return {Status::NotOK, "the server is running without a config file"};
}
diff --git a/src/config/config.h b/src/config/config.h
index d79d1527..d540906f 100644
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -222,6 +222,7 @@ struct Config {
void SetMaster(const std::string &host, uint32_t port);
void ClearMaster();
bool IsSlave() const { return !master_host.empty(); }
+ bool HasConfigFile() const { return !path_.empty(); }
private:
std::string path_;
diff --git a/src/server/namespace.cc b/src/server/namespace.cc
index a0e8d05a..01a44dcf 100644
--- a/src/server/namespace.cc
+++ b/src/server/namespace.cc
@@ -31,6 +31,8 @@ constexpr const char* kErrClusterModeEnabled = "forbidden to
add namespace when
constexpr const char* kErrDeleteDefaultNamespace = "forbidden to delete the
default namespace";
constexpr const char* kErrAddDefaultNamespace = "forbidden to add the default
namespace";
constexpr const char* kErrInvalidToken = "the token is duplicated with
requirepass or masterauth";
+constexpr const char* kErrCantModifyNamespace =
+ "modify namespace requires the server is running with a configuration file
or enabled namespace replication";
Status IsNamespaceLegal(const std::string& ns) {
if (ns.size() > UINT8_MAX) {
@@ -43,6 +45,12 @@ Status IsNamespaceLegal(const std::string& ns) {
return Status::OK();
}
+bool Namespace::IsAllowModify() const {
+ auto config = storage_->GetConfig();
+
+ return config->HasConfigFile() || config->repl_namespace_enabled;
+}
+
Status Namespace::LoadAndRewrite() {
auto config = storage_->GetConfig();
// Load from the configuration file first
@@ -100,6 +108,9 @@ Status Namespace::Set(const std::string& ns, const
std::string& token) {
if (config->cluster_enabled) {
return {Status::NotOK, kErrClusterModeEnabled};
}
+ if (!IsAllowModify()) {
+ return {Status::NotOK, kErrCantModifyNamespace};
+ }
if (ns == kDefaultNamespace) {
return {Status::NotOK, kErrAddDefaultNamespace};
}
@@ -142,6 +153,9 @@ Status Namespace::Del(const std::string& ns) {
if (ns == kDefaultNamespace) {
return {Status::NotOK, kErrDeleteDefaultNamespace};
}
+ if (!IsAllowModify()) {
+ return {Status::NotOK, kErrCantModifyNamespace};
+ }
for (const auto& iter : tokens_) {
if (iter.second == ns) {
@@ -159,9 +173,12 @@ Status Namespace::Del(const std::string& ns) {
Status Namespace::Rewrite() {
auto config = storage_->GetConfig();
- auto s = config->Rewrite(tokens_);
- if (!s.IsOK()) {
- return s;
+ // Rewrite the configuration file only if it's running with the
configuration file
+ if (config->HasConfigFile()) {
+ auto s = config->Rewrite(tokens_);
+ if (!s.IsOK()) {
+ return s;
+ }
}
// Don't propagate write to DB if its role is slave to prevent from
diff --git a/src/server/namespace.h b/src/server/namespace.h
index cccf46e0..943a3ece 100644
--- a/src/server/namespace.h
+++ b/src/server/namespace.h
@@ -42,6 +42,7 @@ class Namespace {
Status Del(const std::string &ns);
const std::map<std::string, std::string> &List() const { return tokens_; }
Status Rewrite();
+ bool IsAllowModify() const;
private:
engine::Storage *storage_;
diff --git a/tests/gocase/integration/cli_options/cli_options_test.go
b/tests/gocase/integration/cli_options/cli_options_test.go
index 767679dd..43f3cf77 100644
--- a/tests/gocase/integration/cli_options/cli_options_test.go
+++ b/tests/gocase/integration/cli_options/cli_options_test.go
@@ -28,7 +28,7 @@ import (
)
func TestCLIOptions(t *testing.T) {
- srv := util.StartServerWithCLIOptions(t, map[string]string{},
[]string{"--maxclients", "23333"})
+ srv := util.StartServerWithCLIOptions(t, true, map[string]string{},
[]string{"--maxclients", "23333"})
defer srv.Close()
ctx := context.Background()
diff --git a/tests/gocase/unit/config/config_test.go
b/tests/gocase/unit/config/config_test.go
index 2bca988a..c6c9b682 100644
--- a/tests/gocase/unit/config/config_test.go
+++ b/tests/gocase/unit/config/config_test.go
@@ -129,3 +129,15 @@ func TestConfigSetCompression(t *testing.T) {
}
require.ErrorContains(t, rdb.ConfigSet(ctx, configKey,
"unsupported").Err(), "invalid enum option")
}
+
+func TestStartWithoutConfigurationFile(t *testing.T) {
+ srv := util.StartServerWithCLIOptions(t, false, map[string]string{},
[]string{})
+ defer srv.Close()
+
+ ctx := context.Background()
+ rdb := srv.NewClient()
+ defer func() { require.NoError(t, rdb.Close()) }()
+
+ require.NoError(t, rdb.Do(ctx, "SET", "foo", "bar").Err())
+ require.Equal(t, "bar", rdb.Do(ctx, "GET", "foo").Val())
+}
diff --git a/tests/gocase/unit/namespace/namespace_test.go
b/tests/gocase/unit/namespace/namespace_test.go
index bc04a7c3..1b80e5b9 100644
--- a/tests/gocase/unit/namespace/namespace_test.go
+++ b/tests/gocase/unit/namespace/namespace_test.go
@@ -241,3 +241,33 @@ func TestNamespaceReplicate(t *testing.T) {
util.ErrorRegexp(t, masterRdb.ConfigSet(ctx,
"repl-namespace-enabled", "no").Err(), ".*cannot switch off
repl_namespace_enabled when namespaces exist in db.*")
})
}
+
+func TestNamespaceRewrite(t *testing.T) {
+ password := "pwd"
+ srv := util.StartServerWithCLIOptions(t, false, map[string]string{
+ "requirepass": password,
+ }, []string{})
+ defer srv.Close()
+
+ rdb := srv.NewClientWithOption(&redis.Options{
+ Password: password,
+ })
+ defer func() { require.NoError(t, rdb.Close()) }()
+ ctx := context.Background()
+
+ t.Run("Cannot modify namespace if running without the configuration",
func(t *testing.T) {
+ errMsg := ".*ERR modify namespace requires the server is
running with a configuration file or enabled namespace replication.*"
+ r := rdb.Do(ctx, "NAMESPACE", "ADD", "ns1", "token1")
+ util.ErrorRegexp(t, r.Err(), errMsg)
+ r = rdb.Do(ctx, "NAMESPACE", "SET", "ns1", "token1")
+ util.ErrorRegexp(t, r.Err(), errMsg)
+ r = rdb.Do(ctx, "NAMESPACE", "DEL", "ns1")
+ util.ErrorRegexp(t, r.Err(), errMsg)
+
+ // Good to go after enabling namespace replication
+ require.NoError(t, rdb.ConfigSet(ctx, "repl-namespace-enabled",
"yes").Err())
+ require.NoError(t, rdb.Do(ctx, "NAMESPACE", "ADD", "ns1",
"token1").Err())
+ require.NoError(t, rdb.Do(ctx, "NAMESPACE", "SET", "ns1",
"token2").Err())
+ require.NoError(t, rdb.Do(ctx, "NAMESPACE", "DEL", "ns1").Err())
+ })
+}
diff --git a/tests/gocase/util/server.go b/tests/gocase/util/server.go
index 5d190750..a3f4314e 100644
--- a/tests/gocase/util/server.go
+++ b/tests/gocase/util/server.go
@@ -194,10 +194,16 @@ func StartTLSServer(t testing.TB, configs
map[string]string) *KvrocksServer {
}
func StartServer(t testing.TB, configs map[string]string) *KvrocksServer {
- return StartServerWithCLIOptions(t, configs, []string{})
+ return StartServerWithCLIOptions(t, true, configs, []string{})
}
-func StartServerWithCLIOptions(t testing.TB, configs map[string]string,
options []string) *KvrocksServer {
+func StartServerWithCLIOptions(
+ t testing.TB,
+ withConfigFile bool,
+ configs map[string]string,
+ options []string,
+) *KvrocksServer {
+
b := *binPath
require.NotEmpty(t, b, "please set the binary path by `-binPath`")
cmd := exec.Command(b)
@@ -215,16 +221,21 @@ func StartServerWithCLIOptions(t testing.TB, configs
map[string]string, options
require.NoError(t, err)
configs["dir"] = dir
- f, err := os.Create(filepath.Join(dir, "kvrocks.conf"))
- require.NoError(t, err)
- defer func() { require.NoError(t, f.Close()) }()
-
- for k := range configs {
- _, err := f.WriteString(fmt.Sprintf("%s %s\n", k, configs[k]))
+ if withConfigFile {
+ f, err := os.Create(filepath.Join(dir, "kvrocks.conf"))
require.NoError(t, err)
- }
+ defer func() { require.NoError(t, f.Close()) }()
- cmd.Args = append(cmd.Args, "-c", f.Name())
+ for k := range configs {
+ _, err := f.WriteString(fmt.Sprintf("%s %s\n", k,
configs[k]))
+ require.NoError(t, err)
+ }
+ cmd.Args = append(cmd.Args, "-c", f.Name())
+ } else {
+ for k := range configs {
+ cmd.Args = append(cmd.Args, fmt.Sprintf("--%s", k),
configs[k])
+ }
+ }
cmd.Args = append(cmd.Args, options...)
stdout, err := os.Create(filepath.Join(dir, "stdout"))