github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/server/settingsworker.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 server
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/keys"
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/cockroach/pkg/settings"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/row"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    24  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    25  	"github.com/cockroachdb/cockroach/pkg/util/log"
    26  	"github.com/cockroachdb/errors"
    27  )
    28  
    29  // RefreshSettings starts a settings-changes listener.
    30  func (s *Server) refreshSettings() {
    31  	tbl := &sqlbase.SettingsTable
    32  
    33  	a := &sqlbase.DatumAlloc{}
    34  	codec := keys.TODOSQLCodec
    35  	settingsTablePrefix := codec.TablePrefix(uint32(tbl.ID))
    36  	colIdxMap := row.ColIDtoRowIndexFromCols(tbl.Columns)
    37  
    38  	processKV := func(ctx context.Context, kv roachpb.KeyValue, u settings.Updater) error {
    39  		if !bytes.HasPrefix(kv.Key, settingsTablePrefix) {
    40  			return nil
    41  		}
    42  
    43  		var k, v, t string
    44  		// First we need to decode the setting name field from the index key.
    45  		{
    46  			types := []*types.T{tbl.Columns[0].Type}
    47  			nameRow := make([]sqlbase.EncDatum, 1)
    48  			_, matches, _, err := sqlbase.DecodeIndexKey(codec, tbl, &tbl.PrimaryIndex, types, nameRow, nil, kv.Key)
    49  			if err != nil {
    50  				return errors.Wrap(err, "failed to decode key")
    51  			}
    52  			if !matches {
    53  				return errors.Errorf("unexpected non-settings KV with settings prefix: %v", kv.Key)
    54  			}
    55  			if err := nameRow[0].EnsureDecoded(types[0], a); err != nil {
    56  				return err
    57  			}
    58  			k = string(tree.MustBeDString(nameRow[0].Datum))
    59  		}
    60  
    61  		// The rest of the columns are stored as a family, packed with diff-encoded
    62  		// column IDs followed by their values.
    63  		{
    64  			// column valueType can be null (missing) so we default it to "s".
    65  			t = "s"
    66  			bytes, err := kv.Value.GetTuple()
    67  			if err != nil {
    68  				return err
    69  			}
    70  			var colIDDiff uint32
    71  			var lastColID sqlbase.ColumnID
    72  			var res tree.Datum
    73  			for len(bytes) > 0 {
    74  				_, _, colIDDiff, _, err = encoding.DecodeValueTag(bytes)
    75  				if err != nil {
    76  					return err
    77  				}
    78  				colID := lastColID + sqlbase.ColumnID(colIDDiff)
    79  				lastColID = colID
    80  				if idx, ok := colIdxMap[colID]; ok {
    81  					res, bytes, err = sqlbase.DecodeTableValue(a, tbl.Columns[idx].Type, bytes)
    82  					if err != nil {
    83  						return err
    84  					}
    85  					switch colID {
    86  					case tbl.Columns[1].ID: // value
    87  						v = string(tree.MustBeDString(res))
    88  					case tbl.Columns[3].ID: // valueType
    89  						t = string(tree.MustBeDString(res))
    90  					case tbl.Columns[2].ID: // lastUpdated
    91  						// TODO(dt): we could decode just the len and then seek `bytes` past
    92  						// it, without allocating/decoding the unused timestamp.
    93  					default:
    94  						return errors.Errorf("unknown column: %v", colID)
    95  					}
    96  				}
    97  			}
    98  		}
    99  
   100  		if err := u.Set(k, v, t); err != nil {
   101  			log.Warningf(ctx, "setting %q to %q failed: %+v", k, v, err)
   102  		}
   103  		return nil
   104  	}
   105  
   106  	ctx := s.AnnotateCtx(context.Background())
   107  	s.stopper.RunWorker(ctx, func(ctx context.Context) {
   108  		gossipUpdateC := s.gossip.RegisterSystemConfigChannel()
   109  		// No new settings can be defined beyond this point.
   110  		for {
   111  			select {
   112  			case <-gossipUpdateC:
   113  				cfg := s.gossip.GetSystemConfig()
   114  				u := s.st.MakeUpdater()
   115  				ok := true
   116  				for _, kv := range cfg.Values {
   117  					if err := processKV(ctx, kv, u); err != nil {
   118  						log.Warningf(ctx, `error decoding settings data: %+v
   119  								this likely indicates the settings table structure or encoding has been altered;
   120  								skipping settings updates`, err)
   121  						ok = false
   122  						break
   123  					}
   124  				}
   125  				if ok {
   126  					u.ResetRemaining()
   127  				}
   128  			case <-s.stopper.ShouldStop():
   129  				return
   130  			}
   131  		}
   132  	})
   133  }