Skip to content

Commit 51c006d

Browse files
authored
Merge pull request #480 from customerio/clear_bits
ClearBits with AndNot
2 parents 4fe1f0a + 34a00d6 commit 51c006d

File tree

4 files changed

+88
-113
lines changed

4 files changed

+88
-113
lines changed

BitSliceIndexing/bsi.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -754,11 +754,7 @@ func batchEqual(e *task, batch []uint32, resultsChan chan *roaring.Bitmap,
754754

755755
// ClearBits cleared the bits that exist in the target if they are also in the found set.
756756
func ClearBits(foundSet, target *roaring.Bitmap) {
757-
iter := foundSet.Iterator()
758-
for iter.HasNext() {
759-
cID := iter.Next()
760-
target.Remove(cID)
761-
}
757+
target.AndNot(foundSet)
762758
}
763759

764760
// ClearValues removes the values found in foundSet
@@ -768,13 +764,13 @@ func (b *BSI) ClearValues(foundSet *roaring.Bitmap) {
768764
wg.Add(1)
769765
go func() {
770766
defer wg.Done()
771-
ClearBits(foundSet, b.eBM)
767+
b.eBM.AndNot(foundSet)
772768
}()
773769
for i := 0; i < b.BitCount(); i++ {
774770
wg.Add(1)
775771
go func(j int) {
776772
defer wg.Done()
777-
ClearBits(foundSet, b.bA[j])
773+
b.bA[j].AndNot(foundSet)
778774
}(i)
779775
}
780776
wg.Wait()

BitSliceIndexing/bsi_test.go

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package roaring
22

33
import (
44
"fmt"
5-
"io/ioutil"
65
"math/rand"
76
"os"
87
"testing"
@@ -35,6 +34,27 @@ func setup() *BSI {
3534
return bsi
3635
}
3736

37+
func setupLargeBSI(t testing.TB) *BSI {
38+
t.Helper()
39+
40+
datEBM, err := os.ReadFile("./testdata/age/EBM")
41+
if err != nil {
42+
return nil
43+
}
44+
b := make([][]byte, 9)
45+
b[0] = datEBM
46+
for i := 1; i <= 8; i++ {
47+
b[i], err = os.ReadFile(fmt.Sprintf("./testdata/age/%d", i))
48+
if err != nil {
49+
return nil
50+
}
51+
}
52+
bsi := NewDefaultBSI()
53+
err = bsi.UnmarshalBinary(b)
54+
require.NoError(t, err)
55+
return bsi
56+
}
57+
3858
func setupNegativeBoundary() *BSI {
3959

4060
bsi := NewBSI(5, -5)
@@ -264,58 +284,12 @@ func TestNewBSIRetainSet(t *testing.T) {
264284

265285
func TestLargeFile(t *testing.T) {
266286

267-
datEBM, err := ioutil.ReadFile("./testdata/age/EBM")
268-
if err != nil {
269-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
270-
return
271-
}
272-
dat1, err := ioutil.ReadFile("./testdata/age/1")
273-
if err != nil {
274-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
275-
return
276-
}
277-
dat2, err := ioutil.ReadFile("./testdata/age/2")
278-
if err != nil {
279-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
280-
return
281-
}
282-
dat3, err := ioutil.ReadFile("./testdata/age/3")
283-
if err != nil {
284-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
285-
return
286-
}
287-
dat4, err := ioutil.ReadFile("./testdata/age/4")
288-
if err != nil {
289-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
290-
return
291-
}
292-
dat5, err := ioutil.ReadFile("./testdata/age/5")
293-
if err != nil {
294-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
295-
return
296-
}
297-
dat6, err := ioutil.ReadFile("./testdata/age/6")
298-
if err != nil {
299-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
300-
return
301-
}
302-
dat7, err := ioutil.ReadFile("./testdata/age/7")
303-
if err != nil {
304-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
305-
return
306-
}
307-
dat8, err := ioutil.ReadFile("./testdata/age/8")
308-
if err != nil {
287+
bsi := setupLargeBSI(t)
288+
if bsi == nil {
309289
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
310290
return
311291
}
312292

313-
b := [][]byte{datEBM, dat1, dat2, dat3, dat4, dat5, dat6, dat7, dat8}
314-
315-
bsi := NewDefaultBSI()
316-
err = bsi.UnmarshalBinary(b)
317-
require.Nil(t, err)
318-
319293
resultA := bsi.CompareValue(0, EQ, 55, 0, nil)
320294
assert.Equal(t, uint64(520157), resultA.GetCardinality())
321295

@@ -468,6 +442,23 @@ func BenchmarkSetRoaring(b *testing.B) {
468442
}
469443
}
470444

445+
func BenchmarkClearValues(b *testing.B) {
446+
bsi := setupLargeBSI(b)
447+
if bsi == nil {
448+
b.Skip("\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
449+
return
450+
}
451+
resultA := bsi.CompareValue(0, EQ, 55, 0, nil)
452+
assert.Equal(b, uint64(520157), resultA.GetCardinality())
453+
b.ResetTimer()
454+
for i := 0; i < b.N; i++ {
455+
b.StopTimer()
456+
b2 := bsi.Clone()
457+
b.StartTimer()
458+
b2.ClearValues(resultA)
459+
}
460+
}
461+
471462
func TestIssue426(t *testing.T) {
472463
bsi := NewBSI(101, 0)
473464
bsi.SetValue(3, 5)

roaring64/bsi64.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ func (b *BSI) ParOr(parallelism int, bsis ...*BSI) {
738738
bits := len(b.bA)
739739
for i := 0; i < len(bsis); i++ {
740740
if len(bsis[i].bA) > bits {
741-
bits = len(bsis[i].bA )
741+
bits = len(bsis[i].bA)
742742
}
743743
}
744744

@@ -942,11 +942,7 @@ func batchEqual(e *task, batch []uint64, resultsChan chan *Bitmap,
942942

943943
// ClearBits cleared the bits that exist in the target if they are also in the found set.
944944
func ClearBits(foundSet, target *Bitmap) {
945-
iter := foundSet.Iterator()
946-
for iter.HasNext() {
947-
cID := iter.Next()
948-
target.Remove(cID)
949-
}
945+
target.AndNot(foundSet)
950946
}
951947

952948
// ClearValues removes the values found in foundSet
@@ -956,13 +952,13 @@ func (b *BSI) ClearValues(foundSet *Bitmap) {
956952
wg.Add(1)
957953
go func() {
958954
defer wg.Done()
959-
ClearBits(foundSet, &b.eBM)
955+
b.eBM.AndNot(foundSet)
960956
}()
961957
for i := 0; i < b.BitCount(); i++ {
962958
wg.Add(1)
963959
go func(j int) {
964960
defer wg.Done()
965-
ClearBits(foundSet, &b.bA[j])
961+
b.bA[j].AndNot(foundSet)
966962
}(i)
967963
}
968964
wg.Wait()

roaring64/bsi64_test.go

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,27 @@ func setupRandom() (bsi *BSI, min, max int64) {
214214
return bsi, min, max
215215
}
216216

217+
func setupLargeBSI(t testing.TB) *BSI {
218+
t.Helper()
219+
220+
datEBM, err := os.ReadFile("./testdata/age/EBM")
221+
if err != nil {
222+
return nil
223+
}
224+
b := make([][]byte, 9)
225+
b[0] = datEBM
226+
for i := 1; i <= 8; i++ {
227+
b[i], err = os.ReadFile(fmt.Sprintf("./testdata/age/%d", i))
228+
if err != nil {
229+
return nil
230+
}
231+
}
232+
bsi := NewDefaultBSI()
233+
err = bsi.UnmarshalBinary(b)
234+
require.NoError(t, err)
235+
return bsi
236+
}
237+
217238
func TestTwosComplement(t *testing.T) {
218239
assert.Equal(t, "1001110", twosComplement(big.NewInt(-50), 7).Text(2))
219240
assert.Equal(t, "110010", twosComplement(big.NewInt(50), 7).Text(2))
@@ -408,59 +429,12 @@ func TestNewBSIRetainSet(t *testing.T) {
408429

409430
func TestLargeFile(t *testing.T) {
410431

411-
datEBM, err := ioutil.ReadFile("./testdata/age/EBM")
412-
if err != nil {
413-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
414-
return
415-
}
416-
dat1, err := ioutil.ReadFile("./testdata/age/1")
417-
if err != nil {
418-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
419-
return
420-
}
421-
dat2, err := ioutil.ReadFile("./testdata/age/2")
422-
if err != nil {
423-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
424-
return
425-
}
426-
dat3, err := ioutil.ReadFile("./testdata/age/3")
427-
if err != nil {
428-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
429-
return
430-
}
431-
dat4, err := ioutil.ReadFile("./testdata/age/4")
432-
if err != nil {
433-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
434-
return
435-
}
436-
dat5, err := ioutil.ReadFile("./testdata/age/5")
437-
if err != nil {
438-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
439-
return
440-
}
441-
dat6, err := ioutil.ReadFile("./testdata/age/6")
442-
if err != nil {
443-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
444-
return
445-
}
446-
dat7, err := ioutil.ReadFile("./testdata/age/7")
447-
if err != nil {
448-
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
449-
return
450-
}
451-
dat8, err := ioutil.ReadFile("./testdata/age/8")
452-
if err != nil {
432+
bsi := setupLargeBSI(t)
433+
if bsi == nil {
453434
fmt.Fprintf(os.Stderr, "\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
454435
return
455436
}
456437

457-
b := [][]byte{datEBM, dat1, dat2, dat3, dat4, dat5, dat6, dat7, dat8}
458-
459-
bsi := NewDefaultBSI()
460-
//bsi.RunOptimize()
461-
err = bsi.UnmarshalBinary(b)
462-
require.Nil(t, err)
463-
464438
resultA := bsi.CompareValue(0, EQ, 55, 0, nil)
465439
assert.Equal(t, uint64(574600), resultA.GetCardinality())
466440

@@ -822,3 +796,21 @@ func TestRangeNilBig(t *testing.T) {
822796
tmpAll := bsi.CompareBigValue(0, RANGE, bsi.MinMaxBig(0, MIN, nil), bsi.MinMaxBig(0, MAX, nil), nil)
823797
assert.Equal(t, tmpAll.GetCardinality(), setAll.GetCardinality())
824798
}
799+
800+
func BenchmarkClearValues(b *testing.B) {
801+
bsi := setupLargeBSI(b)
802+
if bsi == nil {
803+
b.Skip("\n\nIMPORTANT: For testing file IO, the roaring library requires disk access.\nWe omit some tests for now.\n\n")
804+
return
805+
}
806+
resultA := bsi.CompareValue(0, EQ, 55, 0, nil)
807+
808+
assert.Equal(b, uint64(574600), resultA.GetCardinality())
809+
b.ResetTimer()
810+
for i := 0; i < b.N; i++ {
811+
b.StopTimer()
812+
b2 := bsi.Clone()
813+
b.StartTimer()
814+
b2.ClearValues(resultA)
815+
}
816+
}

0 commit comments

Comments
 (0)