autorepair v2 framework (against 4.1.6)#3367
Conversation
a81e10d to
0e36ed5
Compare
There was a problem hiding this comment.
👍 thanks for doing this. I imagine it could be useful to be able to configure things more granularly. I have some cases where we want to run full repair on a table, but never incremental (the main use case is analytics based where etl processes are loading a bunch of SSTables every few hours). Will come back to this as I review and experiment more with the PR, if there is a bunch of things that we would want configurable at table level maybe we could consider adding something like a RepairParams, otherwise maybe this is fine as is.
There was a problem hiding this comment.
This may be overkill and some of the options may not be applicable, but wonder if we could just have a single field that functions similarly to AutoRepairConfig.repair_type_overrides:
So one could do something like:
ALTER TABLE x.y WITH automated_repair={'incremental': {'enabled': false}};
Most of the repair_type_overrides aren't really applicable at a table level, so maybe we'd just have a separate class like AutoRepairParams that functioned similarly to CompactionParams
There was a problem hiding this comment.
👍 thanks for doing this. I imagine it could be useful to be able to configure things more granularly. I have some cases where we want to run full repair on a table, but never incremental (the main use case is analytics based where etl processes are loading a bunch of SSTables every few hours). Will come back to this as I review and experiment more with the PR, if there is a bunch of things that we would want configurable at table level maybe we could consider adding something like a RepairParams, otherwise maybe this is fine as is.
Sure, makes sense. We can finalize all the configuration granularity that we want at a table level and then change it accordingly.
There was a problem hiding this comment.
I incorporated this comment. Now, we have more granular configuration support as follows:
AND automated_repair_full = {'enabled': 'true'}
AND automated_repair_incremental = {'enabled': 'true'};
Please note: I had to use two separate configurations instead of merging due to the limitation of the CQL grammar, which does not allow nested configuration for DDL statements.
AND automated_repair = {'full': {'enabled': 'true'}, 'incremental': {'enabled': 'true'}}
There was a problem hiding this comment.
I think for a first pass this is ok, but eventually would like to see this apply more at a table label; Tables that have/are views would be skipped for incremental, and also those that have CDC enabled.
There was a problem hiding this comment.
Sure, we can provide a more granular table-level configuration with multiple configuration knobs.
There was a problem hiding this comment.
Done - please see above.
There was a problem hiding this comment.
Nit: there are some existing methods (getInt, getUUID) that are overloaded with an additional ifNull parameter, for consistency we should do the same for getLong.
| // this function will return the default value if the row doesn't have that column or the column data is null | |
| // This function is used to avoid the nullpointerexception | |
| public long getLongOrDefault(String column, long defaultValue) { | |
| if (!has(column)){ | |
| return defaultValue; | |
| } | |
| return getLong(column); | |
| } | |
| public long getLong(String column, long ifNull) { | |
| ByteBuffer bytes = data.get(column); | |
| return bytes == null ? ifNull : LongType.instance.compose(bytes); | |
| } |
There was a problem hiding this comment.
Nit: there are some existing methods (
getInt,getUUID) that are overloaded with an additionalifNullparameter, for consistency we should do the same for getLong.
ACK - will update it
There was a problem hiding this comment.
Is there precedence for using Lightweight transactions in internal cassandra stuff? Looking at how this is used, I see we check to see if the CAS insert was applied, but that just effects logging, so I think there is little harm in removing IF NOT EXISTS and just let it overwrite.
There was a problem hiding this comment.
Similar to INSERT_NEW_REPAIR_HISTORY, we can just do a blind delete here (no need for IF EXISTS), if it doesn't exist it'll just create a row tombstone. Given how this is only executed when we detect the host isn't in the ring seems fine to just do that.
There was a problem hiding this comment.
Fantastic to have these out of the gate 👍. We should add some docs to metrics.adoc to document these.
There was a problem hiding this comment.
Fantastic to have these out of the gate 👍. We should add some docs to
metrics.adocto document these.
ACK. Will extend the documentation
There was a problem hiding this comment.
Incorporated
There was a problem hiding this comment.
One thing worth discussing; by default I noticed that if I set:
auto_repair:
enabled: trueThat it doesn't actually run repairs because by default both full and incremental repair are disabled. Is this how we want this to work? I think it's a bit subjective and I don't have a good answer, but felt it was worth discussing.
I think two possible good defaults would be:
- Keep it as-is, if you want to enable repair, you should have to choose which of the repair options you would want enabled by default.
- Full repair is enabled with the above config.
I think maybe what we should just do is go with option one and add a commented section in cassandra.yaml that looks something like this:
# Documentation about auto repair goes here
# auto_repair:
# # Enables auto repair, defaults to false (disabled)
# enabled: true
# repair_type_overrides:
# full:
# # Enables auto full repairs, defaults to false
# enabled: true
# # ... all other various property defaults here
# incremental:
# enabled: falseThere was a problem hiding this comment.
IMO, by default, we should just enable full repair. For the IR, we should let an operator decide whether they want to enable or not.
There was a problem hiding this comment.
that seems sensible to me 👍. I'm not sure whether or not this would get too tricky, but I could see that the 'defaults' for overrides could be contextual based on the kind of repair, e.g. I would want a more frequent min_repair_interval_in_hours for Incremental Repair than for Full Repair. I think that may be too involved though, I think it's ok to just special case full repair to be enabled by default if you have auto_repair.enabled: true
There was a problem hiding this comment.
Done. I changed the min_repair_interval_in_hours to DurationSpec.IntSecondsBound so we can now go up to the second level of granularity.
There was a problem hiding this comment.
Small preference: It could be better to just put this on RepairType, can just define a AutoRepairState getAutoRepairState() on the RepairType enum.
There was a problem hiding this comment.
I like the way you did this. Seems like if I wanted to in theory add a new repair type to be scheduled (e.g. 'Preview repairs on repaired set', 'Preview repairs on unrepaired set', 'Paxos repairs'). I'd just have to add a new enum here, and then implement a AutoRepairState for it and add it to the AutoRepairStateFactory? Nice!
There was a problem hiding this comment.
Seems to be the case! That was incredibly easy!
git diff
diff --git a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairConfig.java b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairConfig.java
index 731d95a8dd..03d3b240c5 100644
--- a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairConfig.java
+++ b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairConfig.java
@@ -46,7 +46,7 @@ public class AutoRepairConfig implements Serializable
public volatile Options global_settings;
public enum RepairType
- {full, incremental}
+ {full, incremental, preview_repaired}
// repair_type_overrides overrides the global_settings for a specific repair type
public volatile Map<RepairType, Options> repair_type_overrides = new EnumMap<>(RepairType.class);
diff --git a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairState.java b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairState.java
index fc0281a7f0..ebda85c52a 100644
--- a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairState.java
+++ b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairState.java
@@ -283,6 +283,27 @@ public abstract class AutoRepairState implements ProgressListener
}
}
+class PreviewRepairedState extends AutoRepairState
+{
+ public PreviewRepairedState()
+ {
+ super(RepairType.preview_repaired);
+ }
+
+
+ @Override
+ public RepairRunnable getRepairRunnable(String keyspace, List<String> tables, Set<Range<Token>> ranges, boolean primaryRangeOnly)
+ {
+ RepairOption option = new RepairOption(RepairParallelism.PARALLEL, primaryRangeOnly, false, false,
+ AutoRepairService.instance.getAutoRepairConfig().getRepairThreads(repairType), ranges,
+ !ranges.isEmpty(), false, false, PreviewKind.REPAIRED, false, true, false, false);
+
+ option.getColumnFamilies().addAll(tables);
+
+ return getRepairRunnable(keyspace, option);
+ }
+}
+
class IncrementalRepairState extends AutoRepairState
{
public IncrementalRepairState()
diff --git a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairStateFactory.java b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairStateFactory.java
index 3812ed6e4d..8c3ba373db 100644
--- a/src/java/org/apache/cassandra/repair/autorepair/AutoRepairStateFactory.java
+++ b/src/java/org/apache/cassandra/repair/autorepair/AutoRepairStateFactory.java
@@ -30,6 +30,8 @@ public class AutoRepairStateFactory
return new FullRepairState();
case incremental:
return new IncrementalRepairState();
+ case preview_repaired:
+ return new PreviewRepairedState();
}
throw new IllegalArgumentException("Invalid repair type: " + repairType);INFO [Thread-12] 2024-06-20 14:02:32,047 RepairRunnable.java:324 - Starting repair command #11 (a5a3fffa-2f37-11ef-a8c2-e106f7a22c03), repairing keyspace easy_cass_stress with repair options (parallelism: parallel, primary range: true, incremental: false, job threads: 1, ColumnFamilies: [keyvalue], dataCenters: [], hosts: [], previewKind: REPAIRED, # of ranges: 1, pull r
epair: false, force repair: false, optimise streams: false, ignore unreplicated keyspaces: true, repairPaxos: false, paxosOnly: false)
There was a problem hiding this comment.
One thing I just stumbled into is that the formatting of multi-word config here is different than the yaml configuration, e.g. minrepairinternvalinhours in the yaml is min_repair_internval_in_hours. Can we update the nodetool config to match the yaml one?
There was a problem hiding this comment.
Sure, will do
There was a problem hiding this comment.
Suggestion: implement toString() to return all the options like a map, otherwise system_views.settings can't read these:
auto_repair.repair_type_overrides | {incremental=org.apache.cassandra.repair.autorepair.AutoRepairConfig$Options@64af73a1, preview_repaired=org.apache.cassandra.repair.autorepair.AutoRepairConfig$Options@2ae56cae}
There was a problem hiding this comment.
Should do something similar we did for other system keyspaces in CassandraRelevantProperties:
SYSTEM_AUTH_DEFAULT_RF("cassandra.system_auth.default_rf", "1"),
SYSTEM_TRACES_DEFAULT_RF("cassandra.system_traces.default_rf", "2"),
SYSTEM_DISTRIBUTED_DEFAULT_RF("cassandra.system_distributed.default_rf", "3"),which is used like:
KeyspaceParams.simple(Math.max(DEFAULT_RF, DatabaseDescriptor.getDefaultKeyspaceRF()))There was a problem hiding this comment.
although, i wonder if we should just leverage system_distributed instead of creating a separate keyspace? This may reduce some operator burden. e.g. in our cluster bring up one of the first things we do is alter these keyspaces to network topology strategy and we also have allowlist/blocklist for system keyspaces that we'd have to update.
There was a problem hiding this comment.
Done. Moved these two tables under system_distributed itself.
There was a problem hiding this comment.
Discussion point: We are currently passing false for optimiseStreams. This is a nice enhancement in the form of CASSANDRA-3200 which cuts down the amount of overstreaming when inconsistencies are found.
I'm not sure it has a lot of precedence for use, but it's been in tree for a long time. We've only started to look into rolling it out ourselves.
I think we should consider setting it to true here, or making it configurable somehow.
There was a problem hiding this comment.
Ok, changed it to true
There was a problem hiding this comment.
NIT: from a naming, having AUTOMATED_REPAIR: true vs DISABLED_AUTOMATED_REPAIR: false is easier for people to reason. Avoiding the double negatives and extra boolean logic for what people expect.
There was a problem hiding this comment.
ACK - will update it accordingly
There was a problem hiding this comment.
Since this is a global setting, I am not sure this is safe or necessary. Other keyspaces not in an island configuration to a single DC will not get repaired correctly (e.g., system_distributed, system_auth). For single keyspaces that are not replicated, there are already checks on a node if it is not replicated for a keyspace in checkNodeContainsKeyspaceReplica of AutoRepairUtils. Could simplify things a little bit and get rid of the pid in schema?
There was a problem hiding this comment.
Yeah, it is not necessary. I have removed it.
There was a problem hiding this comment.
this is kinda across all of these settings, but if look at Config.java . Can see now after 4.x that we for time settings instead of having _in_sec just pass a duration type. Same goes for using the mib options intead of _mb etc. Should probably stick with this kinda thing for most of the config options
There was a problem hiding this comment.
Updated the configs to match with the 4.x by using the DurationSpec.*
e91c424 to
ee68ae2
Compare
…SSANDRA_20180 Avoid returning MY_TURN when replicas are actively taking their turn
…ssandra_20498 Add toString to AutoRepairConfig.java
…ssandra_20531 Create AutoRepair executors only if enabled and a few other nits
…ssandra_20531_1 parens in next line for three Test files
Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
…geSplitter.java Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
Co-authored-by: Francisco Guerrero <frank.guerrero@gmail.com>
…ckport_apr14_apr22_2025 Backport changes from trunk_cep_37 between Apr14 - Apr22 2025 to 4.1 branch
…g large Cassandra tables
Patch by Jaydeepkumar Chovatia; Reviewed by Andy Tolbert, Chris Lohfink for CASSANDRA-20620
…hes quickly patch by Jaydeepkumar Chovatia; reviewed by Andy Tolbert for CASSANDRA-20622
…ssandra_20586_20620_20622 AutoRepair Port CASSANDRA-20586/CASSANDRA-20620/CASSANDRA-20622
patch by Jaydeepkumar Chovatia; reviewed by Bernardo Botella, Andrew Tolbert for CASSANDRA-20623
As per CASSANDRA-20045, we want to prevent full repair against disk full scenarios. Current protection exists only for incremental repair. This change updates the config name to not be incremental repair specific, using the Replace annotation. patch by Himanshu Jindal; reviewed by David Capwell, Jaydeepkumar Chovatia for CASSANDRA-20045
patch by Himanshu Jindal; reviewed by Jaydeepkumar Chovatia, Andy Tolbert for CASSANDRA-20048
…al repair bytes and expected vs. actual keyspaces patch by Jaydeepkumar Chovatia; reviewed by Chris Lohfink for CASSANDRA-20581
…623_20045_20048_20581 Merge CASSANDRA#20623 CASSANDRA#20045 CASSANDRA#20048 CASSANDRA#20581 from trunk to 4.1
patch by Paulo Motta; reviewed by Jaydeepkumar Chovatia for CASSANDRA-21115 (cherry picked from commit afa5512)
…n single-node test setup The new tests introduced by CASSANDRA-21115 call AutoRepairUtils.insertNewRepairHistory which uses a Paxos CAS (IF NOT EXISTS). system_distributed's default RF of 3 makes CAS fail in single-node unit-test setups with "Cannot achieve consistency level QUORUM". Trunk (5.1) does not hit this because its CMS/TCM-backed transactional metadata replaces the Paxos CAS path. On 4.1 we follow the existing convention used by AutoRepairUtilsTest, AutoRepairParameterizedTest, and AutoRepairServiceTest and set the RF to 1 in setupClass() before requireNetwork(). Verified locally: all 9 tests in AutoRepairTest now pass (0 failures). Co-authored-by: Cursor <cursoragent@cursor.com>
…o_repair_v2_on_4_1 CASSANDRA-21115: Fix initial auto-repairs skipped by too soon check (backport to auto_repair_v2_on_4_1)
Fixes checkstyle-test failure:
[ERROR] test/unit/.../AutoRepairTest.java:43:8:
Unused import - org.apache.cassandra.service.AutoRepairService. [UnusedImports]
Import was inadvertently pulled in during the CASSANDRA-21115 cherry-pick
conflict resolution (union of imports). It is used only on trunk (5.1),
where the @before setup() calls AutoRepairService.setup(); this branch does
not have that call.
Verified locally: `ant checkstyle checkstyle-test` clean; AutoRepairTest
still 9/9 passing.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ckstyle-followup/auto_repair_v2_on_4_1 CASSANDRA-21115 follow-up: fix checkstyle-test unused-import failure
CEP:
https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-37+Apache+Cassandra+Unified+Repair+Solution
Design doc:
https://docs.google.com/document/d/1CJWxjEi-mBABPMZ3VWJ9w5KavWfJETAGxfUpsViPcPo/edit?tab=t.0#heading=h.r112r46toau0