From 3dacbaa4552f8bf028e6bbe3227bb090f891788f Mon Sep 17 00:00:00 2001 From: Tian Jiang Date: Thu, 30 Jul 2026 16:48:18 +0800 Subject: [PATCH 1/2] add range test interface --- .../java/org/apache/tsfile/utils/BitMap.java | 29 ++++++++++++++ .../org/apache/tsfile/utils/BitMapImpl.java | 35 ++++++++++++++++ .../org/apache/tsfile/utils/BitMapTest.java | 40 +++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java index 629cda9c0..337bec90f 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java @@ -54,6 +54,35 @@ public boolean isMarked(int position) { return implementation.isMarked(position); } + /** + * Returns whether at least one bit in the specified range is marked. An empty range returns + * {@code false}. + * + * @throws IndexOutOfBoundsException if the range is outside this bitmap + */ + public boolean isRangeAnyMarked(int start, int length) { + return implementation.isRangeAnyMarked(start, length); + } + + /** + * Returns whether every bit in the specified range is marked. An empty range returns {@code + * true}. + * + * @throws IndexOutOfBoundsException if the range is outside this bitmap + */ + public boolean isRangeAllMarked(int start, int length) { + return implementation.isRangeAllMarked(start, length); + } + + /** + * Returns whether no bit in the specified range is marked. An empty range returns {@code true}. + * + * @throws IndexOutOfBoundsException if the range is outside this bitmap + */ + public boolean isRangeNoneMarked(int start, int length) { + return implementation.isRangeNoneMarked(start, length); + } + /** mark as 1 at all positions. */ public void markAll() { implementation.markAll(); diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java index d9f296fe2..801e67cc8 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java @@ -19,6 +19,8 @@ package org.apache.tsfile.utils; +import org.apache.tsfile.i18n.Messages; + abstract class BitMapImpl { protected int size; @@ -39,6 +41,32 @@ int getSize() { abstract boolean isMarked(int position); + boolean isRangeAnyMarked(int start, int length) { + checkRange(start, length); + for (int offset = 0; offset < length; offset += Long.SIZE) { + int batchSize = Math.min(length - offset, Long.SIZE); + if (extractBits(start + offset, batchSize) != 0L) { + return true; + } + } + return false; + } + + boolean isRangeAllMarked(int start, int length) { + checkRange(start, length); + for (int offset = 0; offset < length; offset += Long.SIZE) { + int batchSize = Math.min(length - offset, Long.SIZE); + if (extractBits(start + offset, batchSize) != BitMapLongImpl.lowerBitsMask(batchSize)) { + return false; + } + } + return true; + } + + boolean isRangeNoneMarked(int start, int length) { + return !isRangeAnyMarked(start, length); + } + abstract void markAll(); abstract void mark(int position); @@ -102,4 +130,11 @@ int contentHashCode() { abstract BitMapImpl extend(int newSize); abstract long getRetainedSizeInBytes(); + + private void checkRange(int start, int length) { + if (start < 0 || length < 0 || start > size - length) { + throw new IndexOutOfBoundsException( + Messages.format("error.common.bitmap_start_length_out_of_range", start, length, size)); + } + } } diff --git a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java index e4b59e452..ef73614ad 100644 --- a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java +++ b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; public class BitMapTest { @@ -217,6 +218,45 @@ public void testIsAllUnmarkedInRange() { assertFalse(bitMap.isAllUnmarked(10)); } + @Test + public void testRangeMarkedQueries() { + assertRangeMarkedQueries(new BitMap(0)); + assertRangeMarkedQueries(new BitMap(64)); + assertRangeMarkedQueries(BitMap.createBitMapDynamically(64)); + assertRangeMarkedQueries(new BitMap(100)); + } + + private void assertRangeMarkedQueries(BitMap bitMap) { + for (int i = 0; i < bitMap.getSize(); i++) { + if (i % 4 != 2) { + bitMap.mark(i); + } + } + + for (int start = 0; start <= bitMap.getSize(); start++) { + for (int length = 0; length <= bitMap.getSize() - start; length++) { + boolean anyMarked = false; + boolean allMarked = true; + for (int i = start; i < start + length; i++) { + anyMarked |= bitMap.isMarked(i); + allMarked &= bitMap.isMarked(i); + } + assertEquals(anyMarked, bitMap.isRangeAnyMarked(start, length)); + assertEquals(allMarked, bitMap.isRangeAllMarked(start, length)); + assertEquals(!anyMarked, bitMap.isRangeNoneMarked(start, length)); + } + } + + assertThrows(IndexOutOfBoundsException.class, () -> bitMap.isRangeAnyMarked(-1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> bitMap.isRangeAllMarked(0, -1)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeNoneMarked(bitMap.getSize() + 1, 0)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeAnyMarked(bitMap.getSize(), 1)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeAllMarked(1, Integer.MAX_VALUE)); + } + @Test public void testGetTruncatedByteArray() { BitMap bitMap = new BitMap(16); From 031deadfa8ee293386e10db80690dcba5746f030 Mon Sep 17 00:00:00 2001 From: Tian Jiang Date: Thu, 30 Jul 2026 18:20:05 +0800 Subject: [PATCH 2/2] push-down implementation --- .../apache/tsfile/utils/BitMapArrayImpl.java | 72 +++++- .../org/apache/tsfile/utils/BitMapImpl.java | 28 +-- .../apache/tsfile/utils/BitMapLongImpl.java | 33 ++- .../tsfile/utils/BitMapPerformanceTest.java | 217 ++++++++++++++++++ .../org/apache/tsfile/utils/BitMapTest.java | 9 + 5 files changed, 318 insertions(+), 41 deletions(-) diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMapArrayImpl.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMapArrayImpl.java index 9e8a40910..2a8a4d3f1 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMapArrayImpl.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMapArrayImpl.java @@ -19,8 +19,6 @@ package org.apache.tsfile.utils; -import org.apache.tsfile.i18n.Messages; - import java.util.Arrays; class BitMapArrayImpl extends BitMapImpl { @@ -76,6 +74,47 @@ boolean isMarked(int position) { return (bits[position / Byte.SIZE] & BIT_UTIL[position % Byte.SIZE]) != 0; } + @Override + boolean isRangeAnyMarked(int start, int length) { + checkRange(start, length); + return isRangeAnyMarkedUnchecked(start, length); + } + + @Override + boolean isRangeAllMarked(int start, int length) { + checkRange(start, length); + if (length == 0) { + return true; + } + + int end = start + length; + int firstByte = start >>> 3; + int lastByte = (end - 1) >>> 3; + if (firstByte == lastByte) { + int mask = ((1 << length) - 1) << (start & 7); + return (bits[firstByte] & mask) == mask; + } + + int firstMask = (0xFF << (start & 7)) & 0xFF; + if ((bits[firstByte] & firstMask) != firstMask) { + return false; + } + for (int index = firstByte + 1; index < lastByte; index++) { + if (bits[index] != (byte) 0xFF) { + return false; + } + } + int lastBitCount = end & 7; + int lastMask = lastBitCount == 0 ? 0xFF : (1 << lastBitCount) - 1; + return (bits[lastByte] & lastMask) == lastMask; + } + + @Override + boolean isRangeNoneMarked(int start, int length) { + checkRange(start, length); + return !isRangeAnyMarkedUnchecked(start, length); + } + @Override void markAll() { Arrays.fill(bits, (byte) 0XFF); @@ -288,11 +327,30 @@ long getRetainedSizeInBytes() { return INSTANCE_SIZE + RamUsageEstimator.sizeOfByteArray(bits.length); } - private void checkRange(int startPosition, int length) { - if (startPosition < 0 || startPosition + length > size) { - throw new IndexOutOfBoundsException( - Messages.format( - "error.common.bitmap_start_length_out_of_range", startPosition, length, size)); + private boolean isRangeAnyMarkedUnchecked(int start, int length) { + if (length == 0) { + return false; + } + + int end = start + length; + int firstByte = start >>> 3; + int lastByte = (end - 1) >>> 3; + if (firstByte == lastByte) { + int mask = ((1 << length) - 1) << (start & 7); + return (bits[firstByte] & mask) != 0; + } + + int firstMask = (0xFF << (start & 7)) & 0xFF; + if ((bits[firstByte] & firstMask) != 0) { + return true; + } + for (int index = firstByte + 1; index < lastByte; index++) { + if (bits[index] != 0) { + return true; + } } + int lastBitCount = end & 7; + int lastMask = lastBitCount == 0 ? 0xFF : (1 << lastBitCount) - 1; + return (bits[lastByte] & lastMask) != 0; } } diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java index 801e67cc8..a798af56a 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java @@ -41,31 +41,11 @@ int getSize() { abstract boolean isMarked(int position); - boolean isRangeAnyMarked(int start, int length) { - checkRange(start, length); - for (int offset = 0; offset < length; offset += Long.SIZE) { - int batchSize = Math.min(length - offset, Long.SIZE); - if (extractBits(start + offset, batchSize) != 0L) { - return true; - } - } - return false; - } + abstract boolean isRangeAnyMarked(int start, int length); - boolean isRangeAllMarked(int start, int length) { - checkRange(start, length); - for (int offset = 0; offset < length; offset += Long.SIZE) { - int batchSize = Math.min(length - offset, Long.SIZE); - if (extractBits(start + offset, batchSize) != BitMapLongImpl.lowerBitsMask(batchSize)) { - return false; - } - } - return true; - } + abstract boolean isRangeAllMarked(int start, int length); - boolean isRangeNoneMarked(int start, int length) { - return !isRangeAnyMarked(start, length); - } + abstract boolean isRangeNoneMarked(int start, int length); abstract void markAll(); @@ -131,7 +111,7 @@ int contentHashCode() { abstract long getRetainedSizeInBytes(); - private void checkRange(int start, int length) { + final void checkRange(int start, int length) { if (start < 0 || length < 0 || start > size - length) { throw new IndexOutOfBoundsException( Messages.format("error.common.bitmap_start_length_out_of_range", start, length, size)); diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMapLongImpl.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMapLongImpl.java index 452c7f096..633a6ea97 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMapLongImpl.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMapLongImpl.java @@ -19,8 +19,6 @@ package org.apache.tsfile.utils; -import org.apache.tsfile.i18n.Messages; - class BitMapLongImpl extends BitMapImpl { private static final long ALL_BITS_MARKED = -1L; @@ -79,6 +77,25 @@ boolean isMarked(int position) { return (bits & (1L << position)) != 0; } + @Override + boolean isRangeAnyMarked(int start, int length) { + checkRange(start, length); + return (bits & rangeMask(start, length)) != 0L; + } + + @Override + boolean isRangeAllMarked(int start, int length) { + checkRange(start, length); + long mask = rangeMask(start, length); + return (bits & mask) == mask; + } + + @Override + boolean isRangeNoneMarked(int start, int length) { + checkRange(start, length); + return (bits & rangeMask(start, length)) == 0L; + } + @Override void markAll() { bits = ALL_BITS_MARKED; @@ -219,6 +236,10 @@ static long lowerBitsMask(int length) { return length == Long.SIZE ? -1L : (1L << length) - 1; } + private static long rangeMask(int start, int length) { + return lowerBitsMask(length) << start; + } + private byte[] getExtendedByteArray(int newSize) { byte[] bytes = new byte[BitMap.getSizeOfBytes(newSize)]; for (int i = 0; i < Long.BYTES; i++) { @@ -227,12 +248,4 @@ private byte[] getExtendedByteArray(int newSize) { bytes[Long.BYTES] = paddingByte; return bytes; } - - private void checkRange(int startPosition, int length) { - if (startPosition < 0 || startPosition + length > size) { - throw new IndexOutOfBoundsException( - Messages.format( - "error.common.bitmap_start_length_out_of_range", startPosition, length, size)); - } - } } diff --git a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapPerformanceTest.java b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapPerformanceTest.java index 7f3d239c0..faaa41d06 100644 --- a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapPerformanceTest.java +++ b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapPerformanceTest.java @@ -22,6 +22,7 @@ import org.junit.Assume; import org.junit.Test; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -35,6 +36,8 @@ public class BitMapPerformanceTest { private static final int WARMUP_ROUNDS = 3; private static final int MEASUREMENT_ROUNDS = 7; private static final int CHEAP_OPERATION_COUNT = 2_000_000; + private static final int RANGE_OPERATION_COUNT = 10_000_000; + private static final int RANGE_BITMAP_COUNT = 64; private static final int ALLOCATION_OPERATION_COUNT = 200_000; private static final int COMPOSITE_OPERATION_COUNT = 50_000; private static final int BULK_INSTANCE_COUNT = 1_000_000; @@ -145,6 +148,103 @@ public void testLength64Implementations() { printMemoryUsage(); } + @Test + public void testRangeMarkedQueryImplementations() { + Assume.assumeTrue( + "Set -Dtsfile.runPerformanceTests=true to run the performance test", + Boolean.getBoolean(RUN_PERFORMANCE_TEST_PROPERTY)); + + java.lang.management.ThreadMXBean baseThreadBean = ManagementFactory.getThreadMXBean(); + if (!(baseThreadBean instanceof com.sun.management.ThreadMXBean threadBean)) { + Assume.assumeTrue("Current-thread allocation metrics are unavailable", false); + return; + } + Assume.assumeTrue( + "Current-thread CPU time is unavailable", threadBean.isCurrentThreadCpuTimeSupported()); + Assume.assumeTrue( + "Current-thread allocation metrics are unavailable", + threadBean.isThreadAllocatedMemorySupported()); + if (!threadBean.isThreadCpuTimeEnabled()) { + threadBean.setThreadCpuTimeEnabled(true); + } + if (!threadBean.isThreadAllocatedMemoryEnabled()) { + threadBean.setThreadAllocatedMemoryEnabled(true); + } + + List results = new ArrayList<>(); + results.add( + benchmarkRangeAnyMarked( + "array-backed prefix", createRangeBitMaps(false, 128, 0, 64), 0, 64, threadBean)); + results.add( + benchmarkRangeAnyMarked( + "array-backed partial", createRangeBitMaps(false, 128, 1, 63), 1, 63, threadBean)); + results.add( + benchmarkRangeAnyMarked( + "array-backed next block", createRangeBitMaps(false, 128, 64, 64), 64, 64, threadBean)); + results.add( + benchmarkRangeAnyMarked( + "long-backed prefix", createRangeBitMaps(true, 64, 0, 64), 0, 64, threadBean)); + results.add( + benchmarkRangeAnyMarked( + "long-backed partial", createRangeBitMaps(true, 64, 1, 63), 1, 63, threadBean)); + + printRangeResults(results); + } + + private static RangeBenchmarkResult benchmarkRangeAnyMarked( + String name, + BitMap[] bitMaps, + int start, + int length, + com.sun.management.ThreadMXBean threadBean) { + Workload currentHelper = currentIoTDBRangeAnyMarkedWorkload(bitMaps, start, length); + Workload newApi = rangeAnyMarkedWorkload(bitMaps, start, length); + for (int round = 0; round < WARMUP_ROUNDS; round++) { + runMeasured(currentHelper, RANGE_OPERATION_COUNT, threadBean); + runMeasured(newApi, RANGE_OPERATION_COUNT, threadBean); + } + + long[] currentCpuNanos = new long[MEASUREMENT_ROUNDS]; + long[] currentAllocatedBytes = new long[MEASUREMENT_ROUNDS]; + long[] apiCpuNanos = new long[MEASUREMENT_ROUNDS]; + long[] apiAllocatedBytes = new long[MEASUREMENT_ROUNDS]; + for (int round = 0; round < MEASUREMENT_ROUNDS; round++) { + MeasuredRun currentRun; + MeasuredRun apiRun; + if ((round & 1) == 0) { + currentRun = runMeasured(currentHelper, RANGE_OPERATION_COUNT, threadBean); + apiRun = runMeasured(newApi, RANGE_OPERATION_COUNT, threadBean); + } else { + apiRun = runMeasured(newApi, RANGE_OPERATION_COUNT, threadBean); + currentRun = runMeasured(currentHelper, RANGE_OPERATION_COUNT, threadBean); + } + assertEquals(currentRun.checksum, apiRun.checksum); + currentCpuNanos[round] = currentRun.cpuNanos; + currentAllocatedBytes[round] = currentRun.allocatedBytes; + apiCpuNanos[round] = apiRun.cpuNanos; + apiAllocatedBytes[round] = apiRun.allocatedBytes; + } + + return new RangeBenchmarkResult( + name, + median(currentCpuNanos) / (double) RANGE_OPERATION_COUNT, + median(currentAllocatedBytes) / (double) RANGE_OPERATION_COUNT, + median(apiCpuNanos) / (double) RANGE_OPERATION_COUNT, + median(apiAllocatedBytes) / (double) RANGE_OPERATION_COUNT); + } + + private static MeasuredRun runMeasured( + Workload workload, int operationCount, com.sun.management.ThreadMXBean threadBean) { + long threadId = Thread.currentThread().getId(); + long allocatedBytesBefore = threadBean.getThreadAllocatedBytes(threadId); + long cpuNanosBefore = threadBean.getCurrentThreadCpuTime(); + long checksum = workload.run(operationCount); + long cpuNanos = threadBean.getCurrentThreadCpuTime() - cpuNanosBefore; + long allocatedBytes = threadBean.getThreadAllocatedBytes(threadId) - allocatedBytesBefore; + blackHole = checksum; + return new MeasuredRun(cpuNanos, allocatedBytes, checksum); + } + private static BenchmarkResult benchmark( String name, int operationCount, Workload arrayWorkload, Workload longWorkload) { for (int round = 0; round < WARMUP_ROUNDS; round++) { @@ -437,6 +537,72 @@ private static Workload toStringWorkload(BitMap bitMap) { }; } + private static Workload currentIoTDBRangeAnyMarkedWorkload( + BitMap[] bitMaps, int start, int length) { + return operationCount -> { + long checksum = 0; + for (int i = 0; i < operationCount; i++) { + checksum += currentIoTDBRangeAnyMarked(bitMaps[i & 63], start, length) ? 1 : 0; + } + return checksum; + }; + } + + private static Workload rangeAnyMarkedWorkload(BitMap[] bitMaps, int start, int length) { + return operationCount -> { + long checksum = 0; + for (int i = 0; i < operationCount; i++) { + checksum += bitMaps[i & 63].isRangeAnyMarked(start, length) ? 1 : 0; + } + return checksum; + }; + } + + private static boolean currentIoTDBRangeAnyMarked(BitMap bitMap, int start, int length) { + // Mirror IoTDB's prefix shortcut and its byte scan for ranges with a non-zero offset. + if (start == 0) { + return !bitMap.isAllUnmarked(length); + } + + byte[] bytes = bitMap.getByteArray(); + int end = start + length; + int firstByte = start >>> 3; + int lastByte = (end - 1) >>> 3; + if (firstByte == lastByte) { + int mask = ((1 << length) - 1) << (start & 7); + return (bytes[firstByte] & mask) != 0; + } + + int firstMask = (0xFF << (start & 7)) & 0xFF; + if ((bytes[firstByte] & firstMask) != 0) { + return true; + } + for (int index = firstByte + 1; index < lastByte; index++) { + if (bytes[index] != 0) { + return true; + } + } + int lastBitCount = end & 7; + int lastMask = lastBitCount == 0 ? 0xFF : (1 << lastBitCount) - 1; + return (bytes[lastByte] & lastMask) != 0; + } + + private static BitMap[] createRangeBitMaps(boolean longBacked, int size, int start, int length) { + BitMap[] bitMaps = new BitMap[RANGE_BITMAP_COUNT]; + for (int index = 0; index < bitMaps.length; index++) { + bitMaps[index] = + new BitMap(longBacked ? new BitMapLongImpl(size) : new BitMapArrayImpl(size)); + if ((index & 1) == 0) { + bitMaps[index].mark(start + index % length); + } else if (start > 0) { + bitMaps[index].mark(start - 1); + } else if (start + length < size) { + bitMaps[index].mark(start + length); + } + } + return bitMaps; + } + private static BitMap arrayBitMap() { return new BitMap(new BitMapArrayImpl(BIT_MAP_SIZE)); } @@ -495,6 +661,22 @@ private static void printMemoryUsage() { "Reduction: %.2f%% per object%n", (arrayBytes - longBytes) * 100.0 / arrayBytes); } + private static void printRangeResults(List results) { + System.out.println("isRangeAnyMarked performance (current-thread median CPU/allocation)"); + System.out.printf( + "%-28s %14s %12s %14s %12s%n", + "representation / range", "current ns/op", "current B/op", "new API ns/op", "new API B/op"); + for (RangeBenchmarkResult result : results) { + System.out.printf( + "%-28s %14.3f %12.3f %14.3f %12.3f%n", + result.name, + result.currentCpuNanosPerOperation, + result.currentAllocatedBytesPerOperation, + result.apiCpuNanosPerOperation, + result.apiAllocatedBytesPerOperation); + } + } + @FunctionalInterface private interface Workload { long run(int operationCount); @@ -521,6 +703,19 @@ private TimedRun(long elapsedNanos, long checksum) { } } + private static class MeasuredRun { + + private final long cpuNanos; + private final long allocatedBytes; + private final long checksum; + + private MeasuredRun(long cpuNanos, long allocatedBytes, long checksum) { + this.cpuNanos = cpuNanos; + this.allocatedBytes = allocatedBytes; + this.checksum = checksum; + } + } + private static class BenchmarkResult { private final String name; @@ -534,4 +729,26 @@ private BenchmarkResult( this.longNanosPerOperation = longNanosPerOperation; } } + + private static class RangeBenchmarkResult { + + private final String name; + private final double currentCpuNanosPerOperation; + private final double currentAllocatedBytesPerOperation; + private final double apiCpuNanosPerOperation; + private final double apiAllocatedBytesPerOperation; + + private RangeBenchmarkResult( + String name, + double currentCpuNanosPerOperation, + double currentAllocatedBytesPerOperation, + double apiCpuNanosPerOperation, + double apiAllocatedBytesPerOperation) { + this.name = name; + this.currentCpuNanosPerOperation = currentCpuNanosPerOperation; + this.currentAllocatedBytesPerOperation = currentAllocatedBytesPerOperation; + this.apiCpuNanosPerOperation = apiCpuNanosPerOperation; + this.apiAllocatedBytesPerOperation = apiAllocatedBytesPerOperation; + } + } } diff --git a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java index ef73614ad..d92684555 100644 --- a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java +++ b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java @@ -224,6 +224,15 @@ public void testRangeMarkedQueries() { assertRangeMarkedQueries(new BitMap(64)); assertRangeMarkedQueries(BitMap.createBitMapDynamically(64)); assertRangeMarkedQueries(new BitMap(100)); + + BitMap fullLongRange = BitMap.createBitMapDynamically(Long.SIZE); + fullLongRange.markAll(); + assertTrue(fullLongRange.isRangeAllMarked(0, Long.SIZE)); + + BitMap crossingArrayRange = new BitMap(128); + crossingArrayRange.markRange(32, Long.SIZE); + assertTrue(crossingArrayRange.isRangeAllMarked(32, Long.SIZE)); + assertFalse(crossingArrayRange.isRangeAllMarked(31, Long.SIZE)); } private void assertRangeMarkedQueries(BitMap bitMap) {