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 }