github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/show_cluster_setting.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "bytes" 15 "context" 16 "fmt" 17 "math" 18 "strings" 19 "time" 20 21 "github.com/cockroachdb/cockroach/pkg/kv" 22 "github.com/cockroachdb/cockroach/pkg/security" 23 "github.com/cockroachdb/cockroach/pkg/settings" 24 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 25 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/sql/types" 28 "github.com/cockroachdb/cockroach/pkg/util/contextutil" 29 "github.com/cockroachdb/cockroach/pkg/util/duration" 30 "github.com/cockroachdb/cockroach/pkg/util/retry" 31 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 32 "github.com/cockroachdb/errors" 33 ) 34 35 func (p *planner) showStateMachineSetting( 36 ctx context.Context, st *cluster.Settings, s *settings.StateMachineSetting, name string, 37 ) (string, error) { 38 var res string 39 // For statemachine settings (at the time of writing, this is only the cluster version setting) 40 // we show the value from the KV store and additionally wait for the local Gossip instance to 41 // have observed the value as well. This makes sure that cluster version bumps become visible 42 // immediately while at the same time guaranteeing that a node reporting a certain version has 43 // also processed the corresponding Gossip update (which is important as only then does the node 44 // update its persisted state; see #22796). 45 if err := contextutil.RunWithTimeout(ctx, fmt.Sprintf("show cluster setting %s", name), 2*time.Minute, 46 func(ctx context.Context) error { 47 tBegin := timeutil.Now() 48 49 // The (slight ab)use of WithMaxAttempts achieves convenient context cancellation. 50 return retry.WithMaxAttempts(ctx, retry.Options{}, math.MaxInt32, func() error { 51 return p.execCfg.DB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 52 datums, err := p.ExtendedEvalContext().ExecCfg.InternalExecutor.QueryRowEx( 53 ctx, "read-setting", 54 txn, 55 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 56 "SELECT value FROM system.settings WHERE name = $1", name, 57 ) 58 if err != nil { 59 return err 60 } 61 var kvRawVal []byte 62 if len(datums) != 0 { 63 dStr, ok := datums[0].(*tree.DString) 64 if !ok { 65 return errors.New("the existing value is not a string") 66 } 67 kvRawVal = []byte(string(*dStr)) 68 } else { 69 // There should always be a version saved; there's a migration 70 // populating it. 71 return errors.AssertionFailedf("no value found for version setting") 72 } 73 74 gossipRawVal := []byte(s.Get(&st.SV)) 75 if !bytes.Equal(gossipRawVal, kvRawVal) { 76 return errors.Errorf( 77 "value differs between gossip (%v) and KV (%v); try again later (%v after %s)", 78 gossipRawVal, kvRawVal, ctx.Err(), timeutil.Since(tBegin)) 79 } 80 81 val, err := s.Decode(kvRawVal) 82 if err != nil { 83 return err 84 } 85 res = val.(fmt.Stringer).String() 86 87 return nil 88 }) 89 }) 90 }); err != nil { 91 return "", err 92 } 93 94 return res, nil 95 } 96 97 func (p *planner) ShowClusterSetting( 98 ctx context.Context, n *tree.ShowClusterSetting, 99 ) (planNode, error) { 100 101 if err := p.RequireAdminRole(ctx, "SHOW CLUSTER SETTING"); err != nil { 102 return nil, err 103 } 104 105 name := strings.ToLower(n.Name) 106 st := p.ExecCfg().Settings 107 val, ok := settings.Lookup(name, settings.LookupForLocalAccess) 108 if !ok { 109 return nil, errors.Errorf("unknown setting: %q", name) 110 } 111 112 var dType *types.T 113 switch val.(type) { 114 case *settings.IntSetting: 115 dType = types.Int 116 case *settings.StringSetting, *settings.ByteSizeSetting, *settings.StateMachineSetting, *settings.EnumSetting: 117 dType = types.String 118 case *settings.BoolSetting: 119 dType = types.Bool 120 case *settings.FloatSetting: 121 dType = types.Float 122 case *settings.DurationSetting: 123 dType = types.Interval 124 default: 125 return nil, errors.Errorf("unknown setting type for %s: %s", name, val.Typ()) 126 } 127 128 columns := sqlbase.ResultColumns{{Name: name, Typ: dType}} 129 return &delayedNode{ 130 name: "SHOW CLUSTER SETTING " + name, 131 columns: columns, 132 constructor: func(ctx context.Context, p *planner) (planNode, error) { 133 var d tree.Datum 134 switch s := val.(type) { 135 case *settings.IntSetting: 136 d = tree.NewDInt(tree.DInt(s.Get(&st.SV))) 137 case *settings.StringSetting: 138 d = tree.NewDString(s.String(&st.SV)) 139 case *settings.StateMachineSetting: 140 var err error 141 valStr, err := p.showStateMachineSetting(ctx, st, s, name) 142 if err != nil { 143 return nil, err 144 } 145 d = tree.NewDString(valStr) 146 case *settings.BoolSetting: 147 d = tree.MakeDBool(tree.DBool(s.Get(&st.SV))) 148 case *settings.FloatSetting: 149 d = tree.NewDFloat(tree.DFloat(s.Get(&st.SV))) 150 case *settings.DurationSetting: 151 d = &tree.DInterval{Duration: duration.MakeDuration(s.Get(&st.SV).Nanoseconds(), 0, 0)} 152 case *settings.EnumSetting: 153 d = tree.NewDString(s.String(&st.SV)) 154 case *settings.ByteSizeSetting: 155 d = tree.NewDString(s.String(&st.SV)) 156 default: 157 return nil, errors.Errorf("unknown setting type for %s: %s", name, val.Typ()) 158 } 159 160 v := p.newContainerValuesNode(columns, 0) 161 if _, err := v.rows.AddRow(ctx, tree.Datums{d}); err != nil { 162 v.rows.Close(ctx) 163 return nil, err 164 } 165 return v, nil 166 }, 167 }, nil 168 }