github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/log.go (about) 1 // Copyright 2015 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 kvserver 12 13 import ( 14 "context" 15 "encoding/json" 16 "time" 17 18 "github.com/cockroachdb/cockroach/pkg/kv" 19 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/security" 22 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 23 "github.com/cockroachdb/cockroach/pkg/util/hlc" 24 "github.com/cockroachdb/cockroach/pkg/util/log" 25 "github.com/cockroachdb/errors" 26 ) 27 28 func (s *Store) insertRangeLogEvent( 29 ctx context.Context, txn *kv.Txn, event kvserverpb.RangeLogEvent, 30 ) error { 31 // Record range log event to console log. 32 var info string 33 if event.Info != nil { 34 info = event.Info.String() 35 } 36 if log.V(1) { 37 log.Infof(ctx, "Range Event: %q, range: %d, info: %s", 38 event.EventType, event.RangeID, info) 39 } 40 41 const insertEventTableStmt = ` 42 INSERT INTO system.rangelog ( 43 timestamp, "rangeID", "storeID", "eventType", "otherRangeID", info 44 ) 45 VALUES( 46 $1, $2, $3, $4, $5, $6 47 ) 48 ` 49 args := []interface{}{ 50 event.Timestamp, 51 event.RangeID, 52 event.StoreID, 53 event.EventType.String(), 54 nil, // otherRangeID 55 nil, // info 56 } 57 if event.OtherRangeID != 0 { 58 args[4] = event.OtherRangeID 59 } 60 if event.Info != nil { 61 infoBytes, err := json.Marshal(*event.Info) 62 if err != nil { 63 return err 64 } 65 args[5] = string(infoBytes) 66 } 67 68 // Update range event metrics. We do this close to the insertion of the 69 // corresponding range log entry to reduce potential skew between metrics and 70 // range log. 71 switch event.EventType { 72 case kvserverpb.RangeLogEventType_split: 73 s.metrics.RangeSplits.Inc(1) 74 case kvserverpb.RangeLogEventType_merge: 75 s.metrics.RangeMerges.Inc(1) 76 case kvserverpb.RangeLogEventType_add: 77 s.metrics.RangeAdds.Inc(1) 78 case kvserverpb.RangeLogEventType_remove: 79 s.metrics.RangeRemoves.Inc(1) 80 } 81 82 rows, err := s.cfg.SQLExecutor.ExecEx(ctx, "log-range-event", txn, 83 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 84 insertEventTableStmt, args...) 85 if err != nil { 86 return err 87 } 88 if rows != 1 { 89 return errors.Errorf("%d rows affected by log insertion; expected exactly one row affected.", rows) 90 } 91 return nil 92 } 93 94 // logSplit logs a range split event into the event table. The affected range is 95 // the range which previously existed and is being split in half; the "other" 96 // range is the new range which is being created. 97 // 98 // TODO(mrtracy): There are several different reasons that a range split 99 // could occur, and that information should be logged. 100 func (s *Store) logSplit( 101 ctx context.Context, txn *kv.Txn, updatedDesc, newDesc roachpb.RangeDescriptor, 102 ) error { 103 if !s.cfg.LogRangeEvents { 104 return nil 105 } 106 return s.insertRangeLogEvent(ctx, txn, kvserverpb.RangeLogEvent{ 107 Timestamp: selectEventTimestamp(s, txn.ReadTimestamp()), 108 RangeID: updatedDesc.RangeID, 109 EventType: kvserverpb.RangeLogEventType_split, 110 StoreID: s.StoreID(), 111 OtherRangeID: newDesc.RangeID, 112 Info: &kvserverpb.RangeLogEvent_Info{ 113 UpdatedDesc: &updatedDesc, 114 NewDesc: &newDesc, 115 }, 116 }) 117 } 118 119 // logMerge logs a range split event into the event table. The affected range is 120 // the subsuming range; the "other" range is the subsumed range. 121 // 122 // TODO(benesch): There are several different reasons that a range merge 123 // could occur, and that information should be logged. 124 func (s *Store) logMerge( 125 ctx context.Context, txn *kv.Txn, updatedLHSDesc, rhsDesc roachpb.RangeDescriptor, 126 ) error { 127 if !s.cfg.LogRangeEvents { 128 return nil 129 } 130 return s.insertRangeLogEvent(ctx, txn, kvserverpb.RangeLogEvent{ 131 Timestamp: selectEventTimestamp(s, txn.ReadTimestamp()), 132 RangeID: updatedLHSDesc.RangeID, 133 EventType: kvserverpb.RangeLogEventType_merge, 134 StoreID: s.StoreID(), 135 OtherRangeID: rhsDesc.RangeID, 136 Info: &kvserverpb.RangeLogEvent_Info{ 137 UpdatedDesc: &updatedLHSDesc, 138 RemovedDesc: &rhsDesc, 139 }, 140 }) 141 } 142 143 // logChange logs a replica change event, which represents a replica being added 144 // to or removed from a range. 145 // TODO(mrtracy): There are several different reasons that a replica change 146 // could occur, and that information should be logged. 147 func (s *Store) logChange( 148 ctx context.Context, 149 txn *kv.Txn, 150 changeType roachpb.ReplicaChangeType, 151 replica roachpb.ReplicaDescriptor, 152 desc roachpb.RangeDescriptor, 153 reason kvserverpb.RangeLogEventReason, 154 details string, 155 ) error { 156 if !s.cfg.LogRangeEvents { 157 return nil 158 } 159 160 var logType kvserverpb.RangeLogEventType 161 var info kvserverpb.RangeLogEvent_Info 162 switch changeType { 163 case roachpb.ADD_REPLICA: 164 logType = kvserverpb.RangeLogEventType_add 165 info = kvserverpb.RangeLogEvent_Info{ 166 AddedReplica: &replica, 167 UpdatedDesc: &desc, 168 Reason: reason, 169 Details: details, 170 } 171 case roachpb.REMOVE_REPLICA: 172 logType = kvserverpb.RangeLogEventType_remove 173 info = kvserverpb.RangeLogEvent_Info{ 174 RemovedReplica: &replica, 175 UpdatedDesc: &desc, 176 Reason: reason, 177 Details: details, 178 } 179 default: 180 return errors.Errorf("unknown replica change type %s", changeType) 181 } 182 183 return s.insertRangeLogEvent(ctx, txn, kvserverpb.RangeLogEvent{ 184 Timestamp: selectEventTimestamp(s, txn.ReadTimestamp()), 185 RangeID: desc.RangeID, 186 EventType: logType, 187 StoreID: s.StoreID(), 188 Info: &info, 189 }) 190 } 191 192 // selectEventTimestamp selects a timestamp for this log message. If the 193 // transaction this event is being written in has a non-zero timestamp, then that 194 // timestamp should be used; otherwise, the store's physical clock is used. 195 // This helps with testing; in normal usage, the logging of an event will never 196 // be the first action in the transaction, and thus the transaction will have an 197 // assigned database timestamp. However, in the case of our tests log events 198 // *are* the first action in a transaction, and we must elect to use the store's 199 // physical time instead. 200 func selectEventTimestamp(s *Store, input hlc.Timestamp) time.Time { 201 if input == (hlc.Timestamp{}) { 202 return s.Clock().PhysicalTime() 203 } 204 return input.GoTime() 205 }