mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 00:55:55 +00:00
add CountRange()
This commit adds `roaring.Bitmap.CountRange()` to return the number of bits in a subrange of a bitmap. This significantly improves server start time and is needed for upcoming zero copy bitmap optimizations.
This commit is contained in:
parent
d2106de4c0
commit
888040c26c
2 changed files with 82 additions and 1 deletions
|
|
@ -234,7 +234,8 @@ func (f *Fragment) openCache() error {
|
|||
// Read in all bitmaps by ID.
|
||||
// This will cause them to be added to the cache.
|
||||
for _, bitmapID := range pb.GetBitmapIDs() {
|
||||
f.bitmap(bitmapID)
|
||||
n := f.storage.CountRange(bitmapID*SliceWidth, (bitmapID+1)*SliceWidth)
|
||||
f.cache.Add(bitmapID, n)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"sort"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
|
@ -134,6 +135,41 @@ func (b *Bitmap) Count() (n uint64) {
|
|||
return n
|
||||
}
|
||||
|
||||
// CountRange returns the number of bits set between [start, end).
|
||||
func (b *Bitmap) CountRange(start, end uint64) (n uint64) {
|
||||
i := search64(b.keys, highbits(start))
|
||||
j := search64(b.keys, highbits(end))
|
||||
|
||||
// If range is entirely in one container then just count that range.
|
||||
if i > 0 && i == j {
|
||||
return uint64(b.containers[i].countRange(lowbits(start), lowbits(end)))
|
||||
}
|
||||
|
||||
// Count first partial container.
|
||||
if i < 0 {
|
||||
i = -i
|
||||
} else {
|
||||
n += uint64(b.containers[i].countRange(lowbits(start), (bitmapN*64)+1))
|
||||
}
|
||||
|
||||
// Count last container.
|
||||
if j < 0 {
|
||||
j = -j
|
||||
if j > len(b.containers) {
|
||||
j = len(b.containers)
|
||||
}
|
||||
} else {
|
||||
n += uint64(b.containers[j].countRange(0, lowbits(end)))
|
||||
}
|
||||
|
||||
// Count containers in between.
|
||||
for x := i + 1; x < j; x++ {
|
||||
n += uint64(b.containers[x].n)
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Slice returns a slice of all integers in the bitmap.
|
||||
func (b *Bitmap) Slice() []uint64 {
|
||||
var a []uint64
|
||||
|
|
@ -658,6 +694,50 @@ func (c *container) unmap() {
|
|||
c.mapped = false
|
||||
}
|
||||
|
||||
// countRange counts the number of bits set between [start, end).
|
||||
func (c *container) countRange(start, end uint32) (n int) {
|
||||
if c.isArray() {
|
||||
return c.arrayCountRange(start, end)
|
||||
}
|
||||
return c.bitmapCountRange(start, end)
|
||||
}
|
||||
|
||||
func (c *container) arrayCountRange(start, end uint32) (n int) {
|
||||
i := sort.Search(len(c.array), func(i int) bool { return c.array[i] >= start })
|
||||
for ; i < len(c.array); i++ {
|
||||
v := c.array[i]
|
||||
if v >= end {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *container) bitmapCountRange(start, end uint32) int {
|
||||
var n uint64
|
||||
i, j := start/64, end/64
|
||||
|
||||
// Count partial starting word.
|
||||
if off := start % 64; off != 0 {
|
||||
n += popcount(c.bitmap[i] << off)
|
||||
}
|
||||
|
||||
// Count words in between.
|
||||
for ; i < j; i++ {
|
||||
n += popcount(c.bitmap[i])
|
||||
}
|
||||
|
||||
// Count partial ending word.
|
||||
if int(j) < len(c.bitmap) {
|
||||
if off := end % 64; off != 0 {
|
||||
n += popcount(c.bitmap[j] >> off)
|
||||
}
|
||||
}
|
||||
|
||||
return int(n)
|
||||
}
|
||||
|
||||
// add adds a value to the container.
|
||||
func (c *container) add(v uint32) bool {
|
||||
if c.isArray() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue