github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/apply/cmd.go (about)

     1  // Copyright 2019 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 apply
    12  
    13  import "context"
    14  
    15  // Command is a command that has been successfully replicated through raft
    16  // by being durably committed to the raft log of a quorum of peers in a raft
    17  // group.
    18  type Command interface {
    19  	// Index is the log index of the corresponding raft entry.
    20  	Index() uint64
    21  	// IsTrivial returns whether the command can apply in a batch.
    22  	IsTrivial() bool
    23  	// IsLocal returns whether the command was locally proposed. Command
    24  	// that were locally proposed typically have a client waiting on a
    25  	// response, so there is additional urgency to apply them quickly.
    26  	IsLocal() bool
    27  }
    28  
    29  // CheckedCommand is a command that has been checked to see whether it can
    30  // apply successfully or not. Committing an entry in a raft log and having
    31  // the command in that entry succeed are similar but not equivalent concepts.
    32  // A successfully committed entry may contain a command that the replicated
    33  // state machine decides to reject (deterministically).
    34  type CheckedCommand interface {
    35  	Command
    36  	// Rejected returns whether the command was rejected.
    37  	Rejected() bool
    38  	// CanAckBeforeApplication returns whether the success of the command
    39  	// can be acknowledged before the command has been applied to the state
    40  	// machine.
    41  	CanAckBeforeApplication() bool
    42  	// AckSuccess acknowledges the success of the command to its client.
    43  	// Must only be called if !Rejected.
    44  	AckSuccess() error
    45  }
    46  
    47  // AppliedCommand is a command that has been applied to the replicated state
    48  // machine. A command is considered "applied" if it has been staged in a
    49  // Batch which has been committed and had its side-effects run on the state
    50  // machine. If the command was rejected (see CheckedCommand), applying the
    51  // command will likely be a no-op, but that is up to the implementation of
    52  // the state machine.
    53  type AppliedCommand interface {
    54  	CheckedCommand
    55  	// FinishAndAckOutcome signals that the application of the command has
    56  	// completed. It also acknowledges the outcome of the command to its
    57  	// client if it was proposed locally. An error will immediately stall
    58  	// entry application, so one must only be returned if the state machine
    59  	// is no longer able to make progress. The method will be called exactly
    60  	// once per Command.
    61  	FinishAndAckOutcome(context.Context) error
    62  }
    63  
    64  // CommandIteratorBase is a common interface extended by all iterator and
    65  // list variants. It is exported so its methods are displayed in godoc when
    66  // it is embedded in other interfaces.
    67  type CommandIteratorBase interface {
    68  	// Valid returns whether the iterator is pointing at a valid element.
    69  	Valid() bool
    70  	// Next advances the iterator. Must not be called if valid is false.
    71  	Next()
    72  	// Close closes the iterator. Once closed, it must not be used.
    73  	Close()
    74  }
    75  
    76  // CommandIterator is an iterator over replicated commands.
    77  type CommandIterator interface {
    78  	CommandIteratorBase
    79  	// Cur returns the command that the iterator is currently pointing at.
    80  	// Must not be called if valid is false.
    81  	Cur() Command
    82  	// NewList returns a new empty command list. Usages of the list will
    83  	// always advance the iterator before pushing in to the list, so
    84  	// implementors are free to share backing memory between the two.
    85  	NewList() CommandList
    86  	// NewCheckedList returns a new empty checked command list. Usages
    87  	// of the list will always advance the iterator before pushing into
    88  	// to the list, so implementors are free to share backing memory
    89  	// between the two.
    90  	NewCheckedList() CheckedCommandList
    91  }
    92  
    93  // CommandList is a list of replicated commands.
    94  type CommandList interface {
    95  	CommandIterator
    96  	// Append adds the command to the end of the list.
    97  	Append(Command)
    98  }
    99  
   100  // CheckedCommandIterator is an iterator over checked replicated
   101  // commands.
   102  type CheckedCommandIterator interface {
   103  	CommandIteratorBase
   104  	// CurChecked returns the checked command that the iterator is
   105  	// currently pointing at. Must not be called if valid is false.
   106  	CurChecked() CheckedCommand
   107  	// NewAppliedList returns a new empty applied command list. Usages
   108  	// of the list will always advance the iterator before pushing into
   109  	// to the list, so implementors are free to share backing memory
   110  	// between the two.
   111  	NewAppliedList() AppliedCommandList
   112  }
   113  
   114  // CheckedCommandList is a list of checked replicated commands.
   115  type CheckedCommandList interface {
   116  	CheckedCommandIterator
   117  	// AppendChecked adds the checked command to the end of the list.
   118  	AppendChecked(CheckedCommand)
   119  }
   120  
   121  // AppliedCommandIterator is an iterator over applied replicated commands.
   122  type AppliedCommandIterator interface {
   123  	CommandIteratorBase
   124  	// CurApplied returns the applied command that the iterator is
   125  	// currently pointing at. Must not be called if valid is false.
   126  	CurApplied() AppliedCommand
   127  }
   128  
   129  // AppliedCommandList is a list of applied replicated commands.
   130  type AppliedCommandList interface {
   131  	AppliedCommandIterator
   132  	// AppendApplied adds the applied command to the end of the list.
   133  	AppendApplied(AppliedCommand)
   134  }
   135  
   136  // takeWhileCmdIter returns an iterator that yields commands based on a
   137  // predicate. It will call the predicate on each command in the provided
   138  // iterator and yield elements while it returns true. The function does
   139  // NOT close the provided iterator, but does drain it of any commands
   140  // that are moved to the returned iterator.
   141  func takeWhileCmdIter(iter CommandIterator, pred func(Command) bool) CommandIterator {
   142  	ret := iter.NewList()
   143  	for iter.Valid() {
   144  		cmd := iter.Cur()
   145  		if !pred(cmd) {
   146  			break
   147  		}
   148  		iter.Next()
   149  		ret.Append(cmd)
   150  	}
   151  	return ret
   152  }
   153  
   154  // mapCmdIter returns an iterator that contains the result of each command
   155  // from the provided iterator transformed by a closure. The closure is
   156  // responsible for converting Commands into CheckedCommand. The function
   157  // closes the provided iterator.
   158  func mapCmdIter(
   159  	iter CommandIterator, fn func(Command) (CheckedCommand, error),
   160  ) (CheckedCommandIterator, error) {
   161  	defer iter.Close()
   162  	ret := iter.NewCheckedList()
   163  	for iter.Valid() {
   164  		checked, err := fn(iter.Cur())
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  		iter.Next()
   169  		ret.AppendChecked(checked)
   170  	}
   171  	return ret, nil
   172  }
   173  
   174  // mapCheckedCmdIter returns an iterator that contains the result of each
   175  // command from the provided iterator transformed by a closure. The closure
   176  // is responsible for converting CheckedCommand into AppliedCommand. The
   177  // function closes the provided iterator.
   178  func mapCheckedCmdIter(
   179  	iter CheckedCommandIterator, fn func(CheckedCommand) (AppliedCommand, error),
   180  ) (AppliedCommandIterator, error) {
   181  	defer iter.Close()
   182  	ret := iter.NewAppliedList()
   183  	for iter.Valid() {
   184  		applied, err := fn(iter.CurChecked())
   185  		if err != nil {
   186  			return nil, err
   187  		}
   188  		iter.Next()
   189  		ret.AppendApplied(applied)
   190  	}
   191  	return ret, nil
   192  }
   193  
   194  // forEachCheckedCmdIter calls a closure on each command in the provided
   195  // iterator. The function closes the provided iterator.
   196  func forEachCheckedCmdIter(iter CheckedCommandIterator, fn func(CheckedCommand) error) error {
   197  	defer iter.Close()
   198  	for iter.Valid() {
   199  		if err := fn(iter.CurChecked()); err != nil {
   200  			return err
   201  		}
   202  		iter.Next()
   203  	}
   204  	return nil
   205  }
   206  
   207  // forEachAppliedCmdIter calls a closure on each command in the provided
   208  // iterator. The function closes the provided iterator.
   209  func forEachAppliedCmdIter(
   210  	ctx context.Context,
   211  	iter AppliedCommandIterator,
   212  	// fn is weirdly written with ctx as a 2nd param because the caller wants to
   213  	// bind it to a method that has the AppliedCommand on the receiver, thus
   214  	// forcing that to be the first param. The caller didn't want to introduce a
   215  	// callback instead to make it clear that nothing escapes to the heap.
   216  	fn func(AppliedCommand, context.Context) error,
   217  ) error {
   218  	defer iter.Close()
   219  	for iter.Valid() {
   220  		if err := fn(iter.CurApplied(), ctx); err != nil {
   221  			return err
   222  		}
   223  		iter.Next()
   224  	}
   225  	return nil
   226  }