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 }