github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/reader/segread/rollupreader.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 segread 18 19 import ( 20 "fmt" 21 "io" 22 "os" 23 "path" 24 25 "github.com/bits-and-blooms/bitset" 26 "github.com/cespare/xxhash" 27 "github.com/siglens/siglens/pkg/blob" 28 "github.com/siglens/siglens/pkg/segment/pqmr" 29 segutils "github.com/siglens/siglens/pkg/segment/utils" 30 "github.com/siglens/siglens/pkg/segment/writer" 31 "github.com/siglens/siglens/pkg/utils" 32 33 log "github.com/sirupsen/logrus" 34 ) 35 36 type RollupReader struct { 37 minRupFd *os.File 38 hourRupFd *os.File 39 dayRupFd *os.File 40 41 // map[blkNum] ==> map[tsBuckKey] ==> RolledRecsForMatchedRecNums 42 allBlocksTomRollup map[uint16]map[uint64]*writer.RolledRecs 43 allBlocksTohRollup map[uint16]map[uint64]*writer.RolledRecs 44 allBlocksTodRollup map[uint16]map[uint64]*writer.RolledRecs 45 46 allBlocksTomLoaded bool 47 allBlocksTohLoaded bool 48 allBlocksTodLoaded bool 49 qid uint64 50 allInUseFiles []string 51 } 52 53 func InitNewRollupReader(segKey string, tsKey string, qid uint64) (*RollupReader, error) { 54 allInUseFiles := make([]string, 0) 55 fName := fmt.Sprintf("%v/rups/%v.crup", path.Dir(segKey), xxhash.Sum64String(tsKey+"m")) 56 err := blob.DownloadSegmentBlob(fName, true) 57 if err != nil { 58 log.Errorf("qid=%d, InitNewRollupReader failed to download min rollup file. %+v, err=%v", qid, fName, err) 59 return nil, err 60 } 61 minRupFd, err := os.OpenFile(fName, os.O_RDONLY, 0644) 62 if err != nil { 63 log.Errorf("qid=%d, InitNewRollupReader: failed to open min rollup file %s. Error: %+v", qid, fName, err) 64 return &RollupReader{}, err 65 } 66 allInUseFiles = append(allInUseFiles, fName) 67 68 fName = fmt.Sprintf("%v/rups/%v.crup", path.Dir(segKey), xxhash.Sum64String(tsKey+"h")) 69 err = blob.DownloadSegmentBlob(fName, true) 70 if err != nil { 71 log.Errorf("qid=%d, InitNewRollupReader failed to download hour rollup file. %+v, err=%v", qid, fName, err) 72 return nil, err 73 } 74 hourRupFd, err := os.OpenFile(fName, os.O_RDONLY, 0644) 75 if err != nil { 76 log.Errorf("qid=%d, InitNewRollupReader: failed to open hour rollup file %s. Error: %+v", qid, fName, err) 77 return &RollupReader{}, err 78 } 79 allInUseFiles = append(allInUseFiles, fName) 80 81 fName = fmt.Sprintf("%v/rups/%v.crup", path.Dir(segKey), xxhash.Sum64String(tsKey+"d")) 82 err = blob.DownloadSegmentBlob(fName, true) 83 if err != nil { 84 log.Errorf("qid=%d, InitNewRollupReader failed to download day rollup file. %+v, err=%v", qid, fName, err) 85 return nil, err 86 } 87 dayRupFd, err := os.OpenFile(fName, os.O_RDONLY, 0644) 88 if err != nil { 89 log.Errorf("qid=%d, InitNewRollupReader: failed to open day rollup file %s. Error: %+v", qid, fName, err) 90 return &RollupReader{}, err 91 } 92 allInUseFiles = append(allInUseFiles, fName) 93 94 allBlocksTomRollup := make(map[uint16]map[uint64]*writer.RolledRecs) 95 allBlocksTohRollup := make(map[uint16]map[uint64]*writer.RolledRecs) 96 allBlocksTodRollup := make(map[uint16]map[uint64]*writer.RolledRecs) 97 98 return &RollupReader{ 99 minRupFd: minRupFd, 100 hourRupFd: hourRupFd, 101 dayRupFd: dayRupFd, 102 allBlocksTomRollup: allBlocksTomRollup, 103 allBlocksTohRollup: allBlocksTohRollup, 104 allBlocksTodRollup: allBlocksTodRollup, 105 qid: qid, 106 allInUseFiles: allInUseFiles, 107 }, nil 108 } 109 110 func (rur *RollupReader) Close() { 111 if rur.minRupFd != nil { 112 rur.minRupFd.Close() 113 } 114 if rur.hourRupFd != nil { 115 rur.hourRupFd.Close() 116 } 117 if rur.dayRupFd != nil { 118 rur.dayRupFd.Close() 119 } 120 err := blob.SetSegSetFilesAsNotInUse(rur.allInUseFiles) 121 if err != nil { 122 log.Errorf("Failed to release needed segment files from local storage %+v! Err: %+v", rur.allInUseFiles, err) 123 } 124 } 125 126 func (rur *RollupReader) GetMinRollups() (map[uint16]map[uint64]*writer.RolledRecs, error) { 127 if rur.allBlocksTomLoaded { 128 return rur.allBlocksTomRollup, nil 129 } 130 err := readRollupFile(rur.minRupFd, rur.allBlocksTomRollup, rur.qid) 131 if err != nil { 132 log.Errorf("qid=%d, GetMinRollups: failed to read min rollups: err=%v", rur.qid, err) 133 return nil, err 134 } 135 rur.allBlocksTomLoaded = true 136 return rur.allBlocksTomRollup, err 137 } 138 139 func (rur *RollupReader) GetHourRollups() (map[uint16]map[uint64]*writer.RolledRecs, error) { 140 if rur.allBlocksTohLoaded { 141 return rur.allBlocksTohRollup, nil 142 } 143 err := readRollupFile(rur.hourRupFd, rur.allBlocksTohRollup, rur.qid) 144 if err != nil { 145 log.Errorf("qid=%d, GetHourRollups: failed to read hour rollups: err=%v", rur.qid, err) 146 return nil, err 147 } 148 rur.allBlocksTohLoaded = true 149 return rur.allBlocksTohRollup, err 150 } 151 152 func (rur *RollupReader) GetDayRollups() (map[uint16]map[uint64]*writer.RolledRecs, error) { 153 if rur.allBlocksTodLoaded { 154 return rur.allBlocksTodRollup, nil 155 } 156 err := readRollupFile(rur.dayRupFd, rur.allBlocksTodRollup, rur.qid) 157 if err != nil { 158 log.Errorf("qid=%d, GetDayRollups: failed to read min rollups: err=%v", rur.qid, err) 159 return nil, err 160 } 161 rur.allBlocksTodLoaded = true 162 return rur.allBlocksTodRollup, err 163 } 164 165 func readRollupFile(fd *os.File, 166 allBlks map[uint16]map[uint64]*writer.RolledRecs, qid uint64) error { 167 168 offset := int64(0) 169 var blkNum uint16 170 bbBlkNum := make([]byte, 2) // blkNum (2) 171 var bKey uint64 172 bbBKey := make([]byte, 8) // for bucket key timestamp 173 var numBucks uint16 174 bbNumBucks := make([]byte, 2) // for num of buckets 175 var mrSize uint16 176 bbMrSize := make([]byte, 2) // for bitset match result size 177 178 bsBlk := make([]byte, segutils.WIP_NUM_RECS/8) 179 180 for { 181 // read blkNum 182 _, err := fd.ReadAt(bbBlkNum, offset) 183 if err != nil { 184 if err != io.EOF { 185 log.Errorf("qid=%d, readRollupFile: failed to read blkNum len err=[%+v]", qid, err) 186 return err 187 } 188 break 189 } 190 offset += 2 191 blkNum = utils.BytesToUint16LittleEndian(bbBlkNum[:]) 192 toxRollup := make(map[uint64]*writer.RolledRecs) 193 allBlks[blkNum] = toxRollup 194 195 // read num of buckets 196 _, err = fd.ReadAt(bbNumBucks, offset) 197 if err != nil { 198 if err != io.EOF { 199 log.Errorf("qid=%d, readRollupFile: failed to read blkNum len err=[%+v]", qid, err) 200 return err 201 } 202 break 203 } 204 offset += 2 205 numBucks = utils.BytesToUint16LittleEndian(bbNumBucks[:]) 206 207 for i := uint16(0); i < numBucks; i++ { 208 // read bucketKey timestamp 209 _, err = fd.ReadAt(bbBKey, offset) 210 if err != nil { 211 log.Errorf("qid=%d, readRollupFile: failed to read bKey for blkNum=%v, i=%v, err=[%+v]", 212 qid, blkNum, i, err) 213 return err 214 } 215 offset += 8 216 bKey = utils.BytesToUint64LittleEndian(bbBKey[:]) 217 218 // skip forward for RR_ENC_BITSET, since thats the only type we support today 219 offset += 1 220 221 // read matched result bitset size 222 _, err = fd.ReadAt(bbMrSize, offset) 223 if err != nil { 224 log.Errorf("qid=%d, readRollupFile: failed to read mrsize for blkNum=%v, i=%v, err=[%+v]", 225 qid, blkNum, i, err) 226 return err 227 } 228 offset += 2 229 mrSize = utils.BytesToUint16LittleEndian(bbMrSize[:]) 230 231 if currBufSize := len(bsBlk); int(mrSize) > currBufSize { 232 toAdd := int(mrSize) - currBufSize 233 newSlice := make([]byte, toAdd) 234 bsBlk = append(bsBlk, newSlice...) 235 } 236 237 // read the actual bitset 238 _, err = fd.ReadAt(bsBlk[:mrSize], offset) 239 if err != nil { 240 if err != io.EOF { 241 log.Errorf("qid=%d, readRollupFile: failed to read bitset err=[%+v]", qid, err) 242 return err 243 } 244 break 245 } 246 offset += int64(mrSize) 247 248 bs := bitset.New(0) 249 err = bs.UnmarshalBinary(bsBlk[:mrSize]) 250 if err != nil { 251 log.Errorf("qid=%d, readRollupFile: failed to unmarshall bitset err=[%+v]", qid, err) 252 return err 253 } 254 255 mr := pqmr.CreatePQMatchResultsFromBs(bs) 256 rr := &writer.RolledRecs{MatchedRes: mr} 257 toxRollup[bKey] = rr 258 } 259 } 260 return nil 261 }