This is an automated email from the ASF dual-hosted git repository.

krathbun pushed a commit to branch 3.1
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/3.1 by this push:
     new de2ae7fd3d Reorganizes MetadataConstraints (#4852)
de2ae7fd3d is described below

commit de2ae7fd3dc1b8b39e012c213b9c9e05dd78509e
Author: Kevin Rathbun <krath...@apache.org>
AuthorDate: Mon Sep 16 10:26:00 2024 -0400

    Reorganizes MetadataConstraints (#4852)
    
    - new class `BulkFileColData` to store the data needed to validate a 
BulkFileColumn update
    Changes to check():
    - now uses switch instead of if
    - validation logic of each column now done in separate methods
    - removed unnecessary checks and simplified logic where applicable (e.g., 
if checks that would never be true, same check done more than once)
    - violations are no longer added to and returned by `validate` methods, 
only added to. Avoids confusion with how the methods should be used.
            - initialized violations at start as a list instead of dealing with 
null. Null added extra unnecessary complexity.
---
 .../server/constraints/BulkFileColData.java        |  77 ++++
 .../server/constraints/MetadataConstraints.java    | 443 +++++++++++----------
 .../server/metadata/RootTabletMutatorImpl.java     |   2 +-
 .../constraints/MetadataConstraintsTest.java       |  41 +-
 .../apache/accumulo/test/functional/BulkNewIT.java |   3 +-
 5 files changed, 342 insertions(+), 224 deletions(-)

diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/constraints/BulkFileColData.java
 
b/server/base/src/main/java/org/apache/accumulo/server/constraints/BulkFileColData.java
new file mode 100644
index 0000000000..6533f8a19a
--- /dev/null
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/constraints/BulkFileColData.java
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ *   https://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.accumulo.server.constraints;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.accumulo.core.metadata.StoredTabletFile;
+
+/**
+ * Data needed to validate a BulkFileColumn update
+ */
+class BulkFileColData {
+  private boolean isSplitMutation, isLocationMutation;
+  private final Set<StoredTabletFile> dataFiles, loadedFiles;
+  private final Set<String> tidsSeen;
+
+  BulkFileColData() {
+    isSplitMutation = false;
+    isLocationMutation = false;
+    dataFiles = new HashSet<>();
+    loadedFiles = new HashSet<>();
+    tidsSeen = new HashSet<>();
+  }
+
+  void setIsSplitMutation(boolean b) {
+    isSplitMutation = b;
+  }
+
+  boolean getIsSplitMutation() {
+    return isSplitMutation;
+  }
+
+  void setIsLocationMutation(boolean b) {
+    isLocationMutation = b;
+  }
+
+  boolean getIsLocationMutation() {
+    return isLocationMutation;
+  }
+
+  void addDataFile(StoredTabletFile stf) {
+    dataFiles.add(stf);
+  }
+
+  void addLoadedFile(StoredTabletFile stf) {
+    loadedFiles.add(stf);
+  }
+
+  boolean dataFilesEqualsLoadedFiles() {
+    return dataFiles.equals(loadedFiles);
+  }
+
+  void addTidSeen(String tid) {
+    tidsSeen.add(tid);
+  }
+
+  Set<String> getTidsSeen() {
+    return tidsSeen;
+  }
+}
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
 
b/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
index da7acdda64..c3ca7bdd4a 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
@@ -21,10 +21,11 @@ package org.apache.accumulo.server.constraints;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import org.apache.accumulo.core.data.ColumnUpdate;
 import org.apache.accumulo.core.data.Mutation;
@@ -62,6 +63,7 @@ import org.slf4j.LoggerFactory;
 public class MetadataConstraints implements Constraint {
 
   private static final Logger log = 
LoggerFactory.getLogger(MetadataConstraints.class);
+  private static final byte[] BULK_COL_BYTES = 
BulkFileColumnFamily.STR_NAME.getBytes(UTF_8);
 
   private ZooCache zooCache = null;
   private String zooRoot = null;
@@ -113,246 +115,115 @@ public class MetadataConstraints implements Constraint {
     return validColumnQuals.contains(new ColumnFQ(cu));
   }
 
-  private static ArrayList<Short> addViolation(ArrayList<Short> lst, int 
violation) {
-    if (lst == null) {
-      lst = new ArrayList<>();
-    }
+  private static void addViolation(ArrayList<Short> lst, int violation) {
     lst.add((short) violation);
-    return lst;
   }
 
-  private static ArrayList<Short> addIfNotPresent(ArrayList<Short> lst, int 
intViolation) {
-    if (lst == null) {
-      return addViolation(null, intViolation);
-    }
-    short violation = (short) intViolation;
-    if (!lst.contains(violation)) {
-      return addViolation(lst, intViolation);
+  private static void addIfNotPresent(ArrayList<Short> lst, int violation) {
+    if (!lst.contains((short) violation)) {
+      addViolation(lst, violation);
     }
-    return lst;
   }
 
   /*
    * Validates the data file metadata is valid for a StoredTabletFile.
    */
-  private static ArrayList<Short> validateDataFileMetadata(ArrayList<Short> 
violations,
-      String metadata) {
+  private static void validateDataFileMetadata(ArrayList<Short> violations, 
String metadata,
+      Consumer<StoredTabletFile> stfConsumer) {
     try {
-      StoredTabletFile.validate(metadata);
+      stfConsumer.accept(StoredTabletFile.of(metadata));
     } catch (RuntimeException e) {
-      violations = addViolation(violations, 9);
+      addViolation(violations, 9);
     }
-    return violations;
   }
 
+  /**
+   * Same as defined in {@link Constraint#check(Environment, Mutation)}, but 
returns an empty list
+   * instead of null if there are no violations
+   *
+   * @param env constraint environment
+   * @param mutation mutation to check
+   * @return list of violations, or empty list if no violations
+   */
   @Override
   public List<Short> check(Environment env, Mutation mutation) {
     final ServerContext context = ((SystemEnvironment) env).getServerContext();
-
-    ArrayList<Short> violations = null;
-
-    Collection<ColumnUpdate> colUpdates = mutation.getUpdates();
-
-    // check the row, it should contains at least one ; or end with <
-    boolean containsSemiC = false;
-
-    byte[] row = mutation.getRow();
-
-    // always allow rows that fall within reserved areas
-    if (row.length > 0 && row[0] == '~') {
-      return null;
-    }
-
-    for (byte b : row) {
-      if (b == ';') {
-        containsSemiC = true;
-      }
-
-      if (b == ';' || b == '<') {
-        break;
-      }
-
-      if (!validTableNameChars[0xff & b]) {
-        violations = addIfNotPresent(violations, 4);
-      }
-    }
-
-    if (containsSemiC) {
-      if (row.length == 0) {
-        violations = addIfNotPresent(violations, 4);
-      }
+    final ArrayList<Short> violations = new ArrayList<>();
+    final Collection<ColumnUpdate> colUpdates = mutation.getUpdates();
+    final byte[] row = mutation.getRow();
+    final List<ColumnUpdate> bulkFileColUpdates;
+    final BulkFileColData bfcValidationData;
+
+    // avoids creating unnecessary objects
+    if (hasBulkCol(colUpdates)) {
+      bulkFileColUpdates = new ArrayList<>();
+      bfcValidationData = new BulkFileColData();
     } else {
-      // see if last row char is <
-      if (row.length == 0 || row[row.length - 1] != '<') {
-        violations = addIfNotPresent(violations, 4);
-      }
+      bulkFileColUpdates = null;
+      bfcValidationData = null;
     }
 
-    if (row.length > 0 && row[0] == '!') {
-      if (row.length < 3 || row[1] != '0' || (row[2] != '<' && row[2] != ';')) 
{
-        violations = addIfNotPresent(violations, 4);
-      }
-    }
-
-    // ensure row is not less than Constants.METADATA_TABLE_ID
-    if (new Text(row).compareTo(new 
Text(AccumuloTable.METADATA.tableId().canonical())) < 0) {
-      violations = addViolation(violations, 5);
+    // always allow rows that fall within reserved areas
+    if (row.length > 0 && row[0] == '~') {
+      return violations;
     }
 
-    boolean checkedBulk = false;
+    validateTabletRow(violations, row);
 
     for (ColumnUpdate columnUpdate : colUpdates) {
-      Text columnFamily = new Text(columnUpdate.getColumnFamily());
+      String colFamStr = new String(columnUpdate.getColumnFamily(), UTF_8);
 
       if (columnUpdate.isDeleted()) {
         if (!isValidColumn(columnUpdate)) {
-          violations = addViolation(violations, 2);
+          addViolation(violations, 2);
         }
         continue;
       }
 
-      if (columnUpdate.getValue().length == 0 && 
!(columnFamily.equals(ScanFileColumnFamily.NAME)
-          || columnFamily.equals(LogColumnFamily.NAME))) {
-        violations = addViolation(violations, 6);
-      }
-
-      if (columnFamily.equals(DataFileColumnFamily.NAME)) {
-        violations = validateDataFileMetadata(violations,
-            new String(columnUpdate.getColumnQualifier(), UTF_8));
-
-        try {
-          DataFileValue dfv = new DataFileValue(columnUpdate.getValue());
+      validateColValLen(violations, columnUpdate);
 
-          if (dfv.getSize() < 0 || dfv.getNumEntries() < 0) {
-            violations = addViolation(violations, 1);
-          }
-        } catch (NumberFormatException | ArrayIndexOutOfBoundsException nfe) {
-          violations = addViolation(violations, 1);
-        }
-      } else if (columnFamily.equals(ScanFileColumnFamily.NAME)) {
-        violations = validateDataFileMetadata(violations,
-            new String(columnUpdate.getColumnQualifier(), UTF_8));
-      } else if (columnFamily.equals(BulkFileColumnFamily.NAME)) {
-        if (!columnUpdate.isDeleted() && !checkedBulk) {
-          /*
-           * This needs to be re-worked after Issue 
https://github.com/apache/accumulo/issues/3505
-           * is done.
-           *
-           * That issue will reorganizes this class and make things more 
efficient so we are not
-           * looping over the same mutation more than once like in this case. 
The below check is
-           * commented out for now because the violation check is already done 
when creating
-           * StoredTabletFiles so it isn't needed here anymore violations =
-           * validateDataFileMetadata(violations, new 
String(columnUpdate.getColumnQualifier(),
-           * UTF_8));
-           */
-
-          // splits, which also write the time reference, are allowed to write 
this reference even
-          // when
-          // the transaction is not running because the other half of the 
tablet is holding a
-          // reference
-          // to the file.
-          boolean isSplitMutation = false;
+      switch (colFamStr) {
+        case TabletColumnFamily.STR_NAME:
+          validateTabletFamily(violations, columnUpdate, mutation);
+          break;
+        case ServerColumnFamily.STR_NAME:
+          validateServerFamily(violations, columnUpdate, context, 
bfcValidationData);
+          break;
+        case CurrentLocationColumnFamily.STR_NAME:
           // When a tablet is assigned, it re-writes the metadata. It should 
probably only update
-          // the location information,
-          // but it writes everything. We allow it to re-write the bulk 
information if it is setting
-          // the location.
+          // the location information, but it writes everything. We allow it 
to re-write the bulk
+          // information if it is setting the location.
           // See ACCUMULO-1230.
-          boolean isLocationMutation = false;
-
-          HashSet<StoredTabletFile> dataFiles = new HashSet<>();
-          HashSet<StoredTabletFile> loadedFiles = new HashSet<>();
-
-          String tidString = new String(columnUpdate.getValue(), UTF_8);
-          int otherTidCount = 0;
-
-          for (ColumnUpdate update : mutation.getUpdates()) {
-            if (new 
ColumnFQ(update).equals(ServerColumnFamily.DIRECTORY_COLUMN)) {
-              isSplitMutation = true;
-            } else if (new Text(update.getColumnFamily())
-                .equals(CurrentLocationColumnFamily.NAME)) {
-              isLocationMutation = true;
-            } else if (new 
Text(update.getColumnFamily()).equals(DataFileColumnFamily.NAME)) {
-              try {
-                // This actually validates for a second time as the loop 
already validates
-                // if a DataFileColumnFamily, this will likely be fixed as 
part of
-                // https://github.com/apache/accumulo/issues/3505
-                dataFiles.add(StoredTabletFile.of(new 
Text(update.getColumnQualifier())));
-              } catch (RuntimeException e) {
-                violations = addViolation(violations, 9);
-              }
-            } else if (new 
Text(update.getColumnFamily()).equals(BulkFileColumnFamily.NAME)) {
-              try {
-                loadedFiles.add(StoredTabletFile.of(new 
Text(update.getColumnQualifier())));
-              } catch (RuntimeException e) {
-                violations = addViolation(violations, 9);
-              }
-
-              if (!new String(update.getValue(), UTF_8).equals(tidString)) {
-                otherTidCount++;
-              }
-            }
+          if (bfcValidationData != null) {
+            bfcValidationData.setIsLocationMutation(true);
           }
-
-          if (!isSplitMutation && !isLocationMutation) {
-            if (otherTidCount > 0 || !dataFiles.equals(loadedFiles)) {
-              violations = addViolation(violations, 8);
-            }
+          break;
+        case SuspendLocationColumn.STR_NAME:
+          validateSuspendLocationFamily(violations, columnUpdate);
+          break;
+        case BulkFileColumnFamily.STR_NAME:
+          // defer validating the bulk file column updates until the end 
(relies on checks done
+          // on other column updates)
+          if (bulkFileColUpdates != null) {
+            bulkFileColUpdates.add(columnUpdate);
           }
-
-          checkedBulk = true;
-        }
-      } else {
-        if (!isValidColumn(columnUpdate)) {
-          violations = addViolation(violations, 2);
-        } else {
-          final var column = new ColumnFQ(columnUpdate);
-          if (column.equals(TabletColumnFamily.PREV_ROW_COLUMN)
-              && columnUpdate.getValue().length > 0
-              && (violations == null || !violations.contains((short) 4))) {
-            KeyExtent ke = KeyExtent.fromMetaRow(new Text(mutation.getRow()));
-
-            Text per = TabletColumnFamily.decodePrevEndRow(new 
Value(columnUpdate.getValue()));
-
-            boolean prevEndRowLessThanEndRow =
-                per == null || ke.endRow() == null || 
per.compareTo(ke.endRow()) < 0;
-
-            if (!prevEndRowLessThanEndRow) {
-              violations = addViolation(violations, 3);
-            }
-          } else if (column.equals(ServerColumnFamily.LOCK_COLUMN)) {
-            if (zooCache == null) {
-              zooCache = new ZooCache(context.getZooReader(), null);
-              CleanerUtil.zooCacheClearer(this, zooCache);
-            }
-
-            if (zooRoot == null) {
-              zooRoot = context.getZooKeeperRoot();
-            }
-
-            boolean lockHeld = false;
-            String lockId = new String(columnUpdate.getValue(), UTF_8);
-
-            try {
-              lockHeld = ServiceLock.isLockHeld(zooCache, new 
ZooUtil.LockID(zooRoot, lockId));
-            } catch (Exception e) {
-              log.debug("Failed to verify lock was held {} {}", lockId, 
e.getMessage());
-            }
-
-            if (!lockHeld) {
-              violations = addViolation(violations, 7);
-            }
-          } else if (column.equals(SuspendLocationColumn.SUSPEND_COLUMN)) {
-            try {
-              SuspendingTServer.fromValue(new Value(columnUpdate.getValue()));
-            } catch (IllegalArgumentException e) {
-              violations = addViolation(violations, 10);
-            }
+          break;
+        case DataFileColumnFamily.STR_NAME:
+          validateDataFileFamily(violations, columnUpdate, bfcValidationData);
+          break;
+        case ScanFileColumnFamily.STR_NAME:
+          validateScanFileFamily(violations, columnUpdate);
+          break;
+        default:
+          if (!isValidColumn(columnUpdate)) {
+            addViolation(violations, 2);
           }
-        }
       }
     }
 
-    if (violations != null) {
+    validateBulkFileFamily(violations, bulkFileColUpdates, bfcValidationData);
+
+    if (!violations.isEmpty()) {
       log.debug("violating metadata mutation : {}", new 
String(mutation.getRow(), UTF_8));
       for (ColumnUpdate update : mutation.getUpdates()) {
         log.debug(" update: {}:{} value {}", new 
String(update.getColumnFamily(), UTF_8),
@@ -392,4 +263,174 @@ public class MetadataConstraints implements Constraint {
     return null;
   }
 
+  private void validateColValLen(ArrayList<Short> violations, ColumnUpdate 
columnUpdate) {
+    Text columnFamily = new Text(columnUpdate.getColumnFamily());
+    if (columnUpdate.getValue().length == 0 && 
!(columnFamily.equals(ScanFileColumnFamily.NAME)
+        || columnFamily.equals(LogColumnFamily.NAME))) {
+      addViolation(violations, 6);
+    }
+  }
+
+  private void validateTabletRow(ArrayList<Short> violations, byte[] row) {
+    // check the row, it should contain at least one ";" or end with "<". Row 
should also
+    // not be less than AccumuloTable.METADATA.tableId().
+    boolean containsSemiC = false;
+
+    for (byte b : row) {
+      if (b == ';') {
+        containsSemiC = true;
+      }
+
+      if (b == ';' || b == '<') {
+        break;
+      }
+
+      if (!validTableNameChars[0xff & b]) {
+        addIfNotPresent(violations, 4);
+      }
+    }
+
+    if (!containsSemiC) {
+      // see if last row char is <
+      if (row.length == 0 || row[row.length - 1] != '<') {
+        addIfNotPresent(violations, 4);
+      }
+    }
+
+    if (row.length > 0 && row[0] == '!') {
+      if (row.length < 3 || row[1] != '0' || (row[2] != '<' && row[2] != ';')) 
{
+        addIfNotPresent(violations, 4);
+      }
+    }
+
+    // ensure row is not less than AccumuloTable.METADATA.tableId()
+    if (Arrays.compare(row, 
AccumuloTable.METADATA.tableId().canonical().getBytes(UTF_8)) < 0) {
+      addViolation(violations, 5);
+    }
+  }
+
+  private void validateTabletFamily(ArrayList<Short> violations, ColumnUpdate 
columnUpdate,
+      Mutation mutation) {
+    String qualStr = new String(columnUpdate.getColumnQualifier(), UTF_8);
+
+    if (qualStr.equals(TabletColumnFamily.PREV_ROW_QUAL)) {
+      if (columnUpdate.getValue().length > 0 && !violations.contains((short) 
4)) {
+        KeyExtent ke = KeyExtent.fromMetaRow(new Text(mutation.getRow()));
+        Text per = TabletColumnFamily.decodePrevEndRow(new 
Value(columnUpdate.getValue()));
+        boolean prevEndRowLessThanEndRow =
+            per == null || ke.endRow() == null || per.compareTo(ke.endRow()) < 
0;
+
+        if (!prevEndRowLessThanEndRow) {
+          addViolation(violations, 3);
+        }
+      }
+    }
+  }
+
+  private void validateServerFamily(ArrayList<Short> violations, ColumnUpdate 
columnUpdate,
+      ServerContext context, BulkFileColData bfcValidationData) {
+    String qualStr = new String(columnUpdate.getColumnQualifier(), UTF_8);
+
+    switch (qualStr) {
+      case ServerColumnFamily.LOCK_QUAL:
+        if (zooCache == null) {
+          zooCache = new ZooCache(context.getZooReader(), null);
+          CleanerUtil.zooCacheClearer(this, zooCache);
+        }
+
+        if (zooRoot == null) {
+          zooRoot = context.getZooKeeperRoot();
+        }
+
+        boolean lockHeld = false;
+        String lockId = new String(columnUpdate.getValue(), UTF_8);
+
+        try {
+          lockHeld = ServiceLock.isLockHeld(zooCache, new 
ZooUtil.LockID(zooRoot, lockId));
+        } catch (Exception e) {
+          log.debug("Failed to verify lock was held {} {}", lockId, 
e.getMessage());
+        }
+
+        if (!lockHeld) {
+          addViolation(violations, 7);
+        }
+        break;
+      case ServerColumnFamily.DIRECTORY_QUAL:
+        // splits, which also write the time reference, are allowed to write 
this reference
+        // even when the transaction is not running because the other half of 
the tablet is
+        // holding a reference to the file.
+        if (bfcValidationData != null) {
+          bfcValidationData.setIsSplitMutation(true);
+        }
+        break;
+    }
+  }
+
+  private void validateSuspendLocationFamily(ArrayList<Short> violations,
+      ColumnUpdate columnUpdate) {
+    String qualStr = new String(columnUpdate.getColumnQualifier(), UTF_8);
+    String suspendColQualStr =
+        new 
String(SuspendLocationColumn.SUSPEND_COLUMN.getColumnQualifier().getBytes(), 
UTF_8);
+
+    if (qualStr.equals(suspendColQualStr)) {
+      try {
+        SuspendingTServer.fromValue(new Value(columnUpdate.getValue()));
+      } catch (IllegalArgumentException e) {
+        addViolation(violations, 10);
+      }
+    }
+  }
+
+  private void validateDataFileFamily(ArrayList<Short> violations, 
ColumnUpdate columnUpdate,
+      BulkFileColData bfcValidationData) {
+    Consumer<StoredTabletFile> stfConsumer =
+        bfcValidationData == null ? stf -> {} : bfcValidationData::addDataFile;
+    validateDataFileMetadata(violations, new 
String(columnUpdate.getColumnQualifier(), UTF_8),
+        stfConsumer);
+
+    try {
+      DataFileValue dfv = new DataFileValue(columnUpdate.getValue());
+
+      if (dfv.getSize() < 0 || dfv.getNumEntries() < 0) {
+        addViolation(violations, 1);
+      }
+    } catch (NumberFormatException | ArrayIndexOutOfBoundsException nfe) {
+      addViolation(violations, 1);
+    }
+  }
+
+  private void validateScanFileFamily(ArrayList<Short> violations, 
ColumnUpdate columnUpdate) {
+    validateDataFileMetadata(violations, new 
String(columnUpdate.getColumnQualifier(), UTF_8),
+        stf -> {});
+  }
+
+  private void validateBulkFileFamily(ArrayList<Short> violations,
+      Collection<ColumnUpdate> bulkFileColUpdates, BulkFileColData 
bfcValidationData) {
+    if (bulkFileColUpdates != null && !bulkFileColUpdates.isEmpty()) {
+      for (ColumnUpdate bulkFileColUpdate : bulkFileColUpdates) {
+        validateDataFileMetadata(violations,
+            new String(bulkFileColUpdate.getColumnQualifier(), UTF_8),
+            bfcValidationData::addLoadedFile);
+
+        bfcValidationData.addTidSeen(new String(bulkFileColUpdate.getValue(), 
UTF_8));
+      }
+
+      if (!bfcValidationData.getIsSplitMutation() && 
!bfcValidationData.getIsLocationMutation()) {
+        if (bfcValidationData.getTidsSeen().size() > 1
+            || !bfcValidationData.dataFilesEqualsLoadedFiles()) {
+          addViolation(violations, 8);
+        }
+      }
+    }
+  }
+
+  private boolean hasBulkCol(Collection<ColumnUpdate> colUpdates) {
+    for (ColumnUpdate colUpdate : colUpdates) {
+      if (Arrays.equals(colUpdate.getColumnFamily(), BULK_COL_BYTES)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/metadata/RootTabletMutatorImpl.java
 
b/server/base/src/main/java/org/apache/accumulo/server/metadata/RootTabletMutatorImpl.java
index 7ebdd7db92..85c5992b4f 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/metadata/RootTabletMutatorImpl.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/metadata/RootTabletMutatorImpl.java
@@ -83,7 +83,7 @@ public class RootTabletMutatorImpl extends TabletMutatorBase 
implements Ample.Ta
     MetadataConstraints metaConstraint = new MetadataConstraints();
     List<Short> violations = metaConstraint.check(new RootEnv(context), 
mutation);
 
-    if (violations != null && !violations.isEmpty()) {
+    if (!violations.isEmpty()) {
       throw new IllegalStateException(
           "Mutation for root tablet metadata violated constraints : " + 
violations);
     }
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/constraints/MetadataConstraintsTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/constraints/MetadataConstraintsTest.java
index b8e7cf38a1..4d69ebd8a6 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/constraints/MetadataConstraintsTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/constraints/MetadataConstraintsTest.java
@@ -19,8 +19,9 @@
 package org.apache.accumulo.server.constraints;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.lang.reflect.Method;
 import java.util.Base64;
@@ -71,7 +72,7 @@ public class MetadataConstraintsTest {
 
     List<Short> violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 3), violations.get(0));
 
@@ -80,7 +81,7 @@ public class MetadataConstraintsTest {
 
     violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 4), violations.get(0));
 
@@ -89,7 +90,7 @@ public class MetadataConstraintsTest {
 
     violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 2), violations.get(0));
 
@@ -98,7 +99,7 @@ public class MetadataConstraintsTest {
 
     violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(2, violations.size());
     assertEquals(Short.valueOf((short) 4), violations.get(0));
     assertEquals(Short.valueOf((short) 5), violations.get(1));
@@ -108,7 +109,7 @@ public class MetadataConstraintsTest {
 
     violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 6), violations.get(0));
 
@@ -117,21 +118,21 @@ public class MetadataConstraintsTest {
 
     violations = mc.check(createEnv(), m);
 
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     m = new Mutation(new Text(AccumuloTable.METADATA.tableId().canonical() + 
"<"));
     TabletColumnFamily.PREV_ROW_COLUMN.put(m, new Value("bar"));
 
     violations = mc.check(createEnv(), m);
 
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     m = new Mutation(new Text("!1<"));
     TabletColumnFamily.PREV_ROW_COLUMN.put(m, new Value("bar"));
 
     violations = mc.check(createEnv(), m);
 
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 4), violations.get(0));
 
@@ -146,19 +147,19 @@ public class MetadataConstraintsTest {
     SuspendLocationColumn.SUSPEND_COLUMN.put(m, SuspendingTServer.toValue(ser1,
         SteadyTime.from(System.currentTimeMillis(), TimeUnit.MILLISECONDS)));
     List<Short> violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     m = new Mutation(new Text("0;foo"));
     SuspendLocationColumn.SUSPEND_COLUMN.put(m,
         SuspendingTServer.toValue(ser1, SteadyTime.from(0, 
TimeUnit.MILLISECONDS)));
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     m = new Mutation(new Text("0;foo"));
     // We must encode manually since SteadyTime won't allow a negative
     SuspendLocationColumn.SUSPEND_COLUMN.put(m, new Value(ser1.getHostPort() + 
"|" + -1L));
     violations = mc.check(createEnv(), m);
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(Short.valueOf((short) 10), violations.get(0));
   }
@@ -180,7 +181,7 @@ public class MetadataConstraintsTest {
             .of(new 
Path("hdfs://1.2.3.4/accumulo/tables/2a/t-0003/someFile")).getMetadataText(),
         new DataFileValue(1, 1).encodeAsValue());
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // loaded marker w/o file
     m = new Mutation(new Text("0;foo"));
@@ -209,7 +210,7 @@ public class MetadataConstraintsTest {
             .of(new 
Path("hdfs://1.2.3.4/accumulo/tables/2a/t-0003/someFile2")).getMetadataText(),
         new DataFileValue(1, 1).encodeAsValue());
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // two files w/ different txid
     m = new Mutation(new Text("0;foo"));
@@ -255,7 +256,7 @@ public class MetadataConstraintsTest {
         new Value("5"));
     ServerColumnFamily.DIRECTORY_COLUMN.put(m, new Value("/t1"));
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // mutation that looks like a load
     m = new Mutation(new Text("0;foo"));
@@ -265,14 +266,14 @@ public class MetadataConstraintsTest {
         new Value("5"));
     m.put(CurrentLocationColumnFamily.NAME, new Text("789"), new 
Value("127.0.0.1:9997"));
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // deleting a load flag
     m = new Mutation(new Text("0;foo"));
     m.putDelete(BulkFileColumnFamily.NAME, StoredTabletFile
         .of(new 
Path("hdfs://1.2.3.4/accumulo/tables/2a/t-0003/someFile")).getMetadataText());
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // Missing beginning of path
     m = new Mutation(new Text("0;foo"));
@@ -460,7 +461,7 @@ public class MetadataConstraintsTest {
             .of(new 
Path("hdfs://1.2.3.4/accumulo/tables/2a/t-0003/someFile")).getMetadataText(),
         new DataFileValue(1, 1).encodeAsValue());
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     // Should pass validation with range set
     m = new Mutation(new Text("0;foo"));
@@ -469,7 +470,7 @@ public class MetadataConstraintsTest {
             new Range("a", false, "b", true)).getMetadataText(),
         new DataFileValue(1, 1).encodeAsValue());
     violations = mc.check(createEnv(), m);
-    assertNull(violations);
+    assertTrue(violations.isEmpty());
 
     assertNotNull(mc.getViolationDescription((short) 9));
   }
@@ -488,7 +489,7 @@ public class MetadataConstraintsTest {
 
   private void assertViolation(MetadataConstraints mc, Mutation m, Short 
violation) {
     List<Short> violations = mc.check(createEnv(), m);
-    assertNotNull(violations);
+    assertFalse(violations.isEmpty());
     assertEquals(1, violations.size());
     assertEquals(violation, violations.get(0));
     assertNotNull(mc.getViolationDescription(violations.get(0)));
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java 
b/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
index 06fdb6945f..ee9d418b68 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
@@ -24,7 +24,6 @@ import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -723,7 +722,7 @@ public class BulkNewIT extends SharedMiniClusterBase {
         m.put("", "", NoBulkConstratint.CANARY_VALUE);
         // This test assume the metadata constraint check will not flag this 
mutation, the following
         // validates this assumption.
-        assertNull(metaConstraints.check(env, m));
+        assertTrue(metaConstraints.check(env, m).isEmpty());
         bw.addMutation(m);
         return false;
       } catch (MutationsRejectedException e) {

Reply via email to