Skip to content

Commit

Permalink
*: fix the data overflow bug radondb#125
Browse files Browse the repository at this point in the history
  • Loading branch information
zhyass committed Jun 30, 2021
1 parent 4c7a87f commit af7ec63
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 34 deletions.
3 changes: 1 addition & 2 deletions api/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
Expand Down Expand Up @@ -149,7 +148,7 @@ type MetricsOpts struct {

// MysqlConf defines type for extra cluster configs. It's a simple map between
// string and string.
type MysqlConf map[string]intstr.IntOrString
type MysqlConf map[string]string

// PodSpec defines type for configure cluster pod spec.
type PodSpec struct {
Expand Down
61 changes: 48 additions & 13 deletions cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ package cluster
import (
"fmt"
"math"
"strconv"
"strings"
"unicode"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

apiv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1"
Expand All @@ -34,8 +36,8 @@ import (

// nolint: megacheck, deadcode, varcheck
const (
_ = iota // ignore first value by assigning to blank identifier
kb int64 = 1 << (10 * iota)
_ = iota // ignore first value by assigning to blank identifier
kb uint64 = 1 << (10 * iota)
mb
gb
)
Expand Down Expand Up @@ -257,26 +259,59 @@ func (c *Cluster) EnsureMysqlConf() {
c.Spec.MysqlOpts.MysqlConf = make(apiv1alpha1.MysqlConf)
}

var defaultSize, maxSize, innodbBufferPoolSize int64
var defaultSize, maxSize, innodbBufferPoolSize uint64
innodbBufferPoolSize = 128 * mb
conf, ok := c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]
mem := c.Spec.MysqlOpts.Resources.Requests.Memory().Value()
mem := uint64(c.Spec.MysqlOpts.Resources.Requests.Memory().Value())
cpu := c.Spec.PodSpec.Resources.Limits.Cpu().MilliValue()
if mem <= 1*gb {
defaultSize = int64(0.45 * float64(mem))
maxSize = int64(0.6 * float64(mem))
defaultSize = uint64(0.45 * float64(mem))
maxSize = uint64(0.6 * float64(mem))
} else {
defaultSize = int64(0.6 * float64(mem))
maxSize = int64(0.8 * float64(mem))
defaultSize = uint64(0.6 * float64(mem))
maxSize = uint64(0.8 * float64(mem))
}

conf, ok := c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]
if !ok {
innodbBufferPoolSize = utils.Max(defaultSize, innodbBufferPoolSize)
} else {
innodbBufferPoolSize = utils.Min(utils.Max(int64(conf.IntVal), innodbBufferPoolSize), maxSize)
if nums, err := sizeToBytes(conf); err != nil {
innodbBufferPoolSize = utils.Max(defaultSize, innodbBufferPoolSize)
} else {
innodbBufferPoolSize = utils.Min(utils.Max(nums, innodbBufferPoolSize), maxSize)
}
}

instances := math.Max(math.Min(math.Ceil(float64(cpu)/float64(1000)), math.Floor(float64(innodbBufferPoolSize)/float64(gb))), 1)
c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = intstr.FromInt(int(innodbBufferPoolSize))
c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"] = intstr.FromInt(int(instances))
c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = strconv.FormatUint(innodbBufferPoolSize, 10)
c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"] = strconv.Itoa(int(instances))
}

// sizeToBytes parses a string formatted by ByteSize as bytes.
// K = 1024
// M = 1024 * K
// G = 1024 * M
func sizeToBytes(s string) (uint64, error) {
s = strings.TrimSpace(s)
s = strings.ToUpper(s)

idx := strings.IndexFunc(s, unicode.IsLetter)
if idx == -1 {
return strconv.ParseUint(s, 10, 64)
}

nums, err := strconv.ParseUint(s[:idx], 10, 64)
if err != nil {
return 0, err
}

switch s[idx:] {
case "K":
return nums * kb, nil
case "M":
return nums * mb, nil
case "G":
return nums * gb, nil
}
return 0, fmt.Errorf("'%s' format error, must be a positive integer with a unit of measurement like K, M or G", s)
}
21 changes: 4 additions & 17 deletions cluster/syncer/config_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"github.com/presslabs/controller-util/syncer"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/radondb/radondb-mysql-kubernetes/cluster"
Expand Down Expand Up @@ -69,11 +68,10 @@ func buildMysqlConf(c *cluster.Cluster) (string, error) {

c.EnsureMysqlConf()

addKVConfigsToSection(sec, convertMapToKVConfig(mysqlSysConfigs), convertMapToKVConfig(mysqlCommonConfigs),
convertMapToKVConfig(mysqlStaticConfigs), c.Spec.MysqlOpts.MysqlConf)
addKVConfigsToSection(sec, mysqlSysConfigs, mysqlCommonConfigs, mysqlStaticConfigs, c.Spec.MysqlOpts.MysqlConf)

if c.Spec.MysqlOpts.InitTokuDB {
addKVConfigsToSection(sec, convertMapToKVConfig(mysqlTokudbConfigs))
addKVConfigsToSection(sec, mysqlTokudbConfigs)
}

for _, key := range mysqlBooleanConfigs {
Expand All @@ -91,7 +89,7 @@ func buildMysqlConf(c *cluster.Cluster) (string, error) {
}

// addKVConfigsToSection add a map[string]string to a ini.Section
func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]intstr.IntOrString) {
func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]string) {
for _, extra := range extraMysqld {
keys := []string{}
for key := range extra {
Expand All @@ -103,24 +101,13 @@ func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]intstr.IntO

for _, k := range keys {
value := extra[k]
if _, err := s.NewKey(k, value.String()); err != nil {
if _, err := s.NewKey(k, value); err != nil {
log.Error(err, "failed to add key to config section", "key", k, "value", extra[k], "section", s)
}
}
}
}

// convertMapToKVConfig convert map to kv config.
func convertMapToKVConfig(m map[string]string) map[string]intstr.IntOrString {
config := make(map[string]intstr.IntOrString)

for key, value := range m {
config[key] = intstr.FromString(value)
}

return config
}

// writeConfigs write to string ini.File
// nolint: interfacer
func writeConfigs(cfg *ini.File) (string, error) {
Expand Down
4 changes: 4 additions & 0 deletions config/samples/mysql_v1alpha1_cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ spec:
database: qingcloud
initTokuDB: true

# A simple map between string and string.
# Such as:
# mysqlConf:
# expire_logs_days: "7"
mysqlConf: {}

resources:
Expand Down
4 changes: 2 additions & 2 deletions utils/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ limitations under the License.
package utils

// Min returns the smallest int64 that was passed in the arguments.
func Min(a, b int64) int64 {
func Min(a, b uint64) uint64 {
if a < b {
return a
}
return b
}

// Max returns the largest int64 that was passed in the arguments.
func Max(a, b int64) int64 {
func Max(a, b uint64) uint64 {
if a > b {
return a
}
Expand Down

0 comments on commit af7ec63

Please sign in to comment.