jaydeepkumar1984 commented on code in PR #3598:
URL: https://github.com/apache/cassandra/pull/3598#discussion_r1951815630


##########
src/java/org/apache/cassandra/repair/autorepair/AutoRepairConfig.java:
##########
@@ -0,0 +1,565 @@
+/*
+ * 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.cassandra.repair.autorepair;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+import org.apache.cassandra.config.DurationSpec;
+import org.apache.cassandra.config.ParameterizedClass;
+import org.apache.cassandra.utils.LocalizeString;
+import org.apache.cassandra.exceptions.ConfigurationException;
+import org.apache.cassandra.utils.FBUtilities;
+
+/**
+ * Defines configurations for AutoRepair.
+ */
+public class AutoRepairConfig implements Serializable
+{
+    // Enable/Disable the auto-repair scheduler.
+    // If set to false, the scheduler thread will not be started.
+    // If set to true, the repair scheduler thread will be created. The thread 
will
+    // check for secondary configuration available for each repair type (full, 
incremental,
+    // and preview_repaired), and based on that, it will schedule repairs.
+    public volatile Boolean enabled;
+    // Time interval between successive checks to see if ongoing repairs are 
complete or if it is time to schedule
+    // repairs.
+    public final DurationSpec.IntSecondsBound repair_check_interval = new 
DurationSpec.IntSecondsBound("5m");
+    // The scheduler needs to adjust its order when nodes leave the ring. 
Deleted hosts are tracked in metadata
+    // for a specified duration to ensure they are indeed removed before 
adjustments are made to the schedule.
+    public volatile DurationSpec.IntSecondsBound 
history_clear_delete_hosts_buffer_interval = new 
DurationSpec.IntSecondsBound("2h");
+    // Maximum number of retries for a repair session.
+    public volatile Integer repair_max_retries = 3;
+    // Backoff time before retrying a repair session.
+    public volatile DurationSpec.LongSecondsBound repair_retry_backoff = new 
DurationSpec.LongSecondsBound("30s");
+    // Minimum duration for the execution of a single repair task. This 
prevents the scheduler from overwhelming
+    // the node by scheduling too many repair tasks in a short period of time.
+    public volatile DurationSpec.LongSecondsBound repair_task_min_duration = 
new DurationSpec.LongSecondsBound("5s");
+
+    // global_settings overides Options.defaultOptions for all repair types
+    public volatile Options global_settings;
+
+    public static final Class<? extends IAutoRepairTokenRangeSplitter> 
DEFAULT_SPLITTER = RepairTokenRangeSplitter.class;
+
+    // make transient so gets consturcted in the implementation.
+    private final transient Map<RepairType, IAutoRepairTokenRangeSplitter> 
tokenRangeSplitters = new EnumMap<>(RepairType.class);
+
+    public enum RepairType implements Serializable
+    {
+        FULL,
+        INCREMENTAL,
+        PREVIEW_REPAIRED;
+
+        private final String configName;
+
+        RepairType()
+        {
+            this.configName = LocalizeString.toLowerCaseLocalized(name());
+        }
+
+        /**
+         * @return Format of the repair type as it should be represented in 
configuration.
+         * Canonically this is the enum name in lowerCase.
+         */
+        public String getConfigName()
+        {
+            return configName;
+        }
+
+        public static AutoRepairState getAutoRepairState(RepairType repairType)
+        {
+            switch (repairType)
+            {
+                case FULL:
+                    return new FullRepairState();
+                case INCREMENTAL:
+                    return new IncrementalRepairState();
+                case PREVIEW_REPAIRED:
+                    return new PreviewRepairedState();
+            }
+
+            throw new IllegalArgumentException("Invalid repair type: " + 
repairType);
+        }
+
+        /**
+         * Case-insensitive parsing of the repair type string into {@link 
RepairType}
+         *
+         * @param repairTypeStr the repair type string
+         * @return the {@link RepairType} represented by the {@code 
repairTypeStr} string
+         * @throws IllegalArgumentException when the repair type string does 
not match any repair type
+         */
+        public static RepairType parse(String repairTypeStr)
+        {
+            return 
RepairType.valueOf(LocalizeString.toUpperCaseLocalized(Objects.requireNonNull(repairTypeStr,
 "repairTypeStr cannot be null")));
+        }
+    }
+
+    // repair_type_overrides overrides the global_settings for a specific 
repair type.  String used as key instead
+    // of enum to allow lower case key in yaml.
+    public volatile ConcurrentMap<String, Options> repair_type_overrides = 
Maps.newConcurrentMap();
+
+    public AutoRepairConfig()
+    {
+        this(false);
+    }
+
+    public AutoRepairConfig(boolean enabled)
+    {
+        this.enabled = enabled;
+        global_settings = Options.getDefaultOptions();
+    }
+
+    public DurationSpec.IntSecondsBound getRepairCheckInterval()
+    {
+        return repair_check_interval;
+    }
+
+    public boolean isAutoRepairSchedulingEnabled()
+    {
+        return enabled;
+    }
+
+    public DurationSpec.IntSecondsBound 
getAutoRepairHistoryClearDeleteHostsBufferInterval()
+    {
+        return history_clear_delete_hosts_buffer_interval;
+    }
+
+    public void startScheduler()
+    {
+        enabled = true;
+        AutoRepair.instance.setup();
+    }
+
+    public void setAutoRepairHistoryClearDeleteHostsBufferInterval(String 
duration)
+    {
+        history_clear_delete_hosts_buffer_interval = new 
DurationSpec.IntSecondsBound(duration);
+    }
+
+    public int getRepairMaxRetries()
+    {
+        return repair_max_retries;
+    }
+
+    public void setRepairMaxRetries(int maxRetries)
+    {
+        repair_max_retries = maxRetries;
+    }
+
+    public DurationSpec.LongSecondsBound getRepairRetryBackoff()
+    {
+        return repair_retry_backoff;
+    }
+
+    public void setRepairRetryBackoff(String interval)
+    {
+        repair_retry_backoff = new DurationSpec.LongSecondsBound(interval);
+    }
+
+    public DurationSpec.LongSecondsBound getRepairTaskMinDuration()
+    {
+        return repair_task_min_duration;
+    }
+
+    public void setRepairTaskMinDuration(String duration)
+    {
+        repair_task_min_duration = new DurationSpec.LongSecondsBound(duration);
+    }
+
+    public boolean isAutoRepairEnabled(RepairType repairType)
+    {
+        return enabled && applyOverrides(repairType, opt -> opt.enabled);
+    }
+
+    public void setAutoRepairEnabled(RepairType repairType, boolean enabled)
+    {
+        getOptions(repairType).enabled = enabled;
+    }
+
+    public void setRepairByKeyspace(RepairType repairType, boolean 
repairByKeyspace)
+    {
+        getOptions(repairType).repair_by_keyspace = repairByKeyspace;
+    }
+
+    public boolean getRepairByKeyspace(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.repair_by_keyspace);
+    }
+
+    public int getRepairThreads(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.number_of_repair_threads);
+    }
+
+    public void setRepairThreads(RepairType repairType, int repairThreads)
+    {
+        getOptions(repairType).number_of_repair_threads = repairThreads;
+    }
+
+    public DurationSpec.IntSecondsBound getRepairMinInterval(RepairType 
repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.min_repair_interval);
+    }
+
+    public void setRepairMinInterval(RepairType repairType, String 
minRepairInterval)
+    {
+        getOptions(repairType).min_repair_interval = new 
DurationSpec.IntSecondsBound(minRepairInterval);
+    }
+
+    public int getRepairSSTableCountHigherThreshold(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.sstable_upper_threshold);
+    }
+
+    public void setRepairSSTableCountHigherThreshold(RepairType repairType, 
int sstableHigherThreshold)
+    {
+        getOptions(repairType).sstable_upper_threshold = 
sstableHigherThreshold;
+    }
+
+    public DurationSpec.IntSecondsBound 
getAutoRepairTableMaxRepairTime(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.table_max_repair_time);
+    }
+
+    public void setAutoRepairTableMaxRepairTime(RepairType repairType, String 
autoRepairTableMaxRepairTime)
+    {
+        getOptions(repairType).table_max_repair_time = new 
DurationSpec.IntSecondsBound(autoRepairTableMaxRepairTime);
+    }
+
+    public Set<String> getIgnoreDCs(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.ignore_dcs);
+    }
+
+    public void setIgnoreDCs(RepairType repairType, Set<String> ignoreDCs)
+    {
+        getOptions(repairType).ignore_dcs = ignoreDCs;
+    }
+
+    public boolean getRepairPrimaryTokenRangeOnly(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> 
opt.repair_primary_token_range_only);
+    }
+
+    public void setRepairPrimaryTokenRangeOnly(RepairType repairType, boolean 
primaryTokenRangeOnly)
+    {
+        getOptions(repairType).repair_primary_token_range_only = 
primaryTokenRangeOnly;
+    }
+
+    public int getParallelRepairPercentage(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> 
opt.parallel_repair_percentage);
+    }
+
+    public void setParallelRepairPercentage(RepairType repairType, int 
percentage)
+    {
+        getOptions(repairType).parallel_repair_percentage = percentage;
+    }
+
+    public int getParallelRepairCount(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.parallel_repair_count);
+    }
+
+    public void setParallelRepairCount(RepairType repairType, int count)
+    {
+        getOptions(repairType).parallel_repair_count = count;
+    }
+
+    public boolean getMaterializedViewRepairEnabled(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> 
opt.materialized_view_repair_enabled);
+    }
+
+    public void setMaterializedViewRepairEnabled(RepairType repairType, 
boolean enabled)
+    {
+        getOptions(repairType).materialized_view_repair_enabled = enabled;
+    }
+
+    public void setForceRepairNewNode(RepairType repairType, boolean 
forceRepairNewNode)
+    {
+        getOptions(repairType).force_repair_new_node = forceRepairNewNode;
+    }
+
+    public boolean getForceRepairNewNode(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.force_repair_new_node);
+    }
+
+    public ParameterizedClass getTokenRangeSplitter(RepairType repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.token_range_splitter);
+    }
+
+    /**
+     * Set a new token range splitter, this is not meant to be used other than 
for testing.
+     */
+    @VisibleForTesting
+    void setTokenRangeSplitter(RepairType repairType, ParameterizedClass 
tokenRangeSplitter)
+    {
+        getOptions(repairType).token_range_splitter = tokenRangeSplitter;
+        tokenRangeSplitters.remove(repairType);
+    }
+
+    public IAutoRepairTokenRangeSplitter 
getTokenRangeSplitterInstance(RepairType repairType)
+    {
+        return tokenRangeSplitters.computeIfAbsent(repairType,
+                                                   key -> 
newAutoRepairTokenRangeSplitter(key, getTokenRangeSplitter(key)));
+    }
+
+    public void setInitialSchedulerDelay(RepairType repairType, String 
initialSchedulerDelay)
+    {
+        getOptions(repairType).initial_scheduler_delay = new 
DurationSpec.IntSecondsBound(initialSchedulerDelay);
+    }
+
+    public DurationSpec.IntSecondsBound getInitialSchedulerDelay(RepairType 
repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.initial_scheduler_delay);
+    }
+
+    public DurationSpec.IntSecondsBound getRepairSessionTimeout(RepairType 
repairType)
+    {
+        return applyOverrides(repairType, opt -> opt.repair_session_timeout);
+    }
+
+    public void setRepairSessionTimeout(RepairType repairType, String 
repairSessionTimeout)
+    {
+        getOptions(repairType).repair_session_timeout = new 
DurationSpec.IntSecondsBound(repairSessionTimeout);
+    }
+
+    @VisibleForTesting
+    static IAutoRepairTokenRangeSplitter 
newAutoRepairTokenRangeSplitter(RepairType repairType, ParameterizedClass 
parameterizedClass) throws ConfigurationException
+    {
+        try
+        {
+            Class<? extends IAutoRepairTokenRangeSplitter> 
tokenRangeSplitterClass;
+            final String className;
+            if (parameterizedClass.class_name != null && 
!parameterizedClass.class_name.isEmpty())
+            {
+                className = parameterizedClass.class_name.contains(".") ?
+                            parameterizedClass.class_name :
+                            "org.apache.cassandra.repair.autorepair." + 
parameterizedClass.class_name;
+                tokenRangeSplitterClass = FBUtilities.classForName(className, 
"token_range_splitter");
+            }
+            else
+            {
+                // If token_range_splitter.class_name is not defined, just use 
default, this is for convenience.
+                tokenRangeSplitterClass = AutoRepairConfig.DEFAULT_SPLITTER;
+            }
+            try
+            {
+                Map<String, String> parameters = parameterizedClass.parameters 
!= null ? parameterizedClass.parameters : Collections.emptyMap();
+                // first attempt to initialize with RepairType and Map 
arguments.
+                return 
tokenRangeSplitterClass.getConstructor(RepairType.class, 
Map.class).newInstance(repairType, parameters);
+            }
+            catch (NoSuchMethodException nsme)
+            {
+                // fall back on no argument constructor.
+                return tokenRangeSplitterClass.getConstructor().newInstance();
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new ConfigurationException("Unable to create instance of 
IAutoRepairTokenRangeSplitter", ex);
+        }
+    }
+
+    // Options configures auto-repair behavior for a given repair type.
+    // All fields can be modified dynamically.
+    public static class Options implements Serializable
+    {
+        // defaultOptions defines the default auto-repair behavior when no 
overrides are defined
+        @VisibleForTesting
+        private static Map<AutoRepairConfig.RepairType, Options> 
defaultOptions;
+
+        private static Map<AutoRepairConfig.RepairType, Options> 
initializeDefaultOptions()
+        {
+            Map<AutoRepairConfig.RepairType, Options> options = new 
EnumMap<>(AutoRepairConfig.RepairType.class);
+            options.put(AutoRepairConfig.RepairType.FULL, getDefaultOptions());
+            options.put(RepairType.INCREMENTAL, getDefaultOptions());
+            options.put(RepairType.PREVIEW_REPAIRED, getDefaultOptions());
+
+
+            options.get(RepairType.FULL).min_repair_interval = new 
DurationSpec.IntSecondsBound("24h");
+            // Incremental repairs operate over unrepaired data and should 
finish quickly. Running them more frequently keeps
+            // the unrepaired set smaller and thus causes repairs to operate 
over a smaller set of data, so a more frequent
+            // increase this interval to 24h or longer to reduce the impact of 
anticompaction caused by incremental repair.
+            options.get(RepairType.INCREMENTAL).min_repair_interval = new 
DurationSpec.IntSecondsBound("1h");
+            options.get(RepairType.PREVIEW_REPAIRED).min_repair_interval = new 
DurationSpec.IntSecondsBound("24h");
+
+            return options;
+        }
+
+        public static Map<AutoRepairConfig.RepairType, Options> 
getDefaultOptionsMap()
+        {
+            if (defaultOptions == null)
+            {
+                synchronized (AutoRepairConfig.class)
+                {
+                    if (defaultOptions == null)
+                    {
+                        defaultOptions = initializeDefaultOptions();
+                    }
+                }
+            }
+            return defaultOptions;
+        }
+
+        public Options()
+        {
+        }
+
+        @VisibleForTesting
+        protected static Options getDefaultOptions()
+        {
+            Options opts = new Options();
+
+            opts.enabled = false;
+            opts.repair_by_keyspace = true;
+            opts.number_of_repair_threads = 1;
+            opts.parallel_repair_count = 3;
+            opts.parallel_repair_percentage = 3;
+            opts.sstable_upper_threshold = 10000;
+            opts.ignore_dcs = new HashSet<>();
+            opts.repair_primary_token_range_only = true;
+            opts.force_repair_new_node = false;
+            opts.table_max_repair_time = new 
DurationSpec.IntSecondsBound("6h");
+            opts.materialized_view_repair_enabled = false;
+            opts.token_range_splitter = new 
ParameterizedClass(DEFAULT_SPLITTER.getName(), Collections.emptyMap());
+            opts.initial_scheduler_delay = new 
DurationSpec.IntSecondsBound("5m"); // 5 minutes

Review Comment:
   The comment is not needed here



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: pr-unsubscr...@cassandra.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscr...@cassandra.apache.org
For additional commands, e-mail: pr-h...@cassandra.apache.org

Reply via email to