github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/execinfra/metadata_test_receiver.go (about) 1 // Copyright 2018 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 execinfra 12 13 import ( 14 "context" 15 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 18 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 19 "github.com/cockroachdb/cockroach/pkg/util" 20 ) 21 22 // MetadataTestReceiver is a Processors that is complimentary to 23 // MetadataTestSender which checks that all metadata emitted by latter is 24 // received. 25 type MetadataTestReceiver struct { 26 ProcessorBase 27 input RowSource 28 29 // trailingErrMeta stores the error metadata received from the input. We 30 // do not return this metadata immediately because metadata propagation errors 31 // are prioritized over query errors, which ensures that tests which expect a 32 // query error can still fail if they do not properly propagate metadata. 33 trailingErrMeta []execinfrapb.ProducerMetadata 34 35 senders []string 36 rowCounts map[string]rowNumCounter 37 } 38 39 type rowNumCounter struct { 40 expected, actual int32 41 seen util.FastIntSet 42 err error 43 } 44 45 var _ Processor = &MetadataTestReceiver{} 46 var _ RowSource = &MetadataTestReceiver{} 47 48 const metadataTestReceiverProcName = "meta receiver" 49 50 // NewMetadataTestReceiver creates a new MetadataTestReceiver. 51 func NewMetadataTestReceiver( 52 flowCtx *FlowCtx, 53 processorID int32, 54 input RowSource, 55 post *execinfrapb.PostProcessSpec, 56 output RowReceiver, 57 senders []string, 58 ) (*MetadataTestReceiver, error) { 59 mtr := &MetadataTestReceiver{ 60 input: input, 61 senders: senders, 62 rowCounts: make(map[string]rowNumCounter), 63 } 64 if err := mtr.Init( 65 mtr, 66 post, 67 input.OutputTypes(), 68 flowCtx, 69 processorID, 70 output, 71 nil, /* memMonitor */ 72 ProcStateOpts{ 73 InputsToDrain: []RowSource{input}, 74 TrailingMetaCallback: func(context.Context) []execinfrapb.ProducerMetadata { 75 var trailingMeta []execinfrapb.ProducerMetadata 76 if mtr.rowCounts != nil { 77 if meta := mtr.checkRowNumMetadata(); meta != nil { 78 trailingMeta = append(trailingMeta, *meta) 79 } 80 } 81 mtr.InternalClose() 82 return trailingMeta 83 }, 84 }, 85 ); err != nil { 86 return nil, err 87 } 88 return mtr, nil 89 } 90 91 // checkRowNumMetadata examines all of the received RowNum metadata to ensure 92 // that it has received exactly one of each expected RowNum. If the check 93 // detects dropped or repeated metadata, it returns error metadata. Otherwise, 94 // it returns nil. 95 func (mtr *MetadataTestReceiver) checkRowNumMetadata() *execinfrapb.ProducerMetadata { 96 defer func() { mtr.rowCounts = nil }() 97 98 if len(mtr.rowCounts) != len(mtr.senders) { 99 var missingSenders string 100 for _, sender := range mtr.senders { 101 if _, exists := mtr.rowCounts[sender]; !exists { 102 if missingSenders == "" { 103 missingSenders = sender 104 } else { 105 missingSenders += fmt.Sprintf(", %s", sender) 106 } 107 } 108 } 109 return &execinfrapb.ProducerMetadata{ 110 Err: fmt.Errorf( 111 "expected %d metadata senders but found %d; missing %s", 112 len(mtr.senders), len(mtr.rowCounts), missingSenders, 113 ), 114 } 115 } 116 for id, cnt := range mtr.rowCounts { 117 if cnt.err != nil { 118 return &execinfrapb.ProducerMetadata{Err: cnt.err} 119 } 120 if cnt.expected != cnt.actual { 121 return &execinfrapb.ProducerMetadata{ 122 Err: fmt.Errorf( 123 "dropped metadata from sender %s: expected %d RowNum messages but got %d", 124 id, cnt.expected, cnt.actual), 125 } 126 } 127 for i := 0; i < int(cnt.expected); i++ { 128 if !cnt.seen.Contains(i) { 129 return &execinfrapb.ProducerMetadata{ 130 Err: fmt.Errorf( 131 "dropped and repeated metadata from sender %s: have %d messages but missing RowNum #%d", 132 id, cnt.expected, i+1), 133 } 134 } 135 } 136 } 137 138 return nil 139 } 140 141 // Start is part of the RowSource interface. 142 func (mtr *MetadataTestReceiver) Start(ctx context.Context) context.Context { 143 mtr.input.Start(ctx) 144 return mtr.StartInternal(ctx, metadataTestReceiverProcName) 145 } 146 147 // Next is part of the RowSource interface. 148 // 149 // This implementation doesn't follow the usual patterns of other processors; it 150 // makes more limited use of the ProcessorBase's facilities because it needs to 151 // inspect metadata while draining. 152 func (mtr *MetadataTestReceiver) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) { 153 for { 154 if mtr.State == StateTrailingMeta { 155 if meta := mtr.popTrailingMeta(); meta != nil { 156 return nil, meta 157 } 158 // If there's no more trailingMeta, we've moved to stateExhausted, and we 159 // might return some trailingErrMeta below. 160 } 161 if mtr.State == StateExhausted { 162 if len(mtr.trailingErrMeta) > 0 { 163 meta := mtr.trailingErrMeta[0] 164 mtr.trailingErrMeta = mtr.trailingErrMeta[1:] 165 return nil, &meta 166 } 167 return nil, nil 168 } 169 170 row, meta := mtr.input.Next() 171 172 if meta != nil { 173 if meta.RowNum != nil { 174 rowNum := meta.RowNum 175 rcnt, exists := mtr.rowCounts[rowNum.SenderID] 176 if !exists { 177 rcnt.expected = -1 178 } 179 if rcnt.err != nil { 180 return nil, meta 181 } 182 if rowNum.LastMsg { 183 if rcnt.expected != -1 { 184 rcnt.err = fmt.Errorf( 185 "repeated metadata from reader %s: received more than one RowNum with LastMsg set", 186 rowNum.SenderID) 187 mtr.rowCounts[rowNum.SenderID] = rcnt 188 return nil, meta 189 } 190 rcnt.expected = rowNum.RowNum 191 } else { 192 rcnt.actual++ 193 rcnt.seen.Add(int(rowNum.RowNum - 1)) 194 } 195 mtr.rowCounts[rowNum.SenderID] = rcnt 196 } 197 if meta.Err != nil { 198 // Keep track of the err in trailingErrMeta, which will be returned 199 // after everything else (including ProcessorBase.trailingMeta). 200 mtr.trailingErrMeta = append(mtr.trailingErrMeta, *meta) 201 continue 202 } 203 204 return nil, meta 205 } 206 207 if row == nil { 208 mtr.moveToTrailingMeta() 209 continue 210 } 211 212 // We don't use ProcessorBase.ProcessRowHelper() here because we need 213 // special handling for errors: this proc never starts draining in order for 214 // it to be as unintrusive as possible. 215 outRow, ok, err := mtr.Out.ProcessRow(mtr.Ctx, row) 216 if err != nil { 217 mtr.trailingMeta = append(mtr.trailingMeta, execinfrapb.ProducerMetadata{Err: err}) 218 continue 219 } 220 if outRow == nil { 221 if !ok { 222 mtr.MoveToDraining(nil /* err */) 223 } 224 continue 225 } 226 227 // Swallow rows if we're draining. 228 if mtr.State == StateDraining { 229 continue 230 } 231 232 if !ok { 233 mtr.MoveToDraining(nil /* err */) 234 } 235 236 return outRow, nil 237 } 238 } 239 240 // ConsumerDone is part of the RowSource interface. 241 func (mtr *MetadataTestReceiver) ConsumerDone() { 242 mtr.input.ConsumerDone() 243 } 244 245 // ConsumerClosed is part of the RowSource interface. 246 func (mtr *MetadataTestReceiver) ConsumerClosed() { 247 // The consumer is done, Next() will not be called again. 248 mtr.InternalClose() 249 }