common/sentinel.go (100 lines of code) (raw):
package utils
import (
"encoding/json"
"fmt"
"reflect"
nimo "github.com/gugemichael/nimo4go"
LOG "github.com/vinllen/log4go"
)
const (
TypeFull = "full"
TypeIncr = "incr"
)
// IncrSentinelOptions. option's value type should be
// String or Bool or Int64
// only used in incremental sync.
var IncrSentinelOptions struct {
OplogDump int64
DuplicatedDump bool
Pause bool
TPS int64
TargetDelay int64
ExitPoint int64 // store 64 bit full timestamp
Shutdown bool // close shake
}
// only used in full sync.
var FullSentinelOptions struct {
TPS int64
}
func init() {
IncrSentinelOptions.TargetDelay = -1
IncrSentinelOptions.ExitPoint = -1
}
type Sentinel struct {
tp string
}
func NewSentinel(tp string) *Sentinel {
return &Sentinel{
tp: tp,
}
}
func (sentinel *Sentinel) getOptions() interface{} {
switch sentinel.tp {
case TypeFull:
return &FullSentinelOptions
case TypeIncr:
return &IncrSentinelOptions
}
return nil
}
func (sentinel *Sentinel) getProvider() *nimo.HttpRestProvider {
switch sentinel.tp {
case TypeFull:
return FullSyncHttpApi
case TypeIncr:
return IncrSyncHttpApi
}
return nil
}
func (sentinel *Sentinel) Register() {
provider := sentinel.getProvider()
provider.RegisterAPI("/sentinel", nimo.HttpGet, func([]byte) interface{} {
return sentinel.getOptions()
})
provider.RegisterAPI("/sentinel/options", nimo.HttpPost, func(body []byte) interface{} {
// check the exist of every option. options will be configured only
// if all the header kv pair are exist! this means that we ensure the
// operation consistency
options := sentinel.getOptions()
kv := make(map[string]interface{})
if err := json.Unmarshal(body, &kv); err != nil {
LOG.Info("Register set options wrong format : %v", err)
return map[string]string{"sentinel": "request json options wrong format"}
}
for name := range kv {
if !reflect.ValueOf(options).Elem().FieldByName(name).IsValid() {
return map[string]string{"sentinel": fmt.Sprintf("%s is not exist", name)}
}
}
for name, value := range kv {
field := reflect.ValueOf(options).Elem().FieldByName(name)
switch field.Kind() {
case reflect.Bool:
if v, ok := value.(bool); ok {
field.SetBool(v)
continue
}
case reflect.Int64:
// fmt.Printf("%s, %v, %s", name, value, reflect.TypeOf(value).String())
if v, ok := value.(float64); ok {
if name == "TargetDelay" && int64(v) < 0 {
v = 0
}
field.SetInt(int64(v))
continue
}
case reflect.String:
if v, ok := value.(string); ok {
field.SetString(v)
continue
}
default:
}
return map[string]string{"sentinel": fmt.Sprintf("%s option isn't corret", name)}
}
LOG.Info("new sentinel options: %v", options)
return map[string]string{"sentinel": "success"}
})
}