UnmarshalBinary has containers with needCopyOnWrite set to true
davidwartell opened this issue · comments
David Wartell commented
The below code produces a failure on assert.Equal(t, bitmap, bitmapUnmarshalled) with the following differences:
Diff:
--- Expected
+++ Actual
@@ -2067,4 +2067,4 @@
needCopyOnWrite: ([]bool) (len=2) {
- (bool) false,
- (bool) false
+ (bool) true,
+ (bool) true
},
func TestRoaringBitmapMarshalCowBug(t *testing.T) {
id := uint64(100000)
bitmap := roaring.NewBitmap()
for i := uint64(0); i < id; i++ {
if i%2 == 0 {
bitmap.Add(uint32(i))
}
}
bitmapBytes, err := bitmap.MarshalBinary()
require.Nil(t, err)
bitmapUnmarshalled := roaring.NewBitmap()
err = bitmapUnmarshalled.UnmarshalBinary(bitmapBytes)
require.Nil(t, err)
assert.Equal(t, bitmap, bitmapUnmarshalled)
assert.True(t, bitmap.Equals(bitmapUnmarshalled))
}
I also noticed a workaround is to Clone() the bitmap after UnmarshalBinary. This seems to clear the true values in needCopyOnWrite []bool
github.com/RoaringBitmap/roaring v1.3.0
go version go1.20.5 darwin/arm64
func TestRoaringBitmapMarshalCowBug(t *testing.T) {
id := uint64(100000)
bitmap := roaring.NewBitmap()
for i := uint64(0); i < id; i++ {
if i%2 == 0 {
bitmap.Add(uint32(i))
}
}
bitmapBytes, err := bitmap.MarshalBinary()
require.Nil(t, err)
bitmapUnmarshalled := roaring.NewBitmap()
err = bitmapUnmarshalled.UnmarshalBinary(bitmapBytes)
require.Nil(t, err)
// Clone() clears the COW values
bitmapUnmarshalled = bitmapUnmarshalled.Clone()
assert.Equal(t, bitmap, bitmapUnmarshalled)
assert.True(t, bitmap.Equals(bitmapUnmarshalled))
}
=== RUN TestRoaringBitmapMarshalCowBug
--- PASS: TestRoaringBitmapMarshalCowBug (0.00s)
PASS
Daniel Lemire commented
@davidwartell Please have a look at #397