This is an automated email from the ASF dual-hosted git repository.
ctubbsii pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new 208204bdd6 Add validate method to TabletMetadata (#5340)
208204bdd6 is described below
commit 208204bdd6392348acd741b1f44e393fd56953be
Author: Arbaaz Khan <[email protected]>
AuthorDate: Thu May 15 15:07:52 2025 -0400
Add validate method to TabletMetadata (#5340)
Add a validate method to TabletMetadata to ensure tablet files
have ranges that match the tablet in which they are located.
---
.../core/metadata/schema/TabletMetadata.java | 25 ++++++++++++-
.../core/metadata/schema/TabletMetadataTest.java | 43 ++++++++++++++++++++++
2 files changed, 67 insertions(+), 1 deletion(-)
diff --git
a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
index 8d0f84a60d..b51890b6ca 100644
---
a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
+++
b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
@@ -63,6 +63,7 @@ import
org.apache.accumulo.core.clientImpl.TabletAvailabilityUtil;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.TableId;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.dataImpl.KeyExtent;
@@ -846,6 +847,26 @@ public class TabletMetadata {
.map(address -> new TServerInstance(address,
stat.getEphemeralOwner()));
}
+ public static void validate(TabletMetadata tm) {
+ if (tm.files.isEmpty() || !tm.fetchedCols.contains(ColumnType.PREV_ROW)) {
+ return;
+ }
+
+ Collection<StoredTabletFile> files = tm.getFiles();
+ Range tabletRange = tm.getExtent().toDataRange();
+
+ for (StoredTabletFile file : files) {
+ if (!isFileRangeValid(file, tabletRange)) {
+ throw new IllegalStateException(
+ "File range " + file.getRange() + " does not overlap with tablet
range " + tabletRange);
+ }
+ }
+ }
+
+ private static boolean isFileRangeValid(StoredTabletFile file, Range
tabletRange) {
+ return !file.hasRange() || tabletRange.clip(file.getRange(), true) != null;
+ }
+
static class Builder {
private TableId tableId;
private Text prevEndRow;
@@ -1006,7 +1027,9 @@ public class TabletMetadata {
TabletMetadata build(EnumSet<ColumnType> fetchedCols) {
this.fetchedCols = fetchedCols;
- return new TabletMetadata(this);
+ TabletMetadata tm = new TabletMetadata(this);
+ validate(tm);
+ return tm;
}
}
}
diff --git
a/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
b/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
index c974493f6d..2256ab5ca3 100644
---
a/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
+++
b/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
@@ -35,9 +35,11 @@ import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LAST;
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION;
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.MERGED;
+import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW;
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.SUSPEND;
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.UNSPLITTABLE;
import static
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.USER_COMPACTION_REQUESTED;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -374,6 +376,45 @@ public class TabletMetadataTest {
assertTrue(closeCalled.get());
}
+ @Test
+ public void testValidateWithNonOverlappingFileRange() {
+ KeyExtent extent = new KeyExtent(TableId.of("1"), new Text("d"), new
Text("b"));
+
+ Range fileRange = new Range(new Text("x\0"), true, new Text("z\0"), false);
+ StoredTabletFile file =
+ StoredTabletFile.of(new Path("file:///accumulo/tables/t-0/b-0/f1.rf"),
fileRange);
+ TabletMetadataBuilder builder =
+ TabletMetadata.builder(extent).putFile(file, new DataFileValue(0, 0,
0));
+
+ assertThrows(IllegalStateException.class, () ->
builder.build(ColumnType.values()));
+ }
+
+ @Test
+ public void testValidateWithOverlappingFileRange() {
+ KeyExtent extent = new KeyExtent(TableId.of("2"), new Text("m"), new
Text("a"));
+
+ Range fileRange = new Range(new Text("c\0"), true, new Text("e\0"), false);
+ StoredTabletFile file =
+ StoredTabletFile.of(new Path("file:///accumulo/tables/t-0/b-0/f2.rf"),
fileRange);
+ TabletMetadataBuilder builder =
+ TabletMetadata.builder(extent).putFile(file, new DataFileValue(0, 0,
0));
+
+ assertDoesNotThrow(() -> builder.build(ColumnType.values()));
+ }
+
+ @Test
+ public void testValidateWithNoFileRange() {
+ KeyExtent extent = new KeyExtent(TableId.of("3"), new Text("d"), new
Text("b"));
+
+ Range emptyRange = new Range();
+ StoredTabletFile file =
+ StoredTabletFile.of(new Path("file:///accumulo/tables/t-0/b-0/f3.rf"),
emptyRange);
+ TabletMetadataBuilder builder =
+ TabletMetadata.builder(extent).putFile(file, new DataFileValue(0, 0,
0));
+
+ assertDoesNotThrow(() -> builder.build(ColumnType.values()));
+ }
+
@Test
public void testTmBuilderImmutable() {
TabletMetadata.Builder b = new Builder();
@@ -414,6 +455,7 @@ public class TabletMetadataTest {
.add(FateId.from(FateInstanceType.USER, UUID.randomUUID())));
// Set some data in the collections and very they are not empty but still
immutable
+ b.table(TableId.of("4"));
b.extCompaction(ecid, ecMeta);
b.file(stf, new DataFileValue(0, 0, 0));
b.log(LogEntry.fromPath("localhost+8020/" + UUID.randomUUID()));
@@ -422,6 +464,7 @@ public class TabletMetadataTest {
b.compacted(FateId.from(FateInstanceType.USER, UUID.randomUUID()));
b.userCompactionsRequested(FateId.from(FateInstanceType.USER,
UUID.randomUUID()));
b.keyValue(new AbstractMap.SimpleImmutableEntry<>(new Key(), new Value()));
+ b.sawPrevEndRow(true);
var tm2 = b.build(EnumSet.allOf(ColumnType.class));
assertEquals(1, tm2.getExternalCompactions().size());