diff --git a/controller/aof.go b/controller/aof.go index f094d394..813f719e 100644 --- a/controller/aof.go +++ b/controller/aof.go @@ -166,7 +166,7 @@ func (c *Controller) writeAOF(value resp.Value, d *commandDetailsT) error { if !d.updated { return nil // just ignore writes if the command did not update } - if c.config.FollowHost == "" { + if c.config.followHost() == "" { // process hooks, for leader only if d.parent { // process children only diff --git a/controller/config.go b/controller/config.go index 0f3827cb..da9a334a 100644 --- a/controller/config.go +++ b/controller/config.go @@ -7,8 +7,10 @@ import ( "os" "strconv" "strings" + "sync" "time" + "github.com/tidwall/gjson" "github.com/tidwall/resp" "github.com/tidwall/tile38/controller/glob" "github.com/tidwall/tile38/controller/server" @@ -20,6 +22,12 @@ const ( ) const ( + FollowHost = "follow_host" + FollowPort = "follow_port" + FollowID = "follow_id" + FollowPos = "follow_pos" + ServerID = "server_id" + ReadOnly = "read_only" RequirePass = "requirepass" LeaderAuth = "leaderauth" ProtectedMode = "protected-mode" @@ -32,82 +40,309 @@ var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory // Config is a tile38 config type Config struct { - FollowHost string `json:"follow_host,omitempty"` - FollowPort int `json:"follow_port,omitempty"` - FollowID string `json:"follow_id,omitempty"` - FollowPos int `json:"follow_pos,omitempty"` - ServerID string `json:"server_id,omitempty"` - ReadOnly bool `json:"read_only,omitempty"` + path string - // Properties - RequirePassP string `json:"requirepass,omitempty"` - RequirePass string `json:"-"` - LeaderAuthP string `json:"leaderauth,omitempty"` - LeaderAuth string `json:"-"` - ProtectedModeP string `json:"protected-mode,omitempty"` - ProtectedMode string `json:"-"` - MaxMemoryP string `json:"maxmemory,omitempty"` - MaxMemory int `json:"-"` - AutoGCP string `json:"autogc,omitempty"` - AutoGC uint64 `json:"-"` - KeepAliveP string `json:"keepalive,omitempty"` - KeepAlive int `json:"-"` + mu sync.RWMutex + + _followHost string + _followPort int64 + _followID string + _followPos int64 + _serverID string + _readOnly bool + + _requirePassP string + _requirePass string + _leaderAuthP string + _leaderAuth string + _protectedModeP string + _protectedMode string + _maxMemoryP string + _maxMemory int64 + _autoGCP string + _autoGC uint64 + _keepAliveP string + _keepAlive int64 } -func (c *Controller) loadConfig() error { - data, err := ioutil.ReadFile(c.dir + "/config") +func loadConfig(path string) (*Config, error) { + data, err := ioutil.ReadFile(path) if err != nil { if os.IsNotExist(err) { - return c.initConfig() + config := &Config{path: path, _serverID: randomKey(16)} + config.write(true) + return config, nil } - return err + return nil, err } - err = json.Unmarshal(data, &c.config) - if err != nil { - return err + json := string(data) + config := &Config{ + path: path, + _followHost: gjson.Get(json, FollowHost).String(), + _followPort: gjson.Get(json, FollowPort).Int(), + _followID: gjson.Get(json, FollowID).String(), + _followPos: gjson.Get(json, FollowPos).Int(), + _serverID: gjson.Get(json, ServerID).String(), + _readOnly: gjson.Get(json, ReadOnly).Bool(), + _requirePassP: gjson.Get(json, RequirePass).String(), + _leaderAuthP: gjson.Get(json, LeaderAuth).String(), + _protectedModeP: gjson.Get(json, ProtectedMode).String(), + _maxMemoryP: gjson.Get(json, MaxMemory).String(), + _autoGCP: gjson.Get(json, AutoGC).String(), + _keepAliveP: gjson.Get(json, KeepAlive).String(), } // load properties - if err := c.setConfigProperty(RequirePass, c.config.RequirePassP, true); err != nil { - return err + if err := config.setProperty(RequirePass, config._requirePassP, true); err != nil { + return nil, err } - if err := c.setConfigProperty(LeaderAuth, c.config.LeaderAuthP, true); err != nil { - return err + if err := config.setProperty(LeaderAuth, config._leaderAuthP, true); err != nil { + return nil, err } - if err := c.setConfigProperty(ProtectedMode, c.config.ProtectedModeP, true); err != nil { - return err + if err := config.setProperty(ProtectedMode, config._protectedModeP, true); err != nil { + println(2) + return nil, err } - if err := c.setConfigProperty(MaxMemory, c.config.MaxMemoryP, true); err != nil { - return err + if err := config.setProperty(MaxMemory, config._maxMemoryP, true); err != nil { + return nil, err } - if err := c.setConfigProperty(AutoGC, c.config.AutoGCP, true); err != nil { - return err + if err := config.setProperty(AutoGC, config._autoGCP, true); err != nil { + return nil, err } - if err := c.setConfigProperty(KeepAlive, c.config.KeepAliveP, true); err != nil { - return err + if err := config.setProperty(KeepAlive, config._keepAliveP, true); err != nil { + return nil, err } - return nil + config.write(false) + return config, nil } -func parseMemSize(s string) (bytes int, ok bool) { +func (config *Config) write(writeProperties bool) { + config.mu.Lock() + defer config.mu.Unlock() + + if writeProperties { + // save properties + config._requirePassP = config._requirePass + config._leaderAuthP = config._leaderAuth + if config._protectedMode == defaultProtectedMode { + config._protectedModeP = "" + } else { + config._protectedModeP = config._protectedMode + } + config._maxMemoryP = formatMemSize(config._maxMemory) + if config._autoGC == 0 { + config._autoGCP = "" + } else { + config._autoGCP = strconv.FormatUint(config._autoGC, 10) + } + if config._keepAlive == defaultKeepAlive { + config._keepAliveP = "" + } else { + config._keepAliveP = strconv.FormatUint(uint64(config._keepAlive), 10) + } + } + + m := make(map[string]interface{}) + if config._followHost != "" { + m[FollowHost] = config._followHost + } + if config._followPort != 0 { + m[FollowPort] = config._followPort + } + if config._followID != "" { + m[FollowID] = config._followID + } + if config._followPos != 0 { + m[FollowPos] = config._followPos + } + if config._serverID != "" { + m[ServerID] = config._serverID + } + if config._readOnly { + m[ReadOnly] = config._readOnly + } + if config._requirePassP != "" { + m[RequirePass] = config._requirePassP + } + if config._leaderAuthP != "" { + m[LeaderAuth] = config._leaderAuthP + } + if config._protectedModeP != "" { + m[ProtectedMode] = config._protectedModeP + } + if config._maxMemoryP != "" { + m[MaxMemory] = config._maxMemoryP + } + if config._autoGCP != "" { + m[AutoGC] = config._autoGCP + } + if config._keepAliveP != "" { + m[KeepAlive] = config._keepAliveP + } + data, err := json.MarshalIndent(m, "", "\t") + if err != nil { + panic(err) + } + data = append(data, '\n') + err = ioutil.WriteFile(config.path, data, 0600) + if err != nil { + panic(err) + } +} + +func (config *Config) followHost() string { + config.mu.RLock() + v := config._followHost + config.mu.RUnlock() + return v +} +func (config *Config) followPort() int { + config.mu.RLock() + v := config._followPort + config.mu.RUnlock() + return int(v) +} +func (config *Config) followID() string { + config.mu.RLock() + v := config._followID + config.mu.RUnlock() + return v +} +func (config *Config) followPos() int64 { + config.mu.RLock() + v := config._followPos + config.mu.RUnlock() + return v +} +func (config *Config) serverID() string { + config.mu.RLock() + v := config._serverID + config.mu.RUnlock() + return v +} +func (config *Config) readOnly() bool { + config.mu.RLock() + v := config._readOnly + config.mu.RUnlock() + return v +} +func (config *Config) requirePass() string { + config.mu.RLock() + v := config._requirePass + config.mu.RUnlock() + return v +} +func (config *Config) leaderAuth() string { + config.mu.RLock() + v := config._leaderAuth + config.mu.RUnlock() + return v +} +func (config *Config) protectedMode() string { + config.mu.RLock() + v := config._protectedMode + config.mu.RUnlock() + return v +} +func (config *Config) maxMemory() int { + config.mu.RLock() + v := config._maxMemory + config.mu.RUnlock() + return int(v) +} +func (config *Config) autoGC() uint64 { + config.mu.RLock() + v := config._autoGC + config.mu.RUnlock() + return v +} +func (config *Config) keepAlive() int64 { + config.mu.RLock() + v := config._keepAlive + config.mu.RUnlock() + return v +} + +func (config *Config) setFollowHost(v string) { + config.mu.Lock() + config._followHost = v + config.mu.Unlock() +} +func (config *Config) setFollowPort(v int) { + config.mu.Lock() + config._followPort = int64(v) + config.mu.Unlock() +} +func (config *Config) setFollowID(v string) { + config.mu.Lock() + config._followID = v + config.mu.Unlock() +} +func (config *Config) setFollowPos(v int64) { + config.mu.Lock() + config._followPos = v + config.mu.Unlock() +} +func (config *Config) setServerID(v string) { + config.mu.Lock() + config._serverID = v + config.mu.Unlock() +} +func (config *Config) setReadOnly(v bool) { + config.mu.Lock() + config._readOnly = v + config.mu.Unlock() +} +func (config *Config) setRequirePass(v string) { + config.mu.Lock() + config._requirePass = v + config.mu.Unlock() +} +func (config *Config) setLeaderAuth(v string) { + config.mu.Lock() + config._leaderAuth = v + config.mu.Unlock() +} +func (config *Config) setProtectedMode(v string) { + config.mu.Lock() + config._protectedMode = v + config.mu.Unlock() +} +func (config *Config) setMaxMemory(v int) { + config.mu.Lock() + config._maxMemory = int64(v) + config.mu.Unlock() +} +func (config *Config) setAutoGC(v uint64) { + config.mu.Lock() + config._autoGC = v + config.mu.Unlock() +} +func (config *Config) setKeepAlive(v int64) { + config.mu.Lock() + config._keepAlive = v + config.mu.Unlock() +} + +func parseMemSize(s string) (bytes int64, ok bool) { if s == "" { return 0, true } s = strings.ToLower(s) var n uint64 - var sz int + var sz int64 var err error if strings.HasSuffix(s, "gb") { n, err = strconv.ParseUint(s[:len(s)-2], 10, 64) - sz = int(n * 1024 * 1024 * 1024) + sz = int64(n * 1024 * 1024 * 1024) } else if strings.HasSuffix(s, "mb") { n, err = strconv.ParseUint(s[:len(s)-2], 10, 64) - sz = int(n * 1024 * 1024) + sz = int64(n * 1024 * 1024) } else if strings.HasSuffix(s, "kb") { n, err = strconv.ParseUint(s[:len(s)-2], 10, 64) - sz = int(n * 1024) + sz = int64(n * 1024) } else { n, err = strconv.ParseUint(s, 10, 64) - sz = int(n) + sz = int64(n) } if err != nil { return 0, false @@ -115,72 +350,74 @@ func parseMemSize(s string) (bytes int, ok bool) { return sz, true } -func formatMemSize(sz int) string { +func formatMemSize(sz int64) string { if sz <= 0 { return "" } if sz < 1024 { - return strconv.FormatInt(int64(sz), 10) + return strconv.FormatInt(sz, 10) } sz /= 1024 if sz < 1024 { - return strconv.FormatInt(int64(sz), 10) + "kb" + return strconv.FormatInt(sz, 10) + "kb" } sz /= 1024 if sz < 1024 { - return strconv.FormatInt(int64(sz), 10) + "mb" + return strconv.FormatInt(sz, 10) + "mb" } sz /= 1024 - return strconv.FormatInt(int64(sz), 10) + "gb" + return strconv.FormatInt(sz, 10) + "gb" } -func (c *Controller) setConfigProperty(name, value string, fromLoad bool) error { +func (config *Config) setProperty(name, value string, fromLoad bool) error { + config.mu.Lock() + defer config.mu.Unlock() var invalid bool switch name { default: return fmt.Errorf("Unsupported CONFIG parameter: %s", name) case RequirePass: - c.config.RequirePass = value + config._requirePass = value case LeaderAuth: - c.config.LeaderAuth = value + config._leaderAuth = value case AutoGC: if value == "" { - c.config.AutoGC = 0 + config._autoGC = 0 } else { gc, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } - c.config.AutoGC = gc + config._autoGC = gc } case MaxMemory: sz, ok := parseMemSize(value) if !ok { return fmt.Errorf("Invalid argument '%s' for CONFIG SET '%s'", value, name) } - c.config.MaxMemory = sz + config._maxMemory = sz case ProtectedMode: switch strings.ToLower(value) { case "": if fromLoad { - c.config.ProtectedMode = defaultProtectedMode + config._protectedMode = defaultProtectedMode } else { invalid = true } case "yes", "no": - c.config.ProtectedMode = strings.ToLower(value) + config._protectedMode = strings.ToLower(value) default: invalid = true } case KeepAlive: if value == "" { - c.config.KeepAlive = defaultKeepAlive + config._keepAlive = defaultKeepAlive } else { keepalive, err := strconv.ParseUint(value, 10, 64) if err != nil { invalid = true } else { - c.config.KeepAlive = int(keepalive) + config._keepAlive = int64(keepalive) } } } @@ -191,83 +428,38 @@ func (c *Controller) setConfigProperty(name, value string, fromLoad bool) error return nil } -func (c *Controller) getConfigProperties(pattern string) map[string]interface{} { +func (config *Config) getProperties(pattern string) map[string]interface{} { m := make(map[string]interface{}) for _, name := range validProperties { matched, _ := glob.Match(pattern, name) if matched { - m[name] = c.getConfigProperty(name) + m[name] = config.getProperty(name) } } return m } -func (c *Controller) getConfigProperty(name string) string { + +func (config *Config) getProperty(name string) string { + config.mu.RLock() + defer config.mu.RUnlock() switch name { default: return "" case AutoGC: - return strconv.FormatUint(c.config.AutoGC, 10) + return strconv.FormatUint(config._autoGC, 10) case RequirePass: - return c.config.RequirePass + return config._requirePass case LeaderAuth: - return c.config.LeaderAuth + return config._leaderAuth case ProtectedMode: - return c.config.ProtectedMode + return config._protectedMode case MaxMemory: - return formatMemSize(c.config.MaxMemory) + return formatMemSize(config._maxMemory) case KeepAlive: - return strconv.FormatUint(uint64(c.config.KeepAlive), 10) + return strconv.FormatUint(uint64(config._keepAlive), 10) } } -func (c *Controller) initConfig() error { - c.config = Config{ServerID: randomKey(16)} - return c.writeConfig(true) -} - -func (c *Controller) writeConfig(writeProperties bool) error { - var err error - bak := c.config - defer func() { - if err != nil { - // revert changes - c.config = bak - } - }() - if writeProperties { - // save properties - c.config.RequirePassP = c.config.RequirePass - c.config.LeaderAuthP = c.config.LeaderAuth - if c.config.ProtectedMode == defaultProtectedMode { - c.config.ProtectedModeP = "" - } else { - c.config.ProtectedModeP = c.config.ProtectedMode - } - c.config.MaxMemoryP = formatMemSize(c.config.MaxMemory) - if c.config.AutoGC == 0 { - c.config.AutoGCP = "" - } else { - c.config.AutoGCP = strconv.FormatUint(c.config.AutoGC, 10) - } - if c.config.KeepAlive == defaultKeepAlive { - c.config.KeepAliveP = "" - } else { - c.config.KeepAliveP = strconv.FormatUint(uint64(c.config.KeepAlive), 10) - } - } - var data []byte - data, err = json.MarshalIndent(c.config, "", "\t") - if err != nil { - return err - } - data = append(data, '\n') - err = ioutil.WriteFile(c.dir+"/config", data, 0600) - if err != nil { - return err - } - return nil -} - func (c *Controller) cmdConfigGet(msg *server.Message) (res string, err error) { start := time.Now() vs := msg.Values[1:] @@ -279,7 +471,7 @@ func (c *Controller) cmdConfigGet(msg *server.Message) (res string, err error) { if len(vs) != 0 { return "", errInvalidNumberOfArguments } - m := c.getConfigProperties(name) + m := c.config.getProperties(name) switch msg.OutputType { case server.JSON: data, err := json.Marshal(m) @@ -314,7 +506,7 @@ func (c *Controller) cmdConfigSet(msg *server.Message) (res string, err error) { if len(vs) != 0 { return "", errInvalidNumberOfArguments } - if err := c.setConfigProperty(name, value, false); err != nil { + if err := c.config.setProperty(name, value, false); err != nil { return "", err } return server.OKMessage(msg, start), nil @@ -325,8 +517,6 @@ func (c *Controller) cmdConfigRewrite(msg *server.Message) (res string, err erro if len(vs) != 0 { return "", errInvalidNumberOfArguments } - if err := c.writeConfig(true); err != nil { - return "", err - } + c.config.write(true) return server.OKMessage(msg, start), nil } diff --git a/controller/controller.go b/controller/controller.go index fabba113..4798445a 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -9,6 +9,7 @@ import ( "net" "os" "path" + "path/filepath" "runtime" "runtime/debug" "strings" @@ -76,7 +77,7 @@ type Controller struct { cols *btree.BTree aofsz int dir string - config Config + config *Config followc uint64 // counter increases when follow property changes follows map[*bytes.Buffer]bool fcond *sync.Cond @@ -138,7 +139,9 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http if err := os.MkdirAll(dir, 0700); err != nil { return err } - if err := c.loadConfig(); err != nil { + var err error + c.config, err = loadConfig(filepath.Join(dir, "config")) + if err != nil { return err } // load the queue before the aof @@ -179,8 +182,8 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http } c.mu.Lock() c.fillExpiresList() - if c.config.FollowHost != "" { - go c.follow(c.config.FollowHost, c.config.FollowPort, c.followc) + if c.config.followHost() != "" { + go c.follow(c.config.followHost(), c.config.followPort(), c.followc) } c.mu.Unlock() defer func() { @@ -225,17 +228,17 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http return false } c.mu.RLock() - is := c.config.ProtectedMode != "no" && c.config.RequirePass == "" + is := c.config.protectedMode() != "no" && c.config.requirePass() == "" c.mu.RUnlock() return is } - var clientId uint64 + var clientId uint64 opened := func(conn *server.Conn) { c.mu.Lock() - if c.config.KeepAlive > 0 { + if c.config.keepAlive() > 0 { err := conn.SetKeepAlive( - time.Duration(c.config.KeepAlive) * time.Second) + time.Duration(c.config.keepAlive()) * time.Second) if err != nil { log.Warnf("could not set keepalive for connection: %v", conn.RemoteAddr().String()) @@ -271,14 +274,13 @@ func (c *Controller) watchGC() { return } - autoGC := c.config.AutoGC c.mu.RUnlock() - if autoGC == 0 { + if c.config.autoGC() == 0 { continue } - if time.Now().Sub(s) < time.Second*time.Duration(autoGC) { + if time.Now().Sub(s) < time.Second*time.Duration(c.config.autoGC()) { continue } @@ -310,10 +312,9 @@ func (c *Controller) watchMemory() { c.mu.RUnlock() return } - maxmem := c.config.MaxMemory oom := c.outOfMemory c.mu.RUnlock() - if maxmem == 0 { + if c.config.maxMemory() == 0 { if oom { c.mu.Lock() c.outOfMemory = false @@ -326,7 +327,7 @@ func (c *Controller) watchMemory() { } runtime.ReadMemStats(&mem) c.mu.Lock() - c.outOfMemory = int(mem.HeapAlloc) > maxmem + c.outOfMemory = int(mem.HeapAlloc) > c.config.maxMemory() c.mu.Unlock() }() } @@ -443,10 +444,7 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message, var write bool if !conn.Authenticated || msg.Command == "auth" { - c.mu.RLock() - requirePass := c.config.RequirePass - c.mu.RUnlock() - if requirePass != "" { + if c.config.requirePass() != "" { password := "" // This better be an AUTH command or the Message should contain an Auth if msg.Command != "auth" && msg.Auth == "" { @@ -460,7 +458,7 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message, password = msg.Values[1].String() } } - if requirePass != strings.TrimSpace(password) { + if c.config.requirePass() != strings.TrimSpace(password) { return writeErr(errors.New("invalid password")) } conn.Authenticated = true @@ -482,10 +480,10 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message, write = true c.mu.Lock() defer c.mu.Unlock() - if c.config.FollowHost != "" { + if c.config.followHost() != "" { return writeErr(errors.New("not the leader")) } - if c.config.ReadOnly { + if c.config.readOnly() { return writeErr(errors.New("read only")) } case "get", "keys", "scan", "nearby", "within", "intersects", "hooks", "search", @@ -493,7 +491,7 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message, // read operations c.mu.RLock() defer c.mu.RUnlock() - if c.config.FollowHost != "" && !c.fcuponce { + if c.config.followHost() != "" && !c.fcuponce { return writeErr(errors.New("catching up to leader")) } case "follow", "readonly", "config": diff --git a/controller/crud.go b/controller/crud.go index be0bd150..02242118 100644 --- a/controller/crud.go +++ b/controller/crud.go @@ -716,7 +716,7 @@ func (c *Controller) parseSetArgs(vs []resp.Value) ( } func (c *Controller) cmdSet(msg *server.Message) (res string, d commandDetailsT, err error) { - if c.config.MaxMemory > 0 && c.outOfMemory { + if c.config.maxMemory() > 0 && c.outOfMemory { err = errOOM return } diff --git a/controller/follow.go b/controller/follow.go index c31978e4..901ec9f6 100644 --- a/controller/follow.go +++ b/controller/follow.go @@ -36,19 +36,18 @@ func (c *Controller) cmdFollow(msg *server.Message) (res string, err error) { host = strings.ToLower(host) sport = strings.ToLower(sport) var update bool - pconfig := c.config if host == "no" && sport == "one" { - update = c.config.FollowHost != "" || c.config.FollowPort != 0 - c.config.FollowHost = "" - c.config.FollowPort = 0 + update = c.config.followHost() != "" || c.config.followPort() != 0 + c.config.setFollowHost("") + c.config.setFollowPort(0) } else { n, err := strconv.ParseUint(sport, 10, 64) if err != nil { return "", errInvalidArgument(sport) } port := int(n) - update = c.config.FollowHost != host || c.config.FollowPort != port - auth := c.config.LeaderAuth + update = c.config.followHost() != host || c.config.followPort() != port + auth := c.config.leaderAuth() if update { c.mu.Unlock() conn, err := DialTimeout(fmt.Sprintf("%s:%d", host, port), time.Second*2) @@ -71,7 +70,7 @@ func (c *Controller) cmdFollow(msg *server.Message) (res string, err error) { c.mu.Lock() return "", fmt.Errorf("cannot follow: invalid id") } - if m["id"] == c.config.ServerID { + if m["id"] == c.config.serverID() { c.mu.Lock() return "", fmt.Errorf("cannot follow self") } @@ -81,18 +80,15 @@ func (c *Controller) cmdFollow(msg *server.Message) (res string, err error) { } c.mu.Lock() } - c.config.FollowHost = host - c.config.FollowPort = port - } - if err := c.writeConfig(false); err != nil { - c.config = pconfig // revert - return "", err + c.config.setFollowHost(host) + c.config.setFollowPort(port) } + c.config.write(false) if update { c.followc++ - if c.config.FollowHost != "" { + if c.config.followHost() != "" { log.Infof("following new host '%s' '%s'.", host, sport) - go c.follow(c.config.FollowHost, c.config.FollowPort, c.followc) + go c.follow(c.config.followHost(), c.config.followPort(), c.followc) } else { log.Infof("following no one") } @@ -159,7 +155,7 @@ func (c *Controller) followStep(host string, port int, followc uint64) error { return errNoLongerFollowing } c.fcup = false - auth := c.config.LeaderAuth + auth := c.config.leaderAuth() c.mu.Unlock() addr := fmt.Sprintf("%s:%d", host, port) @@ -182,7 +178,7 @@ func (c *Controller) followStep(host string, port int, followc uint64) error { if m["id"] == "" { return fmt.Errorf("cannot follow: invalid id") } - if m["id"] == c.config.ServerID { + if m["id"] == c.config.serverID() { return fmt.Errorf("cannot follow self") } if m["following"] != "" { diff --git a/controller/readonly.go b/controller/readonly.go index 12ad6f95..71d8eca7 100644 --- a/controller/readonly.go +++ b/controller/readonly.go @@ -20,29 +20,24 @@ func (c *Controller) cmdReadOnly(msg *server.Message) (res string, err error) { return "", errInvalidNumberOfArguments } update := false - backup := c.config switch strings.ToLower(arg) { default: return "", errInvalidArgument(arg) case "yes": - if !c.config.ReadOnly { + if !c.config.readOnly() { update = true - c.config.ReadOnly = true + c.config.setReadOnly(true) log.Info("read only") } case "no": - if c.config.ReadOnly { + if c.config.readOnly() { update = true - c.config.ReadOnly = false + c.config.setReadOnly(false) log.Info("read write") } } if update { - err := c.writeConfig(false) - if err != nil { - c.config = backup - return "", err - } + c.config.write(false) } return server.OKMessage(msg, start), nil } diff --git a/controller/stats.go b/controller/stats.go index ffc0b460..386ef06e 100644 --- a/controller/stats.go +++ b/controller/stats.go @@ -76,9 +76,9 @@ func (c *Controller) cmdServer(msg *server.Message) (res string, err error) { return "", errInvalidNumberOfArguments } m := make(map[string]interface{}) - m["id"] = c.config.ServerID - if c.config.FollowHost != "" { - m["following"] = fmt.Sprintf("%s:%d", c.config.FollowHost, c.config.FollowPort) + m["id"] = c.config.serverID() + if c.config.followHost() != "" { + m["following"] = fmt.Sprintf("%s:%d", c.config.followHost(), c.config.followPort()) m["caught_up"] = c.fcup m["caught_up_once"] = c.fcuponce } @@ -116,10 +116,10 @@ func (c *Controller) cmdServer(msg *server.Message) (res string, err error) { m["mem_alloc"] = mem.Alloc m["heap_size"] = mem.HeapAlloc m["heap_released"] = mem.HeapReleased - m["max_heap_size"] = c.config.MaxMemory + m["max_heap_size"] = c.config.maxMemory() m["avg_item_size"] = avgsz m["pointer_size"] = (32 << uintptr(uint64(^uintptr(0))>>63)) / 8 - m["read_only"] = c.config.ReadOnly + m["read_only"] = c.config.readOnly() switch msg.OutputType { case server.JSON: