Files
doris/be/test/util/bitmap_test.cpp
Dayue Gao 3b24287251 Support 64 bits integers for BITMAP type (#2772)
Fixes #2771 

Main changes in this CL
* RoaringBitmap is renamed to BitmapValue and moved into bitmap_value.h
* leveraging Roaring64Map to support unsigned BIGINT for BITMAP type
* introduces two new format (SINGLE64 and BITMAP64) for BITMAP type

So far we have three storage format for BITMAP type

```
EMPTY := TypeCode(0x00)
SINGLE32 := TypeCode(0x01), UInt32LittleEndian
BITMAP32 := TypeCode(0x02), RoaringBitmap(defined by https://github.com/RoaringBitmap/RoaringFormatSpec/)
```

In order to support BIGINT element and keep backward compatibility, introduce two new format

```
SINGLE64 := TypeCode(0x03), UInt64LittleEndian
BITMAP64 := TypeCode(0x04), CustomRoaringBitmap64
```

Please note that SINGLE64/BITMAP64 doesn't replace SINGLE32/BITMAP32. Doris will choose the smaller (in terms of space) type automatically during serializing. For example, BITMAP32 is preferred over BITMAP64 when the maximum element is <= UINT32_MAX. This will also make BE rollback possible as long as user didn't write element larger than UINT32_MAX into bitmap column.

Another important design decision is that we fork and maintain our own version of Roaring64Map instead of using the one in "roaring/roaring64map.hh". The reasons are

1. RoaringBitmap doesn't define a standard for the binary format of 64-bits bitmap. As a result, different implementations of Roaring64Map use different format. For example the [C++ version](https://github.com/RoaringBitmap/CRoaring/blob/v0.2.60/cpp/roaring64map.hh#L545) is different from the [Java version](35104c564e/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java (L1097)). Even for CRoaring, the format may change in future releases. However Doris require the serialized format to be stable across versions. Fork is a safe way to achieve this.
2. We may want to make some code changes to Roaring64Map according to our needs. For example, in order to use the BITMAP32 format when the maximum element can be represented in 32 bits, we may want to access the private member of Roaring64Map. Another example is we want to further customize and optimize the format for BITMAP64 case, such as using vint64 instead of uint64 for map size.
2020-01-17 14:13:38 +08:00

141 lines
3.6 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "util/bitmap.h"
#include <gtest/gtest.h>
#include <iostream>
#include "common/logging.h"
namespace doris {
class BitMapTest : public testing::Test {
public:
BitMapTest() { }
virtual ~BitMapTest() {
}
};
TEST_F(BitMapTest, normal) {
// bitmap size
ASSERT_EQ(0, BitmapSize(0));
ASSERT_EQ(1, BitmapSize(1));
ASSERT_EQ(1, BitmapSize(8));
ASSERT_EQ(2, BitmapSize(9));
// set, test, clear
uint8_t bitmap[1024];
memset(bitmap, 0, 1024);
ASSERT_FALSE(BitmapTest(bitmap, 123));
BitmapSet(bitmap, 123);
ASSERT_TRUE(BitmapTest(bitmap, 123));
BitmapClear(bitmap, 123);
ASSERT_FALSE(BitmapTest(bitmap, 123));
BitmapChange(bitmap, 112, true);
ASSERT_TRUE(BitmapTest(bitmap, 112));
BitmapChange(bitmap, 112, false);
ASSERT_FALSE(BitmapTest(bitmap, 112));
// change bits
BitmapChangeBits(bitmap, 100, 200, true);
for (int i = 0; i < 200; i++) {
ASSERT_TRUE(BitmapTest(bitmap, 100 + i));
}
// Find fist
bool found = false;
size_t idx;
found = BitmapFindFirstSet(bitmap, 0, 1024 * 8, &idx);
ASSERT_TRUE(found);
ASSERT_EQ(100, idx);
found = BitmapFindFirstZero(bitmap, 200, 1024 * 8, &idx);
ASSERT_TRUE(found);
ASSERT_EQ(300, idx);
found = BitmapFindFirstSet(bitmap, 300, 1024 * 8, &idx);
ASSERT_FALSE(found);
found = BitmapFindFirstZero(bitmap, 300, 1024 * 8, &idx);
ASSERT_TRUE(found);
ASSERT_EQ(300, idx);
}
TEST_F(BitMapTest, iterator) {
uint8_t bitmap[1024];
memset(bitmap, 0, 1024);
for (int i = 100; i < 2000; ++i) {
BitmapSet(bitmap, i);
}
for (int i = 2100; i < 3000; ++i) {
BitmapSet(bitmap, i);
}
BitmapIterator iter(bitmap, 1024 * 8);
ASSERT_FALSE(iter.done());
bool value;
// 0,100 --- false
auto run = iter.Next(&value);
ASSERT_FALSE(value);
ASSERT_EQ(100, run);
// 100,2000 -- true
run = iter.Next(&value);
ASSERT_TRUE(value);
ASSERT_EQ(2000 - 100, run);
// 2000,2100 -- false
run = iter.Next(&value);
ASSERT_FALSE(value);
ASSERT_EQ(2100 - 2000, run);
// 2100,3000 -- true
run = iter.Next(&value);
ASSERT_TRUE(value);
ASSERT_EQ(3000 - 2100, run);
// 3000,8*1024 -- false
run = iter.Next(&value);
ASSERT_FALSE(value);
ASSERT_EQ(8*1024 - 3000, run);
ASSERT_TRUE(iter.done());
// seek to 8000
iter.SeekTo(8000);
run = iter.Next(&value);
ASSERT_FALSE(value);
ASSERT_EQ(8*1024 - 8000, run);
ASSERT_TRUE(iter.done());
// with max_run
iter.SeekTo(200);
run = iter.Next(&value, 500);
ASSERT_TRUE(value);
ASSERT_EQ(500, run);
run = iter.Next(&value);
ASSERT_TRUE(value);
ASSERT_EQ(2000 - 500 - 200, run);
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}