Files
eventstore/lmdb/count.go
fiatjaf 13db9b84a7
Some checks failed
build cli / make-release (push) Has been cancelled
build cli / build-linux (push) Has been cancelled
lmdb: remove prefix matching support.
2024-04-15 20:03:33 -03:00

96 lines
2.3 KiB
Go

package lmdb
import (
"bytes"
"context"
"encoding/binary"
"github.com/PowerDNS/lmdb-go/lmdb"
"github.com/nbd-wtf/go-nostr"
nostr_binary "github.com/nbd-wtf/go-nostr/binary"
)
func (b *LMDBBackend) CountEvents(ctx context.Context, filter nostr.Filter) (int64, error) {
var count int64 = 0
queries, extraFilter, since, err := b.prepareQueries(filter)
if err != nil {
return 0, err
}
err = b.lmdbEnv.View(func(txn *lmdb.Txn) error {
// actually iterate
for _, q := range queries {
cursor, err := txn.OpenCursor(q.dbi)
if err != nil {
continue
}
var k []byte
var idx []byte
var iterr error
if _, _, errsr := cursor.Get(q.startingPoint, nil, lmdb.SetRange); errsr != nil {
if operr, ok := errsr.(*lmdb.OpError); !ok || operr.Errno != lmdb.NotFound {
// in this case it's really an error
panic(err)
} else {
// we're at the end and we just want notes before this,
// so we just need to set the cursor the last key, this is not a real error
k, idx, iterr = cursor.Get(nil, nil, lmdb.Last)
}
} else {
// move one back as the first step
k, idx, iterr = cursor.Get(nil, nil, lmdb.Prev)
}
for {
// we already have a k and a v and an err from the cursor setup, so check and use these
if iterr != nil ||
len(k) != q.prefixSize+q.timestampSize ||
!bytes.Equal(k[:q.prefixSize], q.prefix) {
// either iteration has errored or we reached the end of this prefix
break // stop this cursor and move to the next one
}
// "id" indexes don't contain a timestamp
if q.timestampSize == 4 {
createdAt := binary.BigEndian.Uint32(k[len(k)-4:])
if createdAt < since {
break
}
}
if extraFilter == nil {
count++
} else {
// fetch actual event
val, err := txn.Get(b.rawEventStore, idx)
if err != nil {
panic(err)
}
evt := &nostr.Event{}
if err := nostr_binary.Unmarshal(val, evt); err != nil {
return err
}
// check if this matches the other filters that were not part of the index
if extraFilter.Matches(evt) {
count++
}
return nil
}
// move one back (we'll look into k and v and err in the next iteration)
k, idx, iterr = cursor.Get(nil, nil, lmdb.Prev)
}
}
return nil
})
return count, err
}