github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/index_skip_table_reader.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 rowexec 12 13 import ( 14 "context" 15 "sync" 16 17 "github.com/cockroachdb/cockroach/pkg/roachpb" 18 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 19 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 20 "github.com/cockroachdb/cockroach/pkg/sql/row" 21 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 22 "github.com/cockroachdb/errors" 23 ) 24 25 // indexSkipTableReader is a processor that retrieves distinct rows from 26 // a table using the prefix of an index to skip reading some rows in the 27 // table. Specifically, given a prefix of an index to distinct over, 28 // the indexSkipTableReader returns all distinct rows where that prefix 29 // of the index is distinct. It uses the index to seek to distinct values 30 // of the prefix instead of doing a full table scan. 31 type indexSkipTableReader struct { 32 execinfra.ProcessorBase 33 34 spans roachpb.Spans 35 36 // currentSpan maintains which span we are currently scanning. 37 currentSpan int 38 39 // keyPrefixLen holds the length of the prefix of the index 40 // that we are performing a distinct over. 41 keyPrefixLen int 42 // indexLen holds the number of columns in the index that 43 // is being considered. 44 indexLen int 45 46 reverse bool 47 48 ignoreMisplannedRanges bool 49 misplannedRanges []roachpb.RangeInfo 50 51 fetcher row.Fetcher 52 alloc sqlbase.DatumAlloc 53 } 54 55 const indexSkipTableReaderProcName = "index skip table reader" 56 57 var istrPool = sync.Pool{ 58 New: func() interface{} { 59 return &indexSkipTableReader{} 60 }, 61 } 62 63 var _ execinfra.Processor = &indexSkipTableReader{} 64 var _ execinfra.RowSource = &indexSkipTableReader{} 65 var _ execinfrapb.MetadataSource = &indexSkipTableReader{} 66 67 func newIndexSkipTableReader( 68 flowCtx *execinfra.FlowCtx, 69 processorID int32, 70 spec *execinfrapb.IndexSkipTableReaderSpec, 71 post *execinfrapb.PostProcessSpec, 72 output execinfra.RowReceiver, 73 ) (*indexSkipTableReader, error) { 74 // NB: we hit this with a zero NodeID (but !ok) with multi-tenancy. 75 if nodeID, ok := flowCtx.NodeID.OptionalNodeID(); nodeID == 0 && ok { 76 return nil, errors.Errorf("attempting to create a tableReader with uninitialized NodeID") 77 } 78 79 t := istrPool.Get().(*indexSkipTableReader) 80 81 returnMutations := spec.Visibility == execinfra.ScanVisibilityPublicAndNotPublic 82 types := spec.Table.ColumnTypesWithMutations(returnMutations) 83 t.ignoreMisplannedRanges = flowCtx.Local 84 t.reverse = spec.Reverse 85 86 if err := t.Init( 87 t, 88 post, 89 types, 90 flowCtx, 91 processorID, 92 output, 93 nil, /* memMonitor */ 94 execinfra.ProcStateOpts{ 95 InputsToDrain: nil, 96 TrailingMetaCallback: t.generateTrailingMeta, 97 }, 98 ); err != nil { 99 return nil, err 100 } 101 102 neededColumns := t.Out.NeededColumns() 103 t.keyPrefixLen = neededColumns.Len() 104 105 columnIdxMap := spec.Table.ColumnIdxMapWithMutations(returnMutations) 106 107 immutDesc := sqlbase.NewImmutableTableDescriptor(spec.Table) 108 index, isSecondaryIndex, err := immutDesc.FindIndexByIndexIdx(int(spec.IndexIdx)) 109 if err != nil { 110 return nil, err 111 } 112 t.indexLen = len(index.ColumnIDs) 113 114 cols := immutDesc.Columns 115 if returnMutations { 116 cols = immutDesc.ReadableColumns 117 } 118 119 tableArgs := row.FetcherTableArgs{ 120 Desc: immutDesc, 121 Index: index, 122 ColIdxMap: columnIdxMap, 123 IsSecondaryIndex: isSecondaryIndex, 124 Cols: cols, 125 ValNeededForCol: neededColumns, 126 } 127 128 if err := t.fetcher.Init( 129 flowCtx.Codec(), 130 t.reverse, 131 spec.LockingStrength, 132 true, /* returnRangeInfo */ 133 false, /* isCheck */ 134 &t.alloc, 135 tableArgs, 136 ); err != nil { 137 return nil, err 138 } 139 140 // Make a copy of the spans for this reader, as we will modify them. 141 nSpans := len(spec.Spans) 142 if cap(t.spans) >= nSpans { 143 t.spans = t.spans[:nSpans] 144 } else { 145 t.spans = make(roachpb.Spans, nSpans) 146 } 147 148 // If we are scanning in reverse, then copy the spans in backwards. 149 if t.reverse { 150 for i, s := range spec.Spans { 151 t.spans[len(spec.Spans)-i-1] = s.Span 152 } 153 } else { 154 for i, s := range spec.Spans { 155 t.spans[i] = s.Span 156 } 157 } 158 159 return t, nil 160 } 161 162 func (t *indexSkipTableReader) Start(ctx context.Context) context.Context { 163 t.StartInternal(ctx, indexSkipTableReaderProcName) 164 return ctx 165 } 166 167 func (t *indexSkipTableReader) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) { 168 for t.State == execinfra.StateRunning { 169 if t.currentSpan >= len(t.spans) { 170 t.MoveToDraining(nil) 171 return nil, t.DrainHelper() 172 } 173 174 // Start a scan to get the smallest value within this span. 175 err := t.fetcher.StartScan( 176 t.Ctx, t.FlowCtx.Txn, t.spans[t.currentSpan:t.currentSpan+1], 177 true, 1 /* batch size limit */, t.FlowCtx.TraceKV, 178 ) 179 if err != nil { 180 t.MoveToDraining(err) 181 return nil, &execinfrapb.ProducerMetadata{Err: err} 182 } 183 184 // Range info resets once a scan begins, so we need to maintain 185 // the range info we get after each scan. 186 if !t.ignoreMisplannedRanges { 187 nodeID, ok := t.FlowCtx.NodeID.OptionalNodeID() 188 if ok { 189 ranges := execinfra.MisplannedRanges(t.Ctx, t.fetcher.GetRangesInfo(), nodeID) 190 for _, r := range ranges { 191 t.misplannedRanges = roachpb.InsertRangeInfo(t.misplannedRanges, r) 192 } 193 } 194 } 195 196 // This key *must not* be modified, as this will cause the fetcher 197 // to begin acting incorrectly. This is because modifications 198 // will corrupt the row internal to the fetcher. 199 key, err := t.fetcher.PartialKey(t.keyPrefixLen) 200 if err != nil { 201 t.MoveToDraining(err) 202 return nil, &execinfrapb.ProducerMetadata{Err: err} 203 } 204 205 row, _, _, err := t.fetcher.NextRow(t.Ctx) 206 if err != nil { 207 t.MoveToDraining(err) 208 return nil, &execinfrapb.ProducerMetadata{Err: err} 209 } 210 if row == nil { 211 // No more rows in this span, so move to the next one. 212 t.currentSpan++ 213 continue 214 } 215 216 if !t.reverse { 217 // We set the new key to be the largest key with the prefix that we have 218 // so that we skip all values with the same prefix, and "skip" to the 219 // next distinct value. 220 t.spans[t.currentSpan].Key = key.PrefixEnd() 221 } else { 222 // In the case of reverse, this is much easier. The reverse fetcher 223 // returns the key retrieved, in this case the first key smaller 224 // than EndKey in the current span. Since EndKey is exclusive, we 225 // just set the retrieved key as EndKey for the next scan. 226 t.spans[t.currentSpan].EndKey = key 227 } 228 229 // If the changes we made turned our current span invalid, mark that 230 // we should move on to the next span before returning the row. 231 if !t.spans[t.currentSpan].Valid() { 232 t.currentSpan++ 233 } 234 235 if outRow := t.ProcessRowHelper(row); outRow != nil { 236 return outRow, nil 237 } 238 } 239 return nil, t.DrainHelper() 240 } 241 242 func (t *indexSkipTableReader) Release() { 243 t.ProcessorBase.Reset() 244 t.fetcher.Reset() 245 *t = indexSkipTableReader{ 246 ProcessorBase: t.ProcessorBase, 247 fetcher: t.fetcher, 248 spans: t.spans[:0], 249 misplannedRanges: t.misplannedRanges[:0], 250 currentSpan: 0, 251 } 252 istrPool.Put(t) 253 } 254 255 func (t *indexSkipTableReader) ConsumerClosed() { 256 t.InternalClose() 257 } 258 259 func (t *indexSkipTableReader) generateTrailingMeta( 260 ctx context.Context, 261 ) []execinfrapb.ProducerMetadata { 262 trailingMeta := t.generateMeta(ctx) 263 t.InternalClose() 264 return trailingMeta 265 } 266 267 func (t *indexSkipTableReader) generateMeta(ctx context.Context) []execinfrapb.ProducerMetadata { 268 var trailingMeta []execinfrapb.ProducerMetadata 269 if !t.ignoreMisplannedRanges { 270 if len(t.misplannedRanges) != 0 { 271 trailingMeta = append(trailingMeta, execinfrapb.ProducerMetadata{Ranges: t.misplannedRanges}) 272 } 273 } 274 if tfs := execinfra.GetLeafTxnFinalState(ctx, t.FlowCtx.Txn); tfs != nil { 275 trailingMeta = append(trailingMeta, execinfrapb.ProducerMetadata{LeafTxnFinalState: tfs}) 276 } 277 return trailingMeta 278 } 279 280 func (t *indexSkipTableReader) DrainMeta(ctx context.Context) []execinfrapb.ProducerMetadata { 281 return t.generateMeta(ctx) 282 }