Skip to content

Commit

Permalink
Adjust settings for promscale
Browse files Browse the repository at this point in the history
Set wal_compression = 1
Set bgwriter_flush_after = 0
Set shared_buffers = 50% of total memory
Do not recommend for bgwriter_delay or bgwriter_lru_maxpages
  • Loading branch information
jgpruitt committed Dec 13, 2022
1 parent db830a3 commit 5c8b365
Show file tree
Hide file tree
Showing 13 changed files with 396 additions and 116 deletions.
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
module github.com/timescale/timescaledb-tune

go 1.12
go 1.18

require (
github.com/fatih/color v1.9.0
github.com/pbnjay/memory v0.0.0-20190104145345-974d429e7ae4
)

require (
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.11 // indirect
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
)
37 changes: 5 additions & 32 deletions pkg/pgtune/background_writer.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
package pgtune

import "github.com/timescale/timescaledb-tune/internal/parse"

const (
BgwriterDelayKey = "bgwriter_delay"
BgwriterLRUMaxPagesKey = "bgwriter_lru_maxpages"
BgwriterFlushAfterKey = "bgwriter_flush_after"

promscaleDefaultBgwriterDelay = "10ms"
promscaleDefaultBgwriterLRUMaxPages = "100000"
promscaleDefaultBgwriterFlushAfter = "0"
)

// BgwriterLabel is the label used to refer to the background writer settings group
const BgwriterLabel = "background writer"

var BgwriterKeys = []string{
BgwriterDelayKey,
BgwriterLRUMaxPagesKey,
BgwriterFlushAfterKey,
}

// PromscaleBgwriterRecommender gives recommendations for the background writer for the promscale profile
Expand All @@ -30,10 +25,8 @@ func (r *PromscaleBgwriterRecommender) IsAvailable() bool {
// file for a given key.
func (r *PromscaleBgwriterRecommender) Recommend(key string) string {
switch key {
case BgwriterDelayKey:
return promscaleDefaultBgwriterDelay
case BgwriterLRUMaxPagesKey:
return promscaleDefaultBgwriterLRUMaxPages
case BgwriterFlushAfterKey:
return promscaleDefaultBgwriterFlushAfter
default:
return NoRecommendation
}
Expand Down Expand Up @@ -61,23 +54,3 @@ func (sg *BgwriterSettingsGroup) GetRecommender(profile Profile) Recommender {
return &NullRecommender{}
}
}

type BgwriterFloatParser struct{}

func (v *BgwriterFloatParser) ParseFloat(key string, s string) (float64, error) {
switch key {
case BgwriterDelayKey:
val, units, err := parse.PGFormatToTime(s, parse.Milliseconds, parse.VarTypeInteger)
if err != nil {
return val, err
}
conv, err := parse.TimeConversion(units, parse.Milliseconds)
if err != nil {
return val, err
}
return val * conv, nil
default:
bfp := &numericFloatParser{}
return bfp.ParseFloat(key, s)
}
}
48 changes: 6 additions & 42 deletions pkg/pgtune/background_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package pgtune
import (
"fmt"
"testing"

"github.com/timescale/timescaledb-tune/internal/parse"
)

func TestBgwriterSettingsGroup_GetRecommender(t *testing.T) {
Expand All @@ -31,20 +29,14 @@ func TestBgwriterSettingsGroupRecommend(t *testing.T) {

// the default profile should provide no recommendations
r := sg.GetRecommender(DefaultProfile)
if val := r.Recommend(BgwriterDelayKey); val != NoRecommendation {
t.Errorf("Expected no recommendation for key %s but got %s", BgwriterDelayKey, val)
}
if val := r.Recommend(BgwriterLRUMaxPagesKey); val != NoRecommendation {
t.Errorf("Expected no recommendation for key %s but got %s", BgwriterLRUMaxPagesKey, val)
if val := r.Recommend(BgwriterFlushAfterKey); val != NoRecommendation {
t.Errorf("Expected no recommendation for key %s but got %s", BgwriterFlushAfterKey, val)
}

// the promscale profile should have recommendations
r = sg.GetRecommender(PromscaleProfile)
if val := r.Recommend(BgwriterDelayKey); val != promscaleDefaultBgwriterDelay {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterDelay, BgwriterDelayKey, val)
}
if val := r.Recommend(BgwriterLRUMaxPagesKey); val != promscaleDefaultBgwriterLRUMaxPages {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterLRUMaxPages, BgwriterLRUMaxPagesKey, val)
if val := r.Recommend(BgwriterFlushAfterKey); val != promscaleDefaultBgwriterFlushAfter {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterFlushAfter, BgwriterFlushAfterKey, val)
}
}

Expand All @@ -53,35 +45,7 @@ func TestPromscaleBgwriterRecommender(t *testing.T) {
if !r.IsAvailable() {
t.Error("PromscaleBgwriterRecommender should always be available")
}
if val := r.Recommend(BgwriterDelayKey); val != promscaleDefaultBgwriterDelay {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterDelay, BgwriterDelayKey, val)
}
if val := r.Recommend(BgwriterLRUMaxPagesKey); val != promscaleDefaultBgwriterLRUMaxPages {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterLRUMaxPages, BgwriterLRUMaxPagesKey, val)
}
}

func TestBgwriterFloatParserParseFloat(t *testing.T) {
v := &BgwriterFloatParser{}

s := "100"
want := 100.0
got, err := v.ParseFloat(BgwriterLRUMaxPagesKey, s)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if got != want {
t.Errorf("incorrect result: got %f want %f", got, want)
}

s = "33" + parse.Minutes.String()
conversion, _ := parse.TimeConversion(parse.Minutes, parse.Milliseconds)
want = 33.0 * conversion
got, err = v.ParseFloat(BgwriterDelayKey, s)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if got != want {
t.Errorf("incorrect result: got %f want %f", got, want)
if val := r.Recommend(BgwriterFlushAfterKey); val != promscaleDefaultBgwriterFlushAfter {
t.Errorf("Expected %s for key %s but got %s", promscaleDefaultBgwriterFlushAfter, BgwriterFlushAfterKey, val)
}
}
36 changes: 35 additions & 1 deletion pkg/pgtune/float_parser.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package pgtune

import (
"fmt"
"strconv"
"strings"

"github.com/timescale/timescaledb-tune/internal/parse"
)

const (
errUnrecognizedBoolValue = "unrecognized bool value: %s"
)

type FloatParser interface {
ParseFloat(string, string) (float64, error)
}
Expand All @@ -23,6 +29,34 @@ func (v *numericFloatParser) ParseFloat(key string, s string) (float64, error) {
return strconv.ParseFloat(s, 64)
}

type boolFloatParser struct{}

func (v *boolFloatParser) ParseFloat(key string, s string) (float64, error) {
s = strings.ToLower(s)
s = strings.TrimLeft(s, `"'`)
s = strings.TrimRight(s, `"'`)
switch s {
case "on":
return 1.0, nil
case "off":
return 0.0, nil
case "true":
return 1.0, nil
case "false":
return 0.0, nil
case "yes":
return 1.0, nil
case "no":
return 0.0, nil
case "1":
return 1.0, nil
case "0":
return 0.0, nil
default:
return 0.0, fmt.Errorf(errUnrecognizedBoolValue, s)
}
}

// GetFloatParser returns the correct FloatParser for a given Recommender.
func GetFloatParser(r Recommender) FloatParser {
switch r.(type) {
Expand All @@ -33,7 +67,7 @@ func GetFloatParser(r Recommender) FloatParser {
case *PromscaleWALRecommender:
return &WALFloatParser{}
case *PromscaleBgwriterRecommender:
return &BgwriterFloatParser{}
return &numericFloatParser{}
case *ParallelRecommender:
return &numericFloatParser{}
default:
Expand Down
115 changes: 114 additions & 1 deletion pkg/pgtune/float_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,119 @@ func TestNumericFloatParserParseFloat(t *testing.T) {
}
}

func Test_boolFloatParser_ParseFloat(t *testing.T) {
tests := []struct {
name string
arg string
want float64
wantErr bool
}{
{
name: "on",
arg: "on",
want: 1.0,
wantErr: false,
},
{
name: "oN",
arg: "oN",
want: 1.0,
wantErr: false,
},
{
name: "'ON'",
arg: "'ON'",
want: 1.0,
wantErr: false,
},
{
name: "off",
arg: "off",
want: 0.0,
wantErr: false,
},
{
name: "OfF",
arg: "OfF",
want: 0.0,
wantErr: false,
},
{
name: "'OFF'",
arg: "'OFF'",
want: 0.0,
wantErr: false,
},
{
name: "true",
arg: "true",
want: 1.0,
wantErr: false,
},
{
name: "false",
arg: "false",
want: 0.0,
wantErr: false,
},
{
name: "yes",
arg: "yes",
want: 1.0,
wantErr: false,
},
{
name: "no",
arg: "no",
want: 0.0,
wantErr: false,
},
{
name: "1",
arg: "1",
want: 1.0,
wantErr: false,
},
{
name: "0",
arg: "0",
want: 0.0,
wantErr: false,
},
{
name: "bob",
arg: "bob",
want: 0.0,
wantErr: true,
},
{
name: "99",
arg: "99",
want: 0.0,
wantErr: true,
},
{
name: "0.1",
arg: "0.1",
want: 0.0,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := &boolFloatParser{}
got, err := v.ParseFloat("", tt.arg)
if (err != nil) != tt.wantErr {
t.Errorf("ParseFloat() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ParseFloat() got = %v, want %v", got, tt.want)
}
})
}
}

func TestGetFloatParser(t *testing.T) {
switch x := (GetFloatParser(&MemoryRecommender{})).(type) {
case *bytesFloatParser:
Expand All @@ -58,7 +171,7 @@ func TestGetFloatParser(t *testing.T) {
}

switch x := (GetFloatParser(&PromscaleBgwriterRecommender{})).(type) {
case *BgwriterFloatParser:
case *numericFloatParser:
default:
t.Errorf("wrong validator type for PromscaleBgwriterRecommender: got %T", x)
}
Expand Down
42 changes: 41 additions & 1 deletion pkg/pgtune/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,41 @@ func (r *MemoryRecommender) recommendWindows() string {
return parse.BytesToPGFormat(temp)
}

// PromscaleMemoryRecommender gives recommendations for ParallelKeys based on system resources
type PromscaleMemoryRecommender struct {
*MemoryRecommender
}

// NewPromscaleMemoryRecommender returns a PromscaleMemoryRecommender that recommends based on the given
// number of cpus and system memory
func NewPromscaleMemoryRecommender(totalMemory uint64, cpus int, maxConns uint64) *PromscaleMemoryRecommender {
return &PromscaleMemoryRecommender{
MemoryRecommender: NewMemoryRecommender(totalMemory, cpus, maxConns),
}
}

// IsAvailable returns whether this Recommender is usable given the system resources. Always true.
func (r *PromscaleMemoryRecommender) IsAvailable() bool {
return true
}

// Recommend returns the recommended PostgreSQL formatted value for the conf
// file for a given key.
func (r *PromscaleMemoryRecommender) Recommend(key string) string {
var val string
switch key {
case SharedBuffersKey:
if runtime.GOOS == osWindows {
val = parse.BytesToPGFormat(sharedBuffersWindows)
} else {
val = parse.BytesToPGFormat(r.totalMemory / 2)
}
default:
val = r.MemoryRecommender.Recommend(key)
}
return val
}

// MemorySettingsGroup is the SettingsGroup to represent settings that affect memory usage.
type MemorySettingsGroup struct {
totalMemory uint64
Expand All @@ -126,5 +161,10 @@ func (sg *MemorySettingsGroup) Keys() []string { return MemoryKeys }

// GetRecommender should return a new MemoryRecommender.
func (sg *MemorySettingsGroup) GetRecommender(profile Profile) Recommender {
return NewMemoryRecommender(sg.totalMemory, sg.cpus, sg.maxConns)
switch profile {
case PromscaleProfile:
return NewPromscaleMemoryRecommender(sg.totalMemory, sg.cpus, sg.maxConns)
default:
return NewMemoryRecommender(sg.totalMemory, sg.cpus, sg.maxConns)
}
}
Loading

0 comments on commit 5c8b365

Please sign in to comment.