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  }