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