get-serials-by-range.go raw

   1  //go:build !(js && wasm)
   2  
   3  package database
   4  
   5  import (
   6  	"bytes"
   7  	"sort"
   8  
   9  	"github.com/dgraph-io/badger/v4"
  10  	"next.orly.dev/pkg/lol/chk"
  11  	"next.orly.dev/pkg/database/indexes/types"
  12  )
  13  
  14  func (d *D) GetSerialsByRange(idx Range) (
  15  	sers types.Uint40s, err error,
  16  ) {
  17  	// Pre-allocate slice with estimated capacity to reduce reallocations
  18  	sers = make(types.Uint40s, 0, 100) // Estimate based on typical range sizes
  19  	if err = d.View(
  20  		func(txn *badger.Txn) (err error) {
  21  			it := txn.NewIterator(
  22  				badger.IteratorOptions{
  23  					Reverse: true,
  24  				},
  25  			)
  26  			defer it.Close()
  27  			// Start from a position that includes the end boundary (until timestamp)
  28  			// We create an end boundary that's slightly beyond the actual end to ensure inclusivity
  29  			endBoundary := make([]byte, len(idx.End))
  30  			copy(endBoundary, idx.End)
  31  			// Add 0xff bytes to ensure we capture all events at the exact until timestamp
  32  			for i := 0; i < 5; i++ {
  33  				endBoundary = append(endBoundary, 0xff)
  34  			}
  35  			it.Seek(endBoundary)
  36  			for it.Valid() {
  37  				item := it.Item()
  38  				var key []byte
  39  				key = item.Key()
  40  				keyWithoutSerial := key[:len(key)-5]
  41  				cmp := bytes.Compare(keyWithoutSerial, idx.Start)
  42  				if cmp < 0 {
  43  					// didn't find it within the timestamp range
  44  					return
  45  				}
  46  				ser := new(types.Uint40)
  47  				buf := bytes.NewBuffer(key[len(key)-5:])
  48  				if err = ser.UnmarshalRead(buf); chk.E(err) {
  49  					return
  50  				}
  51  				sers = append(sers, ser)
  52  				it.Next()
  53  			}
  54  			return
  55  		},
  56  	); chk.E(err) {
  57  		return
  58  	}
  59  	sort.Slice(
  60  		sers, func(i, j int) bool {
  61  			return sers[i].Get() < sers[j].Get()
  62  		},
  63  	)
  64  	return
  65  }
  66