This is an automated email from the ASF dual-hosted git repository.
mgreber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push:
new 8c066270f Add equals() and hashCode() methods to PartialRow and
PartitionSchema
8c066270f is described below
commit 8c066270f9a4a80b29882dbc2cc2bdec756d24e5
Author: Gabriella Lotz <[email protected]>
AuthorDate: Wed Sep 3 16:06:38 2025 +0200
Add equals() and hashCode() methods to PartialRow and PartitionSchema
Implement proper object equality and hash code generation for
PartialRow, HashBucketSchema, and RangeWithHashSchema classes to
enable correct behavior in collections and comparisons.
Change-Id: Iea7d547397c37506c7d0baf4f66aa6b34a99f10e
Reviewed-on: http://gerrit.cloudera.org:8080/23424
Reviewed-by: Marton Greber <[email protected]>
Tested-by: Marton Greber <[email protected]>
Reviewed-by: Zoltan Martonka <[email protected]>
---
.../java/org/apache/kudu/client/PartialRow.java | 42 +++++++++
.../org/apache/kudu/client/PartitionSchema.java | 40 ++++++++
.../org/apache/kudu/client/TestPartialRow.java | 69 ++++++++++++++
.../kudu/client/TestPartitionSchemaClasses.java | 104 +++++++++++++++++++++
4 files changed, 255 insertions(+)
diff --git
a/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java
b/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java
index e41e7033a..bade6df50 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java
@@ -27,6 +27,7 @@ import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import java.util.ListIterator;
+import java.util.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
@@ -1926,4 +1927,45 @@ public class PartialRow {
}
return size;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PartialRow)) {
+ return false;
+ }
+ PartialRow that = (PartialRow) o;
+
+ return Objects.equals(schema, that.schema) &&
+ Objects.equals(columnsBitSet, that.columnsBitSet) &&
+ Objects.equals(nullsBitSet, that.nullsBitSet) &&
+ varLengthData.equals(that.varLengthData) &&
+ Arrays.equals(rowAlloc, that.rowAlloc);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(schema, columnsBitSet, nullsBitSet);
+
+ // Hash values for each set column using getObject()
+ for (int i = 0; i < schema.getColumnCount(); i++) {
+ if (!columnsBitSet.get(i)) {
+ continue;
+ }
+
+ Object value = getObject(i);
+ // Special handling for byte arrays, which don't hash content by default
+ if (value instanceof byte[]) {
+ result = 31 * result + Arrays.hashCode((byte[]) value);
+ } else {
+ result = 31 * result + Objects.hashCode(value);
+ }
+ }
+
+ return result;
+ }
+
+
}
diff --git
a/java/kudu-client/src/main/java/org/apache/kudu/client/PartitionSchema.java
b/java/kudu-client/src/main/java/org/apache/kudu/client/PartitionSchema.java
index 50851a4ae..866519181 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/PartitionSchema.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/PartitionSchema.java
@@ -21,6 +21,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
import java.util.TreeSet;
import com.google.common.base.Preconditions;
@@ -285,6 +286,25 @@ public class PartitionSchema {
public int getSeed() {
return seed;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof HashBucketSchema)) {
+ return false;
+ }
+ HashBucketSchema that = (HashBucketSchema) o;
+ return numBuckets == that.numBuckets &&
+ seed == that.seed &&
+ Objects.equals(columnIds, that.columnIds);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(columnIds, numBuckets, seed);
+ }
}
/**
@@ -308,5 +328,25 @@ public class PartitionSchema {
this.upperBound = upperBound;
this.hashSchemas = hashSchemas;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RangeWithHashSchema)) {
+ return false;
+ }
+ RangeWithHashSchema that = (RangeWithHashSchema) o;
+
+ return Objects.equals(lowerBound, that.lowerBound) &&
+ Objects.equals(upperBound, that.upperBound) &&
+ Objects.equals(hashSchemas, that.hashSchemas);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(lowerBound, upperBound, hashSchemas);
+ }
}
}
diff --git
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java
index d64503b6e..e2e01978e 100644
--- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java
+++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java
@@ -31,6 +31,7 @@ import java.nio.ByteBuffer;
import java.sql.Date;
import java.sql.Timestamp;
import java.time.LocalDate;
+import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
@@ -630,4 +631,72 @@ public class TestPartialRow {
}
}
+ @Test
+ public void testEquals() {
+ Schema schema = getSchemaWithAllTypes();
+
+ PartialRow row1 = getPartialRowWithAllTypes();
+ PartialRow row2 = schema.newPartialRow();
+ row2.addInt("int32", 999);
+ assertFalse(row1.equals(row2));
+
+ PartialRow row3 = schema.newPartialRow();
+ row3.addInt("int32", 44); // same value as row1 but missing other columns
+ assertFalse(row1.equals(row3));
+
+ assertFalse(row1.equals(null));
+
+ assertFalse(row1.equals("not a PartialRow"));
+
+ // Test with different schemas
+ Schema simpleSchema = new Schema(Arrays.asList(
+ new ColumnSchema.ColumnSchemaBuilder("key",
Type.INT32).key(true).build()));
+ PartialRow differentSchemaRow = simpleSchema.newPartialRow();
+ differentSchemaRow.addInt("key", 1);
+ assertFalse(row1.equals(differentSchemaRow));
+
+ // Test equality with itself and identical rows
+ assertTrue(row1.equals(row1));
+
+ PartialRow row4 = getPartialRowWithAllTypes();
+ assertTrue(row1.equals(row4));
+ }
+
+ @Test
+ public void testHashCode() {
+ final Schema schema = getSchemaWithAllTypes();
+
+ // Test hashCode consistency: equal objects must have equal hash codes
+ PartialRow row1 = getPartialRowWithAllTypes();
+ PartialRow row2 = getPartialRowWithAllTypes();
+ assertEquals(row1, row2);
+ assertEquals(row1.hashCode(), row2.hashCode());
+
+ int hash1 = row1.hashCode();
+ int hash2 = row1.hashCode();
+ assertEquals(hash1, hash2);
+
+ PartialRow emptyRow1 = schema.newPartialRow();
+ PartialRow emptyRow2 = schema.newPartialRow();
+ assertEquals(emptyRow1, emptyRow2);
+ assertEquals(emptyRow1.hashCode(), emptyRow2.hashCode());
+
+ // Test that different objects should have different hash codes
+ PartialRow differentRow = schema.newPartialRow();
+ differentRow.addInt("int32", 999);
+ assertFalse(row1.equals(differentRow));
+ // Note: hash codes can collide, but we expect them to be different in
this case
+ assertTrue(row1.hashCode() != differentRow.hashCode());
+
+ // Test with partially filled rows
+ PartialRow partialRow = schema.newPartialRow();
+ partialRow.addInt("int32", 44); // same value as row1 but missing other
columns
+ assertFalse(row1.equals(partialRow));
+ assertTrue(row1.hashCode() != partialRow.hashCode());
+
+ // Test empty row vs filled row
+ PartialRow emptyRow = schema.newPartialRow();
+ assertFalse(row1.equals(emptyRow));
+ assertTrue(row1.hashCode() != emptyRow.hashCode());
+ }
}
diff --git
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartitionSchemaClasses.java
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartitionSchemaClasses.java
new file mode 100644
index 000000000..5e0385cec
--- /dev/null
+++
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartitionSchemaClasses.java
@@ -0,0 +1,104 @@
+// 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.
+
+package org.apache.kudu.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.kudu.ColumnSchema;
+import org.apache.kudu.Schema;
+import org.apache.kudu.Type;
+import org.apache.kudu.test.junit.RetryRule;
+
+public class TestPartitionSchemaClasses {
+
+ @Rule
+ public RetryRule retryRule = new RetryRule();
+
+ @Test
+ public void testHashBucketSchemaEquals() {
+ PartitionSchema.HashBucketSchema schema1 = new
PartitionSchema.HashBucketSchema(
+ Arrays.asList(1, 2), 16, 42);
+ PartitionSchema.HashBucketSchema schema2 = new
PartitionSchema.HashBucketSchema(
+ Arrays.asList(1, 2), 16, 42);
+
+ assertEquals(schema1, schema2);
+ assertEquals(schema1.hashCode(), schema2.hashCode());
+
+ // Different column IDs
+ PartitionSchema.HashBucketSchema schema3 = new
PartitionSchema.HashBucketSchema(
+ Arrays.asList(1, 3), 16, 42);
+ assertFalse(schema1.equals(schema3));
+ // Note: hash codes can collide, but we expect them to be different in
this case
+ assertFalse(schema1.hashCode() == schema3.hashCode());
+
+ // Different number of buckets
+ PartitionSchema.HashBucketSchema schema4 = new
PartitionSchema.HashBucketSchema(
+ Arrays.asList(1, 2), 32, 42);
+ assertFalse(schema1.equals(schema4));
+ assertFalse(schema1.hashCode() == schema4.hashCode());
+
+ // Different seed
+ PartitionSchema.HashBucketSchema schema5 = new
PartitionSchema.HashBucketSchema(
+ Arrays.asList(1, 2), 16, 100);
+ assertFalse(schema1.equals(schema5));
+ assertFalse(schema1.hashCode() == schema5.hashCode());
+ }
+
+ @Test
+ public void testRangeWithHashSchemaEquals() {
+ Schema schema = new Schema(Collections.singletonList(
+ new ColumnSchema.ColumnSchemaBuilder("key",
Type.INT32).key(true).build()));
+
+ PartialRow lower = schema.newPartialRow();
+ lower.addInt("key", 10);
+ PartialRow upper = schema.newPartialRow();
+ upper.addInt("key", 20);
+
+ PartitionSchema.HashBucketSchema hashSchema = new
PartitionSchema.HashBucketSchema(
+ Collections.singletonList(0), 8, 0);
+
+ // Test equality of identical objects
+ PartitionSchema.RangeWithHashSchema range1 = new
PartitionSchema.RangeWithHashSchema(
+ lower, upper, Collections.singletonList(hashSchema));
+ PartitionSchema.RangeWithHashSchema range2 = new
PartitionSchema.RangeWithHashSchema(
+ lower, upper, Collections.singletonList(hashSchema));
+ assertEquals(range1, range2);
+ assertEquals(range1.hashCode(), range2.hashCode());
+
+ // Test inequality with different upper bound
+ PartialRow differentUpper = schema.newPartialRow();
+ differentUpper.addInt("key", 30);
+ PartitionSchema.RangeWithHashSchema range3 = new
PartitionSchema.RangeWithHashSchema(
+ lower, differentUpper, Collections.singletonList(hashSchema));
+ assertFalse(range1.equals(range3));
+
+ // Test inequality with different hash schema
+ PartitionSchema.HashBucketSchema differentHashSchema = new
PartitionSchema.HashBucketSchema(
+ Collections.singletonList(0), 16, 0);
+ PartitionSchema.RangeWithHashSchema range4 = new
PartitionSchema.RangeWithHashSchema(
+ lower, upper, Collections.singletonList(differentHashSchema));
+ assertFalse(range1.equals(range4));
+ }
+}