github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/search/searchstatus_test.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 search
    18  
    19  import (
    20  	"os"
    21  	"testing"
    22  
    23  	dtu "github.com/siglens/siglens/pkg/common/dtypeutils"
    24  	"github.com/siglens/siglens/pkg/segment/pqmr"
    25  	"github.com/siglens/siglens/pkg/segment/results/segresults"
    26  	"github.com/siglens/siglens/pkg/segment/structs"
    27  	"github.com/siglens/siglens/pkg/segment/utils"
    28  	log "github.com/sirupsen/logrus"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  /*
    33  TODO: more tests
    34  test not first updates have different results depending on op
    35  test combination of multiple update types
    36  */
    37  
    38  func mockRecCountBlockSummaries(numBlocks uint16, numRecsPerBlock uint16) []*structs.BlockSummary {
    39  	finalSums := make([]*structs.BlockSummary, numBlocks)
    40  	for i := uint16(0); i < numBlocks; i++ {
    41  		finalSums[i] = &structs.BlockSummary{
    42  			RecCount: numRecsPerBlock,
    43  		}
    44  	}
    45  	return finalSums
    46  }
    47  
    48  func mockSSR(numBlocks uint16) *structs.SegmentSearchRequest {
    49  	bMeta := make(map[uint16]*structs.BlockMetadataHolder)
    50  	for i := uint16(0); i < numBlocks; i++ {
    51  		bMeta[i] = &structs.BlockMetadataHolder{}
    52  	}
    53  	return &structs.SegmentSearchRequest{
    54  		AllBlocksToSearch: bMeta,
    55  	}
    56  }
    57  
    58  func initMockSearchStatus(numBlocks uint16, numRecs uint16) *SegmentSearchStatus {
    59  	bSum := mockRecCountBlockSummaries(numBlocks, numRecs)
    60  	mockSSR := mockSSR(numBlocks)
    61  	status := InitBlocksToSearch(mockSSR, bSum, &segresults.SearchResults{}, &dtu.TimeRange{StartEpochMs: 0, EndEpochMs: uint64(numRecs)})
    62  	return status
    63  }
    64  
    65  func Test_InitSearchStatus(t *testing.T) {
    66  
    67  	numBlocks := uint16(10)
    68  	numRecs := uint16(10)
    69  	bSum := mockRecCountBlockSummaries(numBlocks, numRecs)
    70  	mockSSR := mockSSR(numBlocks)
    71  	status := InitBlocksToSearch(mockSSR, bSum, &segresults.SearchResults{}, &dtu.TimeRange{StartEpochMs: 0, EndEpochMs: uint64(numRecs)})
    72  
    73  	sumMatched, sumUnmatched := status.getTotalCounts()
    74  	assert.Equal(t, uint64(numBlocks*numRecs), sumMatched, "expected=%v, actual=%v", numBlocks*numRecs, sumMatched)
    75  	assert.Equal(t, sumUnmatched, uint64(0))
    76  
    77  	bSearchHelper := structs.InitBlockSearchHelper()
    78  	for i := uint16(0); i < numBlocks; i++ {
    79  		bSearchHelper.ResetBlockHelper()
    80  		for j := uint(0); j < uint(numRecs); j++ {
    81  			bSearchHelper.AddMatchedRecord(j)
    82  		}
    83  		matchedRecs := bSearchHelper.GetAllMatchedRecords()
    84  		assert.Equal(t, int(matchedRecs.GetNumberOfSetBits()), int(numRecs))
    85  	}
    86  
    87  	assert.Len(t, status.AllBlockStatus, int(numBlocks))
    88  	for _, blkStatus := range status.AllBlockStatus {
    89  		recITerator, err := blkStatus.GetRecordIteratorForBlock(utils.And)
    90  		assert.Nil(t, err)
    91  		assert.Equal(t, recITerator.AllRecLen, numRecs)
    92  		for j := uint(0); j < uint(recITerator.AllRecLen); j++ {
    93  			shoulProcess := recITerator.ShouldProcessRecord(j)
    94  			assert.True(t, shoulProcess, j)
    95  		}
    96  	}
    97  }
    98  
    99  func Test_FirstSearchRecords(t *testing.T) {
   100  
   101  	numBlocks := uint16(10)
   102  	numRecs := uint16(10)
   103  	status := initMockSearchStatus(numBlocks, numRecs)
   104  
   105  	// initial and sets
   106  	// type of search request should not influence the results for the first time
   107  	for blkNum := uint16(0); blkNum < numBlocks; blkNum++ {
   108  		recITerator, err := status.GetRecordIteratorForBlock(utils.And, blkNum)
   109  		assert.Nil(t, err)
   110  		assert.Equal(t, recITerator.AllRecLen, numRecs)
   111  		for j := uint(0); j < uint(numRecs); j++ {
   112  			readNum := recITerator.ShouldProcessRecord(j)
   113  			assert.True(t, readNum)
   114  		}
   115  
   116  		recITerator, err = status.GetRecordIteratorForBlock(utils.Or, blkNum)
   117  		assert.Nil(t, err)
   118  		assert.Equal(t, recITerator.AllRecLen, numRecs)
   119  		for j := uint(0); j < uint(numRecs); j++ {
   120  			readNum := recITerator.ShouldProcessRecord(j)
   121  			assert.True(t, readNum)
   122  		}
   123  
   124  		recITerator, err = status.GetRecordIteratorForBlock(utils.Exclusion, blkNum)
   125  		assert.Nil(t, err)
   126  		assert.Equal(t, recITerator.AllRecLen, numRecs)
   127  		for j := uint(0); j < uint(numRecs); j++ {
   128  			readNum := recITerator.ShouldProcessRecord(j)
   129  			assert.True(t, readNum)
   130  		}
   131  	}
   132  }
   133  
   134  func Test_UpdateAndSearch(t *testing.T) {
   135  
   136  	numBlocks := uint16(10)
   137  	numRecs := uint16(10)
   138  	status := initMockSearchStatus(numBlocks, numRecs)
   139  	// test or/and/exclustion updates
   140  	matched := pqmr.CreatePQMatchResults(1)
   141  	matched.AddMatchedRecord(0)
   142  	err := status.updateMatchedRecords(0, matched, utils.And)
   143  	assert.Nil(t, err)
   144  	recITerator, err := status.GetRecordIteratorForBlock(utils.And, 0)
   145  	assert.Nil(t, err)
   146  	processZero := recITerator.ShouldProcessRecord(0)
   147  	assert.True(t, processZero)
   148  	assert.Equal(t, recITerator.AllRecLen, numRecs)
   149  
   150  	for i := uint(1); i < uint(recITerator.AllRecLen); i++ {
   151  		process := recITerator.ShouldProcessRecord(i)
   152  		assert.False(t, process)
   153  	}
   154  
   155  	blkStatus := status.AllBlockStatus[0]
   156  	matchedRecs := blkStatus.allRecords.GetNumberOfSetBits()
   157  	UnmatchedRecs := uint64(blkStatus.numRecords) - uint64(blkStatus.allRecords.GetNumberOfSetBits())
   158  	assert.False(t, blkStatus.firstSearch)
   159  	assert.Equal(t, blkStatus.numRecords, uint16(10))
   160  	assert.Equal(t, matchedRecs, uint(1))
   161  	assert.Equal(t, uint64(UnmatchedRecs), uint64(numRecs-1))
   162  	log.Infof("block status after one and update %+v", blkStatus)
   163  }
   164  
   165  func Test_UpdateOrSearch(t *testing.T) {
   166  
   167  	numBlocks := uint16(10)
   168  	numRecs := uint16(10)
   169  	status := initMockSearchStatus(numBlocks, numRecs)
   170  	// test or/and/exclustion updates
   171  	matched := pqmr.CreatePQMatchResults(1)
   172  	matched.AddMatchedRecord(0)
   173  	err := status.updateMatchedRecords(0, matched, utils.Or)
   174  	assert.Nil(t, err)
   175  
   176  	recITerator, err := status.GetRecordIteratorForBlock(utils.Or, 0)
   177  	assert.Nil(t, err)
   178  	assert.False(t, recITerator.firstSearch)
   179  	orCount := 0
   180  
   181  	process := recITerator.ShouldProcessRecord(0)
   182  	assert.False(t, process)
   183  	for i := uint(1); i < uint(recITerator.AllRecLen); i++ {
   184  		process := recITerator.ShouldProcessRecord(i)
   185  		assert.True(t, process)
   186  		orCount++
   187  	}
   188  	assert.Equal(t, orCount, int(numRecs-1), "search all except recNum 0")
   189  
   190  	blkStatus := status.AllBlockStatus[0]
   191  
   192  	assert.False(t, blkStatus.firstSearch)
   193  	assert.Equal(t, uint64(uint64(blkStatus.numRecords)-uint64(blkStatus.allRecords.GetNumberOfSetBits())), uint64(numRecs-1))
   194  	assert.Equal(t, blkStatus.allRecords.GetNumberOfSetBits(), uint(1))
   195  
   196  	moreOrMatch := pqmr.CreatePQMatchResults(2)
   197  	moreOrMatch.AddMatchedRecord(1)
   198  	moreOrMatch.AddMatchedRecord(2)
   199  
   200  	err = status.updateMatchedRecords(0, moreOrMatch, utils.Or)
   201  	assert.Nil(t, err)
   202  	recITerator, err = status.GetRecordIteratorForBlock(utils.Or, 0)
   203  	assert.Nil(t, err)
   204  	assert.False(t, recITerator.firstSearch)
   205  	assert.Equal(t, recITerator.AllRecLen, numRecs)
   206  
   207  	for i := uint(0); i < uint(3); i++ {
   208  		process := recITerator.ShouldProcessRecord(i)
   209  		assert.False(t, process)
   210  	}
   211  	orCount = 0
   212  	for i := uint(3); i < uint(numRecs); i++ {
   213  		process := recITerator.ShouldProcessRecord(i)
   214  		assert.True(t, process)
   215  		orCount++
   216  	}
   217  
   218  	assert.Equal(t, orCount, int(numRecs-3), "search all except recNum 0,1,2")
   219  	blkStatus = status.AllBlockStatus[0]
   220  	matchedRecs := blkStatus.allRecords.GetNumberOfSetBits()
   221  	unmatchedRecs := uint64(blkStatus.numRecords) - uint64(blkStatus.allRecords.GetNumberOfSetBits())
   222  	assert.False(t, blkStatus.firstSearch)
   223  	assert.Equal(t, uint64(unmatchedRecs), uint64(numRecs-3))
   224  	assert.Equal(t, matchedRecs, uint(3), "matched 0,1,2")
   225  
   226  	log.Infof("block status after one or update %+v", blkStatus)
   227  }
   228  
   229  func Test_UpdateExclusionSearch(t *testing.T) {
   230  
   231  	numBlocks := uint16(10)
   232  	numRecs := uint16(10)
   233  	status := initMockSearchStatus(numBlocks, numRecs)
   234  	// test or/and/exclustion updates
   235  	matched := pqmr.CreatePQMatchResults(1)
   236  	matched.AddMatchedRecord(0)
   237  	err := status.updateMatchedRecords(0, matched, utils.Exclusion)
   238  	assert.Nil(t, err)
   239  
   240  	recITerator, err := status.GetRecordIteratorForBlock(utils.Exclusion, 0)
   241  	assert.Nil(t, err)
   242  	assert.False(t, recITerator.firstSearch)
   243  	orCount := 0
   244  	startTs := uint64(1)
   245  	assert.Equal(t, recITerator.AllRecLen, numRecs)
   246  	assert.False(t, recITerator.ShouldProcessRecord(0))
   247  
   248  	for i := uint(1); i < uint(numRecs); i++ {
   249  		readRec := recITerator.ShouldProcessRecord(i)
   250  		log.Infof("iter next %+v %+v", i, readRec)
   251  		assert.True(t, readRec, "i=%v", i)
   252  		startTs++
   253  		orCount++
   254  	}
   255  	assert.Equal(t, orCount, int(numRecs-1), "search all except recNum 0")
   256  
   257  	blkStatus := status.AllBlockStatus[0]
   258  	matchedRecs := blkStatus.allRecords.GetNumberOfSetBits()
   259  	unmatchedRecs := uint64(blkStatus.numRecords) - uint64(blkStatus.allRecords.GetNumberOfSetBits())
   260  	assert.False(t, blkStatus.firstSearch)
   261  	assert.Equal(t, uint64(1), uint64(unmatchedRecs), "expected=1, unmatched=%v", unmatchedRecs)
   262  	assert.Equal(t, matchedRecs, uint(numRecs-1))
   263  	log.Infof("block status after one exclusion update %+v", blkStatus)
   264  }
   265  
   266  func Test_ReadAndWritePqmrFilesEncode(t *testing.T) {
   267  	fname := "pqmr_encode.pqmr"
   268  	os.Remove(fname)
   269  	numBlocks := uint16(400)
   270  	numRecs := uint(20_000)
   271  	reqLen := uint64(0)
   272  	pbset := pqmr.CreatePQMatchResults(14000)
   273  
   274  	for recNum := uint(0); recNum < numRecs; recNum++ {
   275  		if recNum%3 == 0 {
   276  			pbset.AddMatchedRecord(recNum)
   277  		}
   278  	}
   279  
   280  	for i := uint16(0); i < numBlocks; i++ {
   281  		// Adding 2 bytes for blockNum and 2 bytes for blockLen
   282  		size := 4 + pbset.GetInMemSize()
   283  		reqLen += size
   284  	}
   285  
   286  	buf := make([]byte, reqLen)
   287  	var idx uint32
   288  
   289  	for i := uint16(0); i < numBlocks; i++ {
   290  		packedLen, err := pbset.EncodePqmr(buf[idx:], i)
   291  		assert.Equal(t, nil, err)
   292  		idx += uint32(packedLen)
   293  	}
   294  
   295  	err := pqmr.WritePqmrToDisk(buf[0:idx], fname)
   296  	assert.Nil(t, err)
   297  
   298  	res, err := pqmr.ReadPqmr(&fname)
   299  	assert.Nil(t, err)
   300  	assert.NotNil(t, res)
   301  	assert.Equal(t, numBlocks, res.GetNumBlocks())
   302  	os.Remove(fname)
   303  }