This is an automated email from the ASF dual-hosted git repository.
aokolnychyi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new 1e5dcb1f6b Core: Support merging in PositionDeleteIndex (#11208)
1e5dcb1f6b is described below
commit 1e5dcb1f6b01128032a704258e1730c9936c9a07
Author: Anton Okolnychyi <[email protected]>
AuthorDate: Wed Sep 25 16:22:42 2024 -0700
Core: Support merging in PositionDeleteIndex (#11208)
---
.../iceberg/deletes/BitmapPositionDeleteIndex.java | 9 +++++
.../iceberg/deletes/PositionDeleteIndex.java | 9 +++++
.../iceberg/deletes/PositionDeleteIndexUtil.java | 14 +-------
.../deletes/TestBitmapPositionDeleteIndex.java | 41 ++++++++++++++++++++++
4 files changed, 60 insertions(+), 13 deletions(-)
diff --git
a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java
b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java
index 7503d0d83f..3a04487856 100644
---
a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java
+++
b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java
@@ -42,6 +42,15 @@ class BitmapPositionDeleteIndex implements
PositionDeleteIndex {
roaring64Bitmap.addRange(posStart, posEnd);
}
+ @Override
+ public void merge(PositionDeleteIndex that) {
+ if (that instanceof BitmapPositionDeleteIndex) {
+ merge((BitmapPositionDeleteIndex) that);
+ } else {
+ that.forEach(this::delete);
+ }
+ }
+
@Override
public boolean isDeleted(long position) {
return roaring64Bitmap.contains(position);
diff --git
a/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndex.java
b/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndex.java
index 27c15749ad..c0086fe6aa 100644
--- a/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndex.java
+++ b/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndex.java
@@ -36,6 +36,15 @@ public interface PositionDeleteIndex {
*/
void delete(long posStart, long posEnd);
+ /**
+ * Adds positions from the other index, modifying this index in place.
+ *
+ * @param that the other index to merge
+ */
+ default void merge(PositionDeleteIndex that) {
+ that.forEach(this::delete);
+ }
+
/**
* Checks whether a row at the position is deleted.
*
diff --git
a/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndexUtil.java
b/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndexUtil.java
index 0c3bff28ee..7601232ad2 100644
--- a/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndexUtil.java
+++ b/core/src/main/java/org/apache/iceberg/deletes/PositionDeleteIndexUtil.java
@@ -18,25 +18,13 @@
*/
package org.apache.iceberg.deletes;
-import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
-
public class PositionDeleteIndexUtil {
private PositionDeleteIndexUtil() {}
public static PositionDeleteIndex merge(Iterable<? extends
PositionDeleteIndex> indexes) {
BitmapPositionDeleteIndex result = new BitmapPositionDeleteIndex();
-
- for (PositionDeleteIndex index : indexes) {
- if (index.isNotEmpty()) {
- Preconditions.checkArgument(
- index instanceof BitmapPositionDeleteIndex,
- "Can merge only bitmap-based indexes, got %s",
- index.getClass().getName());
- result.merge((BitmapPositionDeleteIndex) index);
- }
- }
-
+ indexes.forEach(result::merge);
return result;
}
}
diff --git
a/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java
b/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java
index 279c5b8d16..c8fc723deb 100644
---
a/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java
+++
b/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java
@@ -64,6 +64,47 @@ public class TestBitmapPositionDeleteIndex {
assertThat(positions).isEmpty();
}
+ @Test
+ public void testMergeBitmapIndexWithNonEmpty() {
+ long pos1 = 10L; // Container 0 (high bits = 0)
+ long pos2 = 1L << 33; // Container 1 (high bits = 1)
+ long pos3 = pos2 + 1; // Container 1 (high bits = 1)
+ long pos4 = 2L << 33; // Container 2 (high bits = 2)
+
+ BitmapPositionDeleteIndex index1 = new BitmapPositionDeleteIndex();
+ index1.delete(pos2);
+ index1.delete(pos1);
+
+ BitmapPositionDeleteIndex index2 = new BitmapPositionDeleteIndex();
+ index2.delete(pos4);
+ index2.delete(pos3);
+
+ index1.merge(index2);
+
+ // output must be sorted in ascending order across containers
+ List<Long> positions = collect(index1);
+ assertThat(positions).containsExactly(pos1, pos2, pos3, pos4);
+ }
+
+ @Test
+ public void testMergeBitmapIndexWithEmpty() {
+ long pos1 = 10L; // Container 0 (high bits = 0)
+ long pos2 = 1L << 33; // Container 1 (high bits = 1)
+ long pos3 = pos2 + 1; // Container 1 (high bits = 1)
+ long pos4 = 2L << 33; // Container 2 (high bits = 2)
+
+ BitmapPositionDeleteIndex index = new BitmapPositionDeleteIndex();
+ index.delete(pos2);
+ index.delete(pos1);
+ index.delete(pos3);
+ index.delete(pos4);
+ index.merge(PositionDeleteIndex.empty());
+
+ // output must be sorted in ascending order across containers
+ List<Long> positions = collect(index);
+ assertThat(positions).containsExactly(pos1, pos2, pos3, pos4);
+ }
+
private List<Long> collect(PositionDeleteIndex index) {
List<Long> positions = Lists.newArrayList();
index.forEach(positions::add);