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 }