diff --git a/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationDocGen.java b/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationDocGen.java index 4595123deb7..c8e202c1b42 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationDocGen.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationDocGen.java @@ -19,11 +19,16 @@ package org.apache.accumulo.core.conf; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.accumulo.core.conf.Property.markdownRef; import java.io.IOException; import java.io.PrintStream; import java.util.TreeMap; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; + /** * This class generates documentation to inform users of the available configuration properties in a * presentable form. @@ -31,121 +36,157 @@ public class ConfigurationDocGen { private final PrintStream doc; private final TreeMap sortedProps = new TreeMap<>(); + private final Gson gsonPrettyPrinter = + new GsonBuilder().disableJdkUnsafe().setPrettyPrinting().create(); + + private void generate() { + doc.print(""" + --- + title: Server Properties (4.x) + category: configuration + order: 4 + --- + + + + Below are properties set in `accumulo.properties` or the Accumulo shell that configure + Accumulo servers (i.e. tablet server, manager, etc). Properties labeled 'Experimental' + should not be considered stable and have a higher risk of changing in the future. + + + + + + + + + + """); - void generate() { - pageHeader(); - - beginTable("Property"); for (Property prop : sortedProps.values()) { if (prop.getType() == PropertyType.PREFIX) { - prefixSection(prop); + prefixRow(prop); } else { - property(prop); + propertyRow(prop); } } - beginSection("Property Types"); - beginTable("Type"); - propertyTypeDescriptions(); + doc.println(""" + +
PropertyDescription
- doc.close(); - } + ### Property Types - void beginSection(String section) { - doc.println("\n### " + section + "\n"); - } + + + + + + + + + """); - void beginTable(String name) { - doc.println("| " + name + " | Description |"); - doc.println("|--------------|-------------|"); - } + for (PropertyType type : PropertyType.values()) { + if (type != PropertyType.PREFIX) { + doc.printf(""" + + + + + """, type.toString(), type.getFormatDescription()); } } - description += strike(sanitize(prefix.getDescription()), depr); - doc.println("| " + key + " | " + description + " |"); + + doc.println(""" + +
TypeDescription
%s - void pageHeader() { - doc.println("---"); - doc.println("title: Server Properties (4.x)"); - doc.println("category: configuration"); - doc.println("order: 4"); - doc.println("---\n"); - doc.println("\n"); - doc.println("Below are properties set in `accumulo.properties` or the" - + " Accumulo shell that configure Accumulo servers (i.e. tablet server," - + " manager, etc). Properties labeled 'Experimental' should not be considered stable" - + " and have a higher risk of changing in the future.\n"); - } + %s - void prefixSection(Property prefix) { - boolean depr = prefix.isDeprecated(); - String key = strike(" **" + prefix.getKey() + "***", depr); - String description = prefix.isExperimental() ? "**Experimental**
" : ""; - description += "**Available since:** " + prefix.availableSince() + "
"; - if (depr) { - description += "*Deprecated since:* " + prefix.deprecatedSince() + "
"; - if (prefix.isReplaced()) { - description += "*Replaced by:* " + prefix.replacedBy() + "
"; +
+ """); + + doc.close(); + } + + private void prefixRow(Property prefix) { + boolean depr = prefix.isDeprecated(); + doc.printf(""" + + + %s**%s\\***%s + + + %s + **Available since:** %s
+ %s%s + + %s + + + + """, prefix.getKey().replace(".", "_"), depr ? "~~" : "", prefix.getKey(), depr ? "~~" : "", + prefix.isExperimental() ? "**⚠Experimental⚠**
" : "", + prefix.availableSince(), + depr ? "*Deprecated since:* " + prefix.deprecatedSince() + "
" : "", + depr && prefix.isReplaced() + ? "*Replaced by:* %s
".formatted(markdownRef(prefix.replacedBy().getKey())) : "", + prefix.getDescription()); } - void property(Property prop) { + private void propertyRow(Property prop) { boolean depr = prop.isDeprecated(); - String key = strike( - " " + prop.getKey(), - depr); - String description = prop.isExperimental() ? "**Experimental**
" : ""; - description += "**Available since:** "; - if (prop.getKey().startsWith("manager.") - && (prop.availableSince().startsWith("1.") || prop.availableSince().startsWith("2.0"))) { - description += "2.1.0 (formerly *master." + prop.getKey().substring(8) + "* since " - + prop.availableSince() + ")
"; - } else { - description += prop.availableSince() + "
"; - } - if (depr) { - description += "*Deprecated since:* " + prop.deprecatedSince() + "
"; - if (prop.isReplaced()) { - description += "*Replaced by:* " + prop.replacedBy() + "
"; - } - } - description += strike(sanitize(prop.getDescription()), depr) + "
" - + strike("**type:** " + prop.getType().name(), depr) + ", " - + strike("**zk mutable:** " + isZooKeeperMutable(prop), depr) + ", "; - String defaultValue = sanitize(prop.getDefaultValue()).trim(); + String del = depr ? "~~" : ""; + String availableSince = prop.getKey().startsWith("manager.") + && (prop.availableSince().startsWith("1.") || prop.availableSince().startsWith("2.0")) + ? "2.1.0 (formerly *master." + prop.getKey().substring(8) + "* since " + + prop.availableSince() + ")" + : prop.availableSince(); + String defaultValue = prop.getDefaultValue(); if (defaultValue.isEmpty()) { - description += strike("**default value:** empty", depr); - } else if (defaultValue.contains("\n")) { - // deal with multi-line values, skip strikethrough of value - description += strike("**default value:** ", depr) + "\n```\n" + defaultValue + "\n```\n"; + defaultValue = "empty"; } else if (prop.getType() == PropertyType.CLASSNAME && defaultValue.startsWith("org.apache.accumulo")) { - description += strike("**default value:** {% jlink -f " + defaultValue + " %}", depr); + defaultValue = "{% jlink -f " + defaultValue + " %}"; } else { - description += strike("**default value:** `" + defaultValue + "`", depr); - } - doc.println("| " + key + " | " + description + " |"); - } - - private String strike(String s, boolean isDeprecated) { - return (isDeprecated ? "~~" : "") + s + (isDeprecated ? "~~" : ""); - } - - void propertyTypeDescriptions() { - for (PropertyType type : PropertyType.values()) { - if (type == PropertyType.PREFIX) { - continue; - } - doc.println( - "| " + sanitize(type.toString()) + " | " + sanitize(type.getFormatDescription()) + " |"); + defaultValue = switch (prop.getType()) { + case JSON, FATE_META_CONFIG, FATE_USER_CONFIG -> """ + `%s` + + Formatted JSON (for convenience only): + ```json + %s + ``` + """.formatted(defaultValue, + gsonPrettyPrinter.toJson(JsonParser.parseString(defaultValue))); + default -> "`%s`".formatted(defaultValue); + }; } - } - - String sanitize(String str) { - return str.replace("\n", "
"); + doc.printf(""" + + + %s%s%s + + + %s + **Available since:** %s
+ %s%s + + %s + + **type:** %s, **zk mutable:** %s, **default value:** %s + + + """, prop.getKey().replace(".", "_"), del, prop.getKey(), del, + prop.isExperimental() ? "**⚠Experimental⚠**
" : "", availableSince, + depr ? "*Deprecated since:* " + prop.deprecatedSince() + "
" : "", + depr && prop.isReplaced() + ? "*Replaced by:* %s
".formatted(markdownRef(prop.replacedBy().getKey())) : "", + prop.getDescription(), prop.getType().toString(), isZooKeeperMutable(prop), defaultValue); } private ConfigurationDocGen(PrintStream doc) { @@ -160,7 +201,9 @@ private String isZooKeeperMutable(Property prop) { return "no"; } if (Property.isFixedZooPropertyKey(prop)) { - return "yes but requires restart of the " + prop.getKey().split("[.]")[0]; + String serverName = prop.getKey().startsWith("compaction.coordinator.") ? "manager" + : prop.getKey().split("[.]")[0]; + return "yes, but requires restart of the " + serverName; } return "yes"; } 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 ed35c8683f3..3d0071ac119 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 @@ -32,15 +32,27 @@ import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.classloader.ClassLoaderUtil; +import org.apache.accumulo.core.client.sample.Sampler; import org.apache.accumulo.core.data.constraints.NoDeleteConstraint; import org.apache.accumulo.core.file.blockfile.cache.tinylfu.TinyLfuBlockCacheManager; +import org.apache.accumulo.core.file.keyfunctor.ColumnFamilyFunctor; +import org.apache.accumulo.core.file.keyfunctor.ColumnQualifierFunctor; +import org.apache.accumulo.core.file.keyfunctor.RowFunctor; import org.apache.accumulo.core.file.rfile.RFile; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.iteratorsImpl.system.DeletingIterator; import org.apache.accumulo.core.metadata.SystemTables; +import org.apache.accumulo.core.spi.balancer.SimpleLoadBalancer; +import org.apache.accumulo.core.spi.balancer.TableLoadBalancer; +import org.apache.accumulo.core.spi.balancer.TabletBalancer; import org.apache.accumulo.core.spi.compaction.RatioBasedCompactionPlanner; import org.apache.accumulo.core.spi.compaction.SimpleCompactionDispatcher; +import org.apache.accumulo.core.spi.crypto.CryptoServiceFactory; +import org.apache.accumulo.core.spi.crypto.NoCryptoServiceFactory; import org.apache.accumulo.core.spi.fs.RandomVolumeChooser; +import org.apache.accumulo.core.spi.metrics.LoggingMeterRegistryFactory; +import org.apache.accumulo.core.spi.metrics.MeterRegistryFactory; +import org.apache.accumulo.core.spi.ondemand.LastAccessTimeOnDemandTabletUnloader; import org.apache.accumulo.core.spi.scan.ScanDispatcher; import org.apache.accumulo.core.spi.scan.ScanPrioritizer; import org.apache.accumulo.core.spi.scan.ScanServerSelector; @@ -53,19 +65,23 @@ public enum Property { COMPACTION_PREFIX("compaction.", null, PropertyType.PREFIX, "Both major and minor compaction properties can be included under this prefix.", "4.0.0"), - COMPACTION_SERVICE_PREFIX(COMPACTION_PREFIX + "service.", null, PropertyType.PREFIX, - """ - This prefix should be used to define all properties for the compaction services. - See {% jlink -f org.apache.accumulo.core.spi.compaction.RatioBasedCompactionPlanner %}. - A new external compaction service would be defined like the following: - `compaction.service.newService.planner="org.apache.accumulo.core.spi.compaction.RatioBasedCompactionPlanner".` - `compaction.service.newService.opts.groups=" - [{"group": "small", "maxSize": "32M"}, - {"group": "medium", "maxSize": "512M"}, - {"group": "large"}]` - `compaction.service.newService.opts.maxOpen=50` - Additional options can be defined using the `compaction.service..opts.