wip config
This commit is contained in:
parent
d6936636c2
commit
d8f11354df
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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":
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"] != "" {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user