github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/query/microindexcheck.go (about)

     1  /*
     2  Copyright 2023.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package query
    18  
    19  import (
    20  	"sync"
    21  	"sync/atomic"
    22  
    23  	dtu "github.com/siglens/siglens/pkg/common/dtypeutils"
    24  	"github.com/siglens/siglens/pkg/config"
    25  	"github.com/siglens/siglens/pkg/segment/query/metadata"
    26  	"github.com/siglens/siglens/pkg/segment/query/summary"
    27  	"github.com/siglens/siglens/pkg/segment/structs"
    28  	. "github.com/siglens/siglens/pkg/segment/structs"
    29  	"github.com/siglens/siglens/pkg/segment/utils"
    30  	. "github.com/siglens/siglens/pkg/segment/utils"
    31  	log "github.com/sirupsen/logrus"
    32  )
    33  
    34  type ResultSegmentSearchRequestMap struct {
    35  	Result map[string]*SegmentSearchRequest
    36  	Err    error
    37  }
    38  
    39  /*
    40  Top level micro index checking function. For a filter, input segkeys, timeRange, indexNames will do the following:
    41  1. blockbloom/ blockrange filtering
    42  2. search request generation
    43  
    44  Assumes that filesToSearch has been time filtered
    45  Returns a map[string]*SegmentSearchRequest mapping a segment key to the corresponding search request and any errors
    46  */
    47  func MicroIndexCheck(currQuery *SearchQuery, filesToSearch map[string]map[string]*BlockTracker, timeRange *dtu.TimeRange,
    48  	indexNames []string, querySummary *summary.QuerySummary, qid uint64, isQueryPersistent bool, pqid string) (map[string]*SegmentSearchRequest, error) {
    49  
    50  	rangeFilter, rangeOp, isRange := currQuery.ExtractRangeFilterFromQuery(qid)
    51  	bloomWords, wildcardBloom, bloomOp := currQuery.GetAllBlockBloomKeysToSearch()
    52  
    53  	finalFilteredRequest, blocksChecked, blockCount := filterViaMicroIndices(currQuery, indexNames, timeRange,
    54  		filesToSearch, bloomWords, bloomOp, rangeFilter, rangeOp, wildcardBloom, isRange, qid, isQueryPersistent, pqid)
    55  	querySummary.UpdateCMIResults(blocksChecked, blockCount)
    56  	return finalFilteredRequest, nil
    57  }
    58  
    59  // returns final SSRs, count of total blocks checked, count of blocks that passed
    60  func filterViaMicroIndices(currQuery *structs.SearchQuery, indexNames []string, timeRange *dtu.TimeRange,
    61  	filesToSearch map[string]map[string]*BlockTracker, bloomWords map[string]bool, bloomOp LogicalOperator,
    62  	rangeFilter map[string]string, rangeOp utils.FilterOperator, wildCardValue bool,
    63  	isRange bool, qid uint64, isQueryPersistent bool, pqid string) (map[string]*SegmentSearchRequest, uint64, uint64) {
    64  
    65  	finalResults := make(map[string]*SegmentSearchRequest)
    66  
    67  	serResults, totalBlocks, finalBlockCount, errors := getAllSearchRequestsFromCmi(currQuery, timeRange,
    68  		filesToSearch, bloomWords, bloomOp, rangeFilter, rangeOp, isRange, wildCardValue, qid, isQueryPersistent, pqid)
    69  
    70  	if len(errors) > 0 {
    71  		for _, err := range errors {
    72  			log.Errorf("qid=%d filterViaMicroIndices: Failed to get search request from microindices: %+v", qid, err)
    73  		}
    74  	}
    75  
    76  	for _, sReq := range serResults {
    77  		finalResults[sReq.SegmentKey] = sReq
    78  	}
    79  	return finalResults, totalBlocks, finalBlockCount
    80  }
    81  
    82  // returns a list of search request, max possible number of blocks, num blocks to be searched, error
    83  func getAllSearchRequestsFromCmi(currQuery *structs.SearchQuery, timeRange *dtu.TimeRange,
    84  	segkeysToCheck map[string]map[string]*BlockTracker, bloomKeys map[string]bool, bloomOp utils.LogicalOperator,
    85  	rangeFilter map[string]string, rangeOp utils.FilterOperator, isRange bool, wildCardValue bool,
    86  	qid uint64, isQueryPersistent bool, pqid string) ([]*structs.SegmentSearchRequest, uint64, uint64, []error) {
    87  
    88  	sizeChannel := 0
    89  	for _, segKeys := range segkeysToCheck {
    90  		sizeChannel += len(segKeys)
    91  	}
    92  	finalTotalBlockCount := uint64(0)
    93  	finalFilteredBlockCount := uint64(0)
    94  	finalSearchRequests := make([]*structs.SegmentSearchRequest, 0)
    95  	finalSearchRequestErrors := make([]error, 0)
    96  	searchRequestResults := make(chan *structs.SegmentSearchRequest, sizeChannel)
    97  	searchRequestErrors := make(chan error, sizeChannel)
    98  
    99  	colsToCheck, wildcardColQuery := currQuery.GetAllColumnsInQuery()
   100  	delete(colsToCheck, config.GetTimeStampKey()) // timestamp should not be checked in cmi
   101  	var blockWG sync.WaitGroup
   102  	for indexName, segKeys := range segkeysToCheck {
   103  		for segkey, blockTracker := range segKeys {
   104  			blockWG.Add(1)
   105  			go func(key, indName string, blkT *BlockTracker) {
   106  				defer blockWG.Done()
   107  				finalReq, totalBlockCount, filteredBlockCount, err := metadata.RunCmiCheck(key, indName, timeRange, blkT, bloomKeys, bloomOp,
   108  					rangeFilter, rangeOp, isRange, wildCardValue, currQuery, colsToCheck, wildcardColQuery, qid, isQueryPersistent, pqid)
   109  				if err != nil {
   110  					log.Errorf("qid=%d, getAllSearchRequestsFromCmi: Failed to get search request from cmi: %+v", qid, err)
   111  					searchRequestErrors <- err
   112  				} else {
   113  					searchRequestResults <- finalReq
   114  				}
   115  				atomic.AddUint64(&finalTotalBlockCount, totalBlockCount)
   116  				atomic.AddUint64(&finalFilteredBlockCount, filteredBlockCount)
   117  			}(segkey, indexName, blockTracker)
   118  		}
   119  	}
   120  	go func() {
   121  		blockWG.Wait()
   122  		close(searchRequestResults)
   123  		close(searchRequestErrors)
   124  	}()
   125  
   126  	for req := range searchRequestResults {
   127  		if req != nil {
   128  			finalSearchRequests = append(finalSearchRequests, req)
   129  		}
   130  	}
   131  
   132  	for err := range searchRequestErrors {
   133  		finalSearchRequestErrors = append(finalSearchRequestErrors, err)
   134  	}
   135  	return finalSearchRequests, finalTotalBlockCount, finalFilteredBlockCount, finalSearchRequestErrors
   136  }