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  }