Merge branch 'm1ome-gc-config'

This commit is contained in:
Josh Baker 2017-01-21 17:11:04 -07:00
commit 4d36e359ff
2 changed files with 84 additions and 14 deletions

View File

@ -14,7 +14,15 @@ import (
"github.com/tidwall/tile38/controller/server" "github.com/tidwall/tile38/controller/server"
) )
var validProperties = []string{"requirepass", "leaderauth", "protected-mode", "maxmemory"} const (
RequirePass = "requirepass"
LeaderAuth = "leaderauth"
ProtectedMode = "protected-mode"
MaxMemory = "maxmemory"
AutoGC = "autogc"
)
var validProperties = []string{RequirePass, LeaderAuth, ProtectedMode, MaxMemory, AutoGC}
// Config is a tile38 config // Config is a tile38 config
type Config struct { type Config struct {
@ -34,6 +42,8 @@ type Config struct {
ProtectedMode string `json:"-"` ProtectedMode string `json:"-"`
MaxMemoryP string `json:"maxmemory,omitempty"` MaxMemoryP string `json:"maxmemory,omitempty"`
MaxMemory int `json:"-"` MaxMemory int `json:"-"`
AutoGCP string `json:"autogc,omitempty"`
AutoGC uint64 `json:"-"`
} }
func (c *Controller) loadConfig() error { func (c *Controller) loadConfig() error {
@ -49,16 +59,19 @@ func (c *Controller) loadConfig() error {
return err return err
} }
// load properties // load properties
if err := c.setConfigProperty("requirepass", c.config.RequirePassP, true); err != nil { if err := c.setConfigProperty(RequirePass, c.config.RequirePassP, true); err != nil {
return err return err
} }
if err := c.setConfigProperty("leaderauth", c.config.LeaderAuthP, true); err != nil { if err := c.setConfigProperty(LeaderAuth, c.config.LeaderAuthP, true); err != nil {
return err return err
} }
if err := c.setConfigProperty("protected-mode", c.config.ProtectedModeP, true); err != nil { if err := c.setConfigProperty(ProtectedMode, c.config.ProtectedModeP, true); err != nil {
return err return err
} }
if err := c.setConfigProperty("maxmemory", c.config.MaxMemoryP, true); err != nil { if err := c.setConfigProperty(MaxMemory, c.config.MaxMemoryP, true); err != nil {
return err
}
if err := c.setConfigProperty(AutoGC, c.config.AutoGCP, true); err != nil {
return err return err
} }
return nil return nil
@ -115,17 +128,27 @@ func (c *Controller) setConfigProperty(name, value string, fromLoad bool) error
switch name { switch name {
default: default:
return fmt.Errorf("Unsupported CONFIG parameter: %s", name) return fmt.Errorf("Unsupported CONFIG parameter: %s", name)
case "requirepass": case RequirePass:
c.config.RequirePass = value c.config.RequirePass = value
case "leaderauth": case LeaderAuth:
c.config.LeaderAuth = value c.config.LeaderAuth = value
case "maxmemory": case AutoGC:
if value == "" {
c.config.AutoGC = 0
} else {
gc, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
c.config.AutoGC = gc
}
case MaxMemory:
sz, ok := parseMemSize(value) sz, ok := parseMemSize(value)
if !ok { if !ok {
return fmt.Errorf("Invalid argument '%s' for CONFIG SET '%s'", value, name) return fmt.Errorf("Invalid argument '%s' for CONFIG SET '%s'", value, name)
} }
c.config.MaxMemory = sz c.config.MaxMemory = sz
case "protected-mode": case ProtectedMode:
switch strings.ToLower(value) { switch strings.ToLower(value) {
case "": case "":
if fromLoad { if fromLoad {
@ -159,13 +182,15 @@ func (c *Controller) getConfigProperty(name string) string {
switch name { switch name {
default: default:
return "" return ""
case "requirepass": case AutoGC:
return strconv.FormatUint(c.config.AutoGC, 10)
case RequirePass:
return c.config.RequirePass return c.config.RequirePass
case "leaderauth": case LeaderAuth:
return c.config.LeaderAuth return c.config.LeaderAuth
case "protected-mode": case ProtectedMode:
return c.config.ProtectedMode return c.config.ProtectedMode
case "maxmemory": case MaxMemory:
return formatMemSize(c.config.MaxMemory) return formatMemSize(c.config.MaxMemory)
} }
} }
@ -190,6 +215,7 @@ func (c *Controller) writeConfig(writeProperties bool) error {
c.config.LeaderAuthP = c.config.LeaderAuth c.config.LeaderAuthP = c.config.LeaderAuth
c.config.ProtectedModeP = c.config.ProtectedMode c.config.ProtectedModeP = c.config.ProtectedMode
c.config.MaxMemoryP = formatMemSize(c.config.MaxMemory) c.config.MaxMemoryP = formatMemSize(c.config.MaxMemory)
c.config.AutoGCP = strconv.FormatUint(c.config.AutoGC, 10)
} }
var data []byte var data []byte
data, err = json.MarshalIndent(c.config, "", "\t") data, err = json.MarshalIndent(c.config, "", "\t")
@ -242,7 +268,7 @@ func (c *Controller) cmdConfigSet(msg *server.Message) (res string, err error) {
} }
var value string var value string
if vs, value, ok = tokenval(vs); !ok { if vs, value, ok = tokenval(vs); !ok {
if strings.ToLower(name) != "requirepass" { if strings.ToLower(name) != RequirePass {
return "", errInvalidNumberOfArguments return "", errInvalidNumberOfArguments
} }
} }

View File

@ -97,6 +97,7 @@ type Controller struct {
stopBackgroundExpiring bool stopBackgroundExpiring bool
stopWatchingMemory bool stopWatchingMemory bool
stopWatchingAutoGC bool
outOfMemory bool outOfMemory bool
} }
@ -178,11 +179,13 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http
}() }()
go c.processLives() go c.processLives()
go c.watchMemory() go c.watchMemory()
go c.watchGC()
go c.backgroundExpiring() go c.backgroundExpiring()
defer func() { defer func() {
c.mu.Lock() c.mu.Lock()
c.stopBackgroundExpiring = true c.stopBackgroundExpiring = true
c.stopWatchingMemory = true c.stopWatchingMemory = true
c.stopWatchingAutoGC = true
c.mu.Unlock() c.mu.Unlock()
}() }()
handler := func(conn *server.Conn, msg *server.Message, rd *server.AnyReaderWriter, w io.Writer, websocket bool) error { handler := func(conn *server.Conn, msg *server.Message, rd *server.AnyReaderWriter, w io.Writer, websocket bool) error {
@ -226,6 +229,47 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http
return server.ListenAndServe(host, port, protected, handler, opened, closed, ln, http) return server.ListenAndServe(host, port, protected, handler, opened, closed, ln, http)
} }
func (c *Controller) watchGC() {
t := time.NewTicker(time.Second)
defer t.Stop()
s := time.Now()
for range t.C {
c.mu.RLock()
if c.stopWatchingAutoGC {
c.mu.RUnlock()
return
}
autoGC := c.config.AutoGC
c.mu.RUnlock()
if autoGC == 0 {
continue
}
if time.Now().Sub(s) < time.Second*time.Duration(autoGC) {
continue
}
var mem1, mem2 runtime.MemStats
runtime.ReadMemStats(&mem1)
log.Debugf("autogc(before): "+
"alloc: %v, heap_alloc: %v, heap_released: %v",
mem1.Alloc, mem1.HeapAlloc, mem1.HeapReleased)
runtime.GC()
debug.FreeOSMemory()
runtime.ReadMemStats(&mem2)
log.Debugf("autogc(after): "+
"alloc: %v, heap_alloc: %v, heap_released: %v",
mem2.Alloc, mem2.HeapAlloc, mem2.HeapReleased)
s = time.Now()
}
}
func (c *Controller) watchMemory() { func (c *Controller) watchMemory() {
t := time.NewTicker(time.Second * 2) t := time.NewTicker(time.Second * 2)
defer t.Stop() defer t.Stop()