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  }