Skip to content

Validate: unexpected error and questions #469

@svetlana54yo

Description

@svetlana54yo

While using roaring/v2 in my project, I encountered unexpected error interval had zero length from .Validate() at the end of operations similar to those in TestValidate. Please note that bmap is not empty while calling .Validate().

Version: v2.4.3

import (
	"testing"

	"github.com/RoaringBitmap/roaring/v2"
	"github.com/stretchr/testify/require"
)

func TestValidate(t *testing.T) {
	b := roaring.New()
	b.RemoveRange(0, 180)
	b.AddRange(0, 180)
	b.RemoveRange(180, 217)
	b.AddRange(180, 217)
	b.RemoveRange(217, 2394)
	b.RemoveRange(2394, 2427)
	b.AddRange(2394, 2427)
	b.RemoveRange(2427, 2428)
	b.AddRange(2427, 2428)
	b.RemoveRange(2428, 3345)
	b.RemoveRange(3345, 3346)
	b.RemoveRange(3346, 3597)
	b.RemoveRange(3597, 3815)
	b.RemoveRange(3815, 3816)
	b.AddRange(3815, 3816)
	b.RemoveRange(3816, 3856)
	b.RemoveRange(3856, 4067)
	b.RemoveRange(4067, 4069)
	b.RemoveRange(4069, 4071)
	b.RemoveRange(4071, 4095)
	b.RemoveRange(4095, 4096)
	b.RunOptimize()
	require.False(t, b.IsEmpty())
	require.NoError(t, b.Validate())
}

Question: by the way, I’ve discovered that an empty bitmap doesn’t pass validation. Is that intentional? For example, in my project, bitmaps can be empty, and that’s a valid state. However, if I want to perform validation, I have to handle these two cases separately

func TestValidateEmpty(t *testing.T) {
	require.NoError(t, roaring.New().Validate())
}

Question: in my project, I store bitmaps in storage in binary format using .MarshalBinary. I started storing data when the bitmap version was v1 (from the package github.com/RoaringBitmap/roaring). Before saving a v1 bitmap to storage, I also called v1.RunOptimize().

Now, since the v2 binary format is backward-compatible with v1, when reading data from storage, I simply use v2.UnmarshalBinary(..v1 bytes...). Additionally, from time to time, I call v2.Validate() afterward to ensure everything is correct.

However, I’ve discovered that even though v1.RunOptimize() was applied before serialization, v2.Validate() can still fail (see the example below). To prevent this, I have to explicitly call v2.RunOptimize() after deserialization before running v2.Validate().

Is this behavior intentional?

v1 version: v1.9.4.
v2 version: v2.4.3.

import (
	"testing"

	v1 "github.com/RoaringBitmap/roaring"
	v2 "github.com/RoaringBitmap/roaring/v2"
	"github.com/stretchr/testify/require"
)

func TestValidateFromV1(t *testing.T) {
	v1 := v1.NewBitmap()
	for i := 0; i <= 2; i++ {
		v1.Add(uint32(i))
	}
	v1.RunOptimize()
	b, err := v1.MarshalBinary()
	require.NoError(t, err)
	v2 := v2.New()
	require.NoError(t, v2.UnmarshalBinary(b))
	// v2.RunOptimize() <- if uncomment this line, .Validate will pass
	require.NoError(t, v2.Validate())
}

Question: which are gurantees for .Validate if i from origin use v2 bitmap, but don't do any .RunOptimize(). Could it fail ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions