github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/remote/codecs_search.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package remote
    22  
    23  import (
    24  	"github.com/m3db/m3/src/dbnode/encoding"
    25  	"github.com/m3db/m3/src/query/block"
    26  	"github.com/m3db/m3/src/query/errors"
    27  	rpc "github.com/m3db/m3/src/query/generated/proto/rpcpb"
    28  	"github.com/m3db/m3/src/query/models"
    29  	"github.com/m3db/m3/src/query/storage"
    30  	"github.com/m3db/m3/src/query/storage/m3/consolidators"
    31  	"github.com/m3db/m3/src/x/serialize"
    32  )
    33  
    34  func multiTagResultsToM3TagProperties(
    35  	results []consolidators.MultiTagResult,
    36  	encoderPool serialize.TagEncoderPool,
    37  ) (*rpc.M3TagProperties, error) {
    38  	props := make([]rpc.M3TagProperty, len(results))
    39  	for i, result := range results {
    40  		tags, err := compressedTagsFromTagIterator(result.Iter, encoderPool)
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  
    45  		props[i] = rpc.M3TagProperty{
    46  			Id:             result.ID.Bytes(),
    47  			CompressedTags: tags,
    48  		}
    49  	}
    50  
    51  	pprops := make([]*rpc.M3TagProperty, len(props))
    52  	for i := range props {
    53  		pprops[i] = &props[i]
    54  	}
    55  
    56  	return &rpc.M3TagProperties{
    57  		Properties: pprops,
    58  	}, nil
    59  }
    60  
    61  // encodeToCompressedSearchResult encodes SearchResults to a compressed
    62  // search result.
    63  func encodeToCompressedSearchResult(
    64  	results []consolidators.MultiTagResult,
    65  	metadata block.ResultMetadata,
    66  	pools encoding.IteratorPools,
    67  ) (*rpc.SearchResponse, error) {
    68  	if pools == nil {
    69  		return nil, errors.ErrCannotEncodeCompressedTags
    70  	}
    71  
    72  	encoderPool := pools.TagEncoder()
    73  	if encoderPool == nil {
    74  		return nil, errors.ErrCannotEncodeCompressedTags
    75  	}
    76  
    77  	compressedTags, err := multiTagResultsToM3TagProperties(results, encoderPool)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return &rpc.SearchResponse{
    83  		Value: &rpc.SearchResponse_Compressed{
    84  			Compressed: compressedTags,
    85  		},
    86  
    87  		Meta: encodeResultMetadata(metadata),
    88  	}, nil
    89  }
    90  
    91  func decodeDecompressedSearchResponse(
    92  	response *rpc.TagProperties,
    93  	pools encoding.IteratorPools,
    94  ) (models.Metrics, error) {
    95  	return nil, errors.ErrNotImplemented
    96  }
    97  
    98  func decodeCompressedSearchResponse(
    99  	response *rpc.M3TagProperties,
   100  	pools encoding.IteratorPools,
   101  ) ([]consolidators.MultiTagResult, error) {
   102  	if pools == nil || pools.CheckedBytesWrapper() == nil || pools.TagDecoder() == nil {
   103  		return nil, errors.ErrCannotDecodeCompressedTags
   104  	}
   105  
   106  	cbwPool := pools.CheckedBytesWrapper()
   107  	decoderPool := pools.TagDecoder()
   108  	idPool := pools.ID()
   109  
   110  	props := response.GetProperties()
   111  	decoded := make([]consolidators.MultiTagResult, len(props))
   112  	for i, prop := range props {
   113  		checkedBytes := cbwPool.Get(prop.GetCompressedTags())
   114  		decoder := decoderPool.Get()
   115  		decoder.Reset(checkedBytes)
   116  		if err := decoder.Err(); err != nil {
   117  			return nil, err
   118  		}
   119  
   120  		id := idPool.BinaryID(cbwPool.Get(prop.GetId()))
   121  		decoded[i] = consolidators.MultiTagResult{
   122  			ID: id,
   123  			// Copy underlying TagIterator bytes before closing the decoder and returning it to the pool
   124  			Iter: decoder.Duplicate(),
   125  		}
   126  
   127  		decoder.Close()
   128  	}
   129  
   130  	return decoded, nil
   131  }
   132  
   133  func decodeSearchResponse(
   134  	response *rpc.SearchResponse,
   135  	pools encoding.IteratorPools,
   136  	tagOptions models.TagOptions,
   137  ) (models.Metrics, error) {
   138  	if compressed := response.GetCompressed(); compressed != nil {
   139  		results, err := decodeCompressedSearchResponse(compressed, pools)
   140  		if err != nil {
   141  			return nil, err
   142  		}
   143  
   144  		metrics := make(models.Metrics, len(results))
   145  		for i, r := range results {
   146  			m, err := storage.FromM3IdentToMetric(r.ID, r.Iter, tagOptions)
   147  			if err != nil {
   148  				return nil, err
   149  			}
   150  
   151  			metrics[i] = m
   152  		}
   153  
   154  		return metrics, nil
   155  	}
   156  
   157  	if decompressed := response.GetDecompressed(); decompressed != nil {
   158  		return decodeDecompressedSearchResponse(decompressed, pools)
   159  	}
   160  
   161  	return nil, errors.ErrUnexpectedGRPCResponseType
   162  }
   163  
   164  // encodeSearchRequest encodes search request into rpc SearchRequest
   165  func encodeSearchRequest(
   166  	query *storage.FetchQuery,
   167  	options *storage.FetchOptions,
   168  ) (*rpc.SearchRequest, error) {
   169  	matchers, err := encodeTagMatchers(query.TagMatchers)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	opts, err := encodeFetchOptions(options)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	return &rpc.SearchRequest{
   180  		Matchers: &rpc.SearchRequest_TagMatchers{
   181  			TagMatchers: matchers,
   182  		},
   183  
   184  		Start:   fromTime(query.Start),
   185  		End:     fromTime(query.End),
   186  		Options: opts,
   187  	}, nil
   188  }
   189  
   190  // decodeSearchRequest decodes rpc search request to read query and read options
   191  func decodeSearchRequest(
   192  	req *rpc.SearchRequest,
   193  ) (*storage.FetchQuery, error) {
   194  	matchers, err := decodeTagMatchers(req.GetTagMatchers())
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	return &storage.FetchQuery{
   200  		TagMatchers: matchers,
   201  		Start:       toTime(req.GetStart()),
   202  		End:         toTime(req.GetEnd()),
   203  	}, nil
   204  }