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

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


The following commit(s) were added to refs/heads/2.1 by this push:
     new 88abe226fd Log warning when durability not sync for root and meta 
tables (#5988)
88abe226fd is described below

commit 88abe226fd9ca3d04d27d12a0b160b0c09d0f542
Author: Dave Marion <[email protected]>
AuthorDate: Fri Dec 5 11:10:31 2025 -0500

    Log warning when durability not sync for root and meta tables (#5988)
    
    Related to #4455
---
 .../org/apache/accumulo/core/conf/Property.java    | 17 ++++++---
 .../apache/accumulo/core/file/FileOperations.java  | 40 ++++++++++++++++------
 .../accumulo/core/file/rfile/RFileOperations.java  | 17 +++++++++
 .../accumulo/server/compaction/FileCompactor.java  |  2 +-
 .../server/init/FileSystemInitializer.java         |  9 ++---
 .../accumulo/tserver/TabletClientHandler.java      | 12 +++++--
 6 files changed, 75 insertions(+), 22 deletions(-)

diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java 
b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
index 81e5a87532..9cd510fbd0 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
@@ -1283,10 +1283,19 @@ public enum Property {
           + " when the tablet metadata distance is above the supplied value.",
       "2.1.4"),
   TABLE_DURABILITY("table.durability", "sync", PropertyType.DURABILITY,
-      "The durability used to write to the write-ahead log. Legal values are:"
-          + " none, which skips the write-ahead log; log, which sends the data 
to the"
-          + " write-ahead log, but does nothing to make it durable; flush, 
which pushes"
-          + " data to the file system; and sync, which ensures the data is 
written to disk.",
+      "The durability of writes to tables includes ensuring that mutations 
written"
+          + " by clients are persisted in the write-ahead log and that files 
written"
+          + " during a compaction are persisted to disk successfully. This 
property only"
+          + " configures the durability used to write to the write-ahead log. 
Legal"
+          + " values are: none, which skips the write-ahead log; log, which 
sends the"
+          + " data to the write-ahead log, but does nothing to make it 
durable; flush,"
+          + " which pushes data out of the JVM (likely to page cache); and 
sync, which"
+          + " ensures that each mutation is written to the physical disk. To 
configure"
+          + " the durability of files written during minor and major 
compactions, set the"
+          + " Hadoop property \"dfs.datanode.synconclose\" to \"true\". This 
will ensure"
+          + " that the blocks of the files in HDFS are written to the physical 
disk as"
+          + " the compaction output files are written (Note that this may only 
apply"
+          + " to replicated files in HDFS).",
       "1.7.0"),
 
   TABLE_FAILURES_IGNORE("table.failures.ignore", "false", PropertyType.BOOLEAN,
diff --git 
a/core/src/main/java/org/apache/accumulo/core/file/FileOperations.java 
b/core/src/main/java/org/apache/accumulo/core/file/FileOperations.java
index f83d202b2f..ce5c392fdc 100644
--- a/core/src/main/java/org/apache/accumulo/core/file/FileOperations.java
+++ b/core/src/main/java/org/apache/accumulo/core/file/FileOperations.java
@@ -29,6 +29,7 @@ import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.file.blockfile.impl.CacheProvider;
 import org.apache.accumulo.core.file.rfile.RFile;
 import org.apache.accumulo.core.spi.crypto.CryptoService;
@@ -176,6 +177,7 @@ public abstract class FileOperations {
     public final Configuration fsConf;
     public final RateLimiter rateLimiter;
     // writer only objects
+    private final TableId tableId;
     public final String compression;
     public final FSDataOutputStream outputStream;
     public final boolean enableAccumuloStart;
@@ -190,11 +192,12 @@ public abstract class FileOperations {
     public final boolean inclusive;
     public final boolean dropCacheBehind;
 
-    public FileOptions(AccumuloConfiguration tableConfiguration, String 
filename, FileSystem fs,
-        Configuration fsConf, RateLimiter rateLimiter, String compression,
+    public FileOptions(TableId tableId, AccumuloConfiguration 
tableConfiguration, String filename,
+        FileSystem fs, Configuration fsConf, RateLimiter rateLimiter, String 
compression,
         FSDataOutputStream outputStream, boolean enableAccumuloStart, 
CacheProvider cacheProvider,
         Cache<String,Long> fileLenCache, boolean seekToBeginning, 
CryptoService cryptoService,
         Range range, Set<ByteSequence> columnFamilies, boolean inclusive, 
boolean dropCacheBehind) {
+      this.tableId = tableId;
       this.tableConfiguration = tableConfiguration;
       this.filename = filename;
       this.fs = fs;
@@ -213,6 +216,10 @@ public abstract class FileOperations {
       this.dropCacheBehind = dropCacheBehind;
     }
 
+    public TableId getTableId() {
+      return tableId;
+    }
+
     public AccumuloConfiguration getTableConfiguration() {
       return tableConfiguration;
     }
@@ -278,6 +285,7 @@ public abstract class FileOperations {
    * Helper class extended by both writers and readers.
    */
   public static class FileHelper {
+    private TableId tableId;
     private AccumuloConfiguration tableConfiguration;
     private String filename;
     private FileSystem fs;
@@ -286,6 +294,11 @@ public abstract class FileOperations {
     private CryptoService cryptoService;
     private boolean dropCacheBehind = false;
 
+    protected FileHelper table(TableId tid) {
+      this.tableId = tid;
+      return this;
+    }
+
     protected FileHelper fs(FileSystem fs) {
       this.fs = Objects.requireNonNull(fs);
       return this;
@@ -323,28 +336,28 @@ public abstract class FileOperations {
 
     protected FileOptions toWriterBuilderOptions(String compression,
         FSDataOutputStream outputStream, boolean startEnabled) {
-      return new FileOptions(tableConfiguration, filename, fs, fsConf, 
rateLimiter, compression,
-          outputStream, startEnabled, NULL_PROVIDER, null, false, 
cryptoService, null, null, true,
-          dropCacheBehind);
+      return new FileOptions(tableId, tableConfiguration, filename, fs, 
fsConf, rateLimiter,
+          compression, outputStream, startEnabled, NULL_PROVIDER, null, false, 
cryptoService, null,
+          null, true, dropCacheBehind);
     }
 
     protected FileOptions toReaderBuilderOptions(CacheProvider cacheProvider,
         Cache<String,Long> fileLenCache, boolean seekToBeginning) {
-      return new FileOptions(tableConfiguration, filename, fs, fsConf, 
rateLimiter, null, null,
-          false, cacheProvider == null ? NULL_PROVIDER : cacheProvider, 
fileLenCache,
+      return new FileOptions(tableId, tableConfiguration, filename, fs, 
fsConf, rateLimiter, null,
+          null, false, cacheProvider == null ? NULL_PROVIDER : cacheProvider, 
fileLenCache,
           seekToBeginning, cryptoService, null, null, true, dropCacheBehind);
     }
 
     protected FileOptions toIndexReaderBuilderOptions(Cache<String,Long> 
fileLenCache) {
-      return new FileOptions(tableConfiguration, filename, fs, fsConf, 
rateLimiter, null, null,
-          false, NULL_PROVIDER, fileLenCache, false, cryptoService, null, 
null, true,
+      return new FileOptions(tableId, tableConfiguration, filename, fs, 
fsConf, rateLimiter, null,
+          null, false, NULL_PROVIDER, fileLenCache, false, cryptoService, 
null, null, true,
           dropCacheBehind);
     }
 
     protected FileOptions toScanReaderBuilderOptions(Range range, 
Set<ByteSequence> columnFamilies,
         boolean inclusive) {
-      return new FileOptions(tableConfiguration, filename, fs, fsConf, 
rateLimiter, null, null,
-          false, NULL_PROVIDER, null, false, cryptoService, range, 
columnFamilies, inclusive,
+      return new FileOptions(tableId, tableConfiguration, filename, fs, 
fsConf, rateLimiter, null,
+          null, false, NULL_PROVIDER, null, false, cryptoService, range, 
columnFamilies, inclusive,
           dropCacheBehind);
     }
 
@@ -374,6 +387,11 @@ public abstract class FileOperations {
       return this;
     }
 
+    public WriterBuilder forTable(TableId tid) {
+      table(tid);
+      return this;
+    }
+
     @Override
     public WriterBuilder withTableConfiguration(AccumuloConfiguration 
tableConfiguration) {
       tableConfiguration(tableConfiguration);
diff --git 
a/core/src/main/java/org/apache/accumulo/core/file/rfile/RFileOperations.java 
b/core/src/main/java/org/apache/accumulo/core/file/rfile/RFileOperations.java
index 19b020a3d1..c87b071642 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/file/rfile/RFileOperations.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/file/rfile/RFileOperations.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.accumulo.core.client.sample.Sampler;
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
@@ -29,11 +30,14 @@ import org.apache.accumulo.core.conf.Property;
 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.file.FileOperations;
 import org.apache.accumulo.core.file.FileSKVIterator;
 import org.apache.accumulo.core.file.FileSKVWriter;
 import 
org.apache.accumulo.core.file.blockfile.impl.CachableBlockFile.CachableBuilder;
 import org.apache.accumulo.core.file.rfile.bcfile.BCFile;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.RootTable;
 import org.apache.accumulo.core.sample.impl.SamplerConfigurationImpl;
 import org.apache.accumulo.core.sample.impl.SamplerFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -41,6 +45,7 @@ import org.apache.hadoop.fs.CreateFlag;
 import org.apache.hadoop.fs.FSDataOutputStream;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.StreamCapabilities;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.hdfs.DistributedFileSystem;
 import org.slf4j.Logger;
@@ -53,6 +58,7 @@ public class RFileOperations extends FileOperations {
   private static final Logger LOG = 
LoggerFactory.getLogger(RFileOperations.class);
 
   private static final Collection<ByteSequence> EMPTY_CF_SET = 
Collections.emptySet();
+  private static final AtomicBoolean SYNC_CAPABILITY_LOGGED = new 
AtomicBoolean(false);
 
   private static RFile.Reader getReader(FileOptions options) throws 
IOException {
     CachableBuilder cb = new CachableBuilder()
@@ -194,6 +200,17 @@ public class RFileOperations extends FileOperations {
               e.getMessage());
         }
       }
+
+      TableId tid = options.getTableId();
+      if (tid != null && !SYNC_CAPABILITY_LOGGED.get()
+          && (RootTable.ID.equals(tid) || MetadataTable.ID.equals(tid))) {
+        if (!outputStream.hasCapability(StreamCapabilities.HSYNC)) {
+          SYNC_CAPABILITY_LOGGED.set(true);
+          LOG.warn("File created for table {} does not support hsync. If 
dfs.datanode.synconclose"
+              + " is configured, then it may not work. 
dfs.datanode.synconclose is recommended for the"
+              + " root and metadata tables.", tid);
+        }
+      }
     }
 
     BCFile.Writer _cbw = new BCFile.Writer(outputStream, 
options.getRateLimiter(), compression,
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/compaction/FileCompactor.java
 
b/server/base/src/main/java/org/apache/accumulo/server/compaction/FileCompactor.java
index c9352473db..0d48f26799 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/compaction/FileCompactor.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/compaction/FileCompactor.java
@@ -359,7 +359,7 @@ public class FileCompactor implements 
Callable<CompactionStats> {
           && ((isMinC && 
acuTableConf.getBoolean(Property.TABLE_MINC_OUTPUT_DROP_CACHE))
               || (!isMinC && 
acuTableConf.getBoolean(Property.TABLE_MAJC_OUTPUT_DROP_CACHE)));
 
-      WriterBuilder outBuilder = fileFactory.newWriterBuilder()
+      WriterBuilder outBuilder = 
fileFactory.newWriterBuilder().forTable(this.extent.tableId())
           .forFile(outputFile.getMetaInsert(), ns, ns.getConf(), cryptoService)
           
.withTableConfiguration(acuTableConf).withRateLimiter(env.getWriteLimiter());
       if (dropCacheBehindOutput) {
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/init/FileSystemInitializer.java
 
b/server/base/src/main/java/org/apache/accumulo/server/init/FileSystemInitializer.java
index 7e99f13bf9..873ea84347 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/init/FileSystemInitializer.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/init/FileSystemInitializer.java
@@ -127,14 +127,15 @@ class FileSystemInitializer {
     String metadataFileName = tableMetadataTabletDirUri + Path.SEPARATOR + 
"0_1." + ext;
     Tablet replicationTablet =
         new Tablet(REPL_TABLE_ID, replicationTableDefaultTabletDirName, null, 
null);
-    createMetadataFile(fs, metadataFileName, siteConfig, replicationTablet);
+    createMetadataFile(fs, metadataFileName, siteConfig, REPL_TABLE_ID, 
replicationTablet);
 
     // populate the root tablet with info about the metadata table's two 
initial tablets
     Tablet tablesTablet = new Tablet(MetadataTable.ID, 
tableMetadataTabletDirName, null, splitPoint,
         metadataFileName);
     Tablet defaultTablet =
         new Tablet(MetadataTable.ID, defaultMetadataTabletDirName, splitPoint, 
null);
-    createMetadataFile(fs, rootTabletFileUri, siteConfig, tablesTablet, 
defaultTablet);
+    createMetadataFile(fs, rootTabletFileUri, siteConfig, MetadataTable.ID, 
tablesTablet,
+        defaultTablet);
   }
 
   private void createDirectories(VolumeManager fs, String... dirs) throws 
IOException {
@@ -177,7 +178,7 @@ class FileSystemInitializer {
   }
 
   private void createMetadataFile(VolumeManager volmanager, String fileName,
-      AccumuloConfiguration conf, Tablet... tablets) throws IOException {
+      AccumuloConfiguration conf, TableId tid, Tablet... tablets) throws 
IOException {
     // sort file contents in memory, then play back to the file
     TreeMap<Key,Value> sorted = new TreeMap<>();
     for (Tablet tablet : tablets) {
@@ -187,7 +188,7 @@ class FileSystemInitializer {
 
     CryptoService cs = CryptoFactoryLoader.getServiceForServer(conf);
 
-    FileSKVWriter tabletWriter = 
FileOperations.getInstance().newWriterBuilder()
+    FileSKVWriter tabletWriter = 
FileOperations.getInstance().newWriterBuilder().forTable(tid)
         .forFile(fileName, fs, fs.getConf(), 
cs).withTableConfiguration(conf).build();
     tabletWriter.startDefaultLocalityGroup();
 
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
index 571acb5a3f..3644f6146c 100644
--- 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
+++ 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
@@ -426,6 +426,7 @@ public class TabletClientHandler implements 
TabletClientService.Iface {
         Tablet tablet = entry.getKey();
         Durability durability =
             DurabilityImpl.resolveDurabilty(us.durability, 
tablet.getDurability());
+        logDurabilityWarning(tablet, durability);
         List<Mutation> mutations = entry.getValue();
         if (!mutations.isEmpty()) {
           try {
@@ -704,7 +705,7 @@ public class TabletClientHandler implements 
TabletClientService.Iface {
         CommitSession session = prepared.getCommitSession();
         Durability durability = DurabilityImpl
             .resolveDurabilty(DurabilityImpl.fromThrift(tdurability), 
tabletDurability);
-
+        logDurabilityWarning(tablet, durability);
         // Instead of always looping on true, skip completely when durability 
is NONE.
         while (durability != Durability.NONE) {
           try {
@@ -814,7 +815,7 @@ public class TabletClientHandler implements 
TabletClientService.Iface {
         } else {
           final Durability durability =
               DurabilityImpl.resolveDurabilty(sess.durability, 
tablet.getDurability());
-
+          logDurabilityWarning(tablet, durability);
           List<Mutation> mutations = 
Collections.unmodifiableList(entry.getValue());
           if (!mutations.isEmpty()) {
 
@@ -1635,4 +1636,11 @@ public class TabletClientHandler implements 
TabletClientService.Iface {
       return handleTimeout(sessionId);
     }
   }
+
+  private void logDurabilityWarning(Tablet tablet, Durability durability) {
+    if (tablet.getExtent().isMeta() && durability != Durability.SYNC) {
+      log.warn("Property {} is not set to 'sync' for table {}", 
Property.TABLE_DURABILITY.getKey(),
+          tablet.getExtent().tableId());
+    }
+  }
 }

Reply via email to