-
Notifications
You must be signed in to change notification settings - Fork 4.1k
CASSANDRA-21552 Force repair should ignore min_repair_interval #5004
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: cassandra-5.0
Are you sure you want to change the base?
Changes from all commits
371c468
d4c3d53
7716482
1c3460f
1c73369
4e693a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
|
|
||
| import org.junit.Before; | ||
| import org.junit.BeforeClass; | ||
|
|
@@ -29,16 +30,22 @@ | |
| import org.apache.cassandra.config.DatabaseDescriptor; | ||
| import org.apache.cassandra.config.DurationSpec; | ||
| import org.apache.cassandra.cql3.CQLTester; | ||
| import org.apache.cassandra.cql3.QueryProcessor; | ||
| import org.apache.cassandra.db.Keyspace; | ||
| import org.apache.cassandra.exceptions.ConfigurationException; | ||
| import org.apache.cassandra.schema.KeyspaceMetadata; | ||
| import org.apache.cassandra.schema.KeyspaceParams; | ||
| import org.apache.cassandra.schema.ReplicationParams; | ||
| import org.apache.cassandra.schema.SchemaConstants; | ||
| import org.apache.cassandra.repair.autorepair.AutoRepairConfig.RepairType; | ||
| import org.apache.cassandra.schema.SchemaTestUtil; | ||
| import org.apache.cassandra.schema.SystemDistributedKeyspace; | ||
| import org.apache.cassandra.service.StorageService; | ||
| import org.apache.cassandra.utils.FBUtilities; | ||
|
|
||
| import static org.apache.cassandra.Util.setAutoRepairEnabled; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertFalse; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| /** | ||
|
|
@@ -159,4 +166,136 @@ else if (ks.getName().equals(ksname2)) | |
| } | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testForceRepairBypassesMinRepairInterval() | ||
| { | ||
| RepairType repairType = RepairType.FULL; | ||
| UUID myId = StorageService.instance.getHostIdForEndpoint(FBUtilities.getBroadcastAddressAndPort()); | ||
| long now = System.currentTimeMillis(); | ||
|
|
||
| // Truncate history table to start fresh | ||
| QueryProcessor.executeInternal(String.format( | ||
| "TRUNCATE %s.%s", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY)); | ||
|
|
||
| // Seed auto_repair_history directly with a recently completed repair and force_repair=true | ||
| QueryProcessor.executeInternal(String.format( | ||
| "INSERT INTO %s.%s (repair_type, host_id, repair_start_ts, repair_finish_ts, force_repair) VALUES (?, ?, ?, ?, true)", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY), | ||
| repairType.toString(), myId, new java.util.Date(now - 1000), new java.util.Date(now)); | ||
|
|
||
| // Verify force repair is detected | ||
| assertTrue(AutoRepairUtils.isForceRepairSetForNode(repairType, myId)); | ||
|
|
||
| AutoRepairConfig config = DatabaseDescriptor.getAutoRepairConfig(); | ||
| AutoRepairState repairState = RepairType.getAutoRepairState(repairType, config); | ||
|
|
||
| // Even though min_repair_interval hasn't passed, shouldSkipRepairDueToInterval returns false | ||
| // because force repair is set | ||
| assertFalse(AutoRepair.instance.shouldSkipRepairDueToInterval(repairType, repairState, config, myId)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testShouldSkipRepairDueToIntervalWithoutForceRepair() | ||
| { | ||
| RepairType repairType = RepairType.FULL; | ||
| UUID myId = StorageService.instance.getHostIdForEndpoint(FBUtilities.getBroadcastAddressAndPort()); | ||
| long now = System.currentTimeMillis(); | ||
|
|
||
| // Truncate history table to start fresh | ||
| QueryProcessor.executeInternal(String.format( | ||
| "TRUNCATE %s.%s", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY)); | ||
|
|
||
| // Seed auto_repair_history directly with a recently completed repair and force_repair=false | ||
| QueryProcessor.executeInternal(String.format( | ||
| "INSERT INTO %s.%s (repair_type, host_id, repair_start_ts, repair_finish_ts, force_repair) VALUES (?, ?, ?, ?, false)", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY), | ||
| repairType.toString(), myId, new java.util.Date(now - 1000), new java.util.Date(now)); | ||
|
|
||
| // Verify force repair is NOT set | ||
| assertFalse(AutoRepairUtils.isForceRepairSetForNode(repairType, myId)); | ||
|
|
||
| AutoRepairConfig config = DatabaseDescriptor.getAutoRepairConfig(); | ||
| AutoRepairState repairState = RepairType.getAutoRepairState(repairType, config); | ||
|
|
||
| // Without force repair, should skip because min_repair_interval hasn't passed | ||
| assertTrue(AutoRepair.instance.shouldSkipRepairDueToInterval(repairType, repairState, config, myId)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testIsForceRepairSetForNodeReturnsFalseWhenNotSet() | ||
| { | ||
| RepairType repairType = RepairType.FULL; | ||
| UUID myId = StorageService.instance.getHostIdForEndpoint(FBUtilities.getBroadcastAddressAndPort()); | ||
| long now = System.currentTimeMillis(); | ||
|
|
||
| // Truncate history table to start fresh | ||
| QueryProcessor.executeInternal(String.format( | ||
| "TRUNCATE %s.%s", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY)); | ||
|
|
||
| // Seed auto_repair_history directly without setting force_repair | ||
| QueryProcessor.executeInternal(String.format( | ||
| "INSERT INTO %s.%s (repair_type, host_id, repair_start_ts, repair_finish_ts) VALUES (?, ?, ?, ?)", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY), | ||
| repairType.toString(), myId, new java.util.Date(now - 1000), new java.util.Date(now)); | ||
|
|
||
| // Verify force repair is not set | ||
| assertFalse(AutoRepairUtils.isForceRepairSetForNode(repairType, myId)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testIsForceRepairSetForNodeReturnsFalseWhenNoHistory() | ||
| { | ||
| RepairType repairType = RepairType.FULL; | ||
| UUID myId = StorageService.instance.getHostIdForEndpoint(FBUtilities.getBroadcastAddressAndPort()); | ||
|
|
||
| // Truncate history table to start fresh | ||
| QueryProcessor.executeInternal(String.format( | ||
| "TRUNCATE %s.%s", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY)); | ||
|
|
||
| // Verify force repair is not set when no history exists | ||
| assertFalse(AutoRepairUtils.isForceRepairSetForNode(repairType, myId)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testForceRepairBypassesMinRepairIntervalEndToEnd() | ||
| { | ||
| RepairType repairType = RepairType.FULL; | ||
| UUID myId = StorageService.instance.getHostIdForEndpoint(FBUtilities.getBroadcastAddressAndPort()); | ||
| long now = System.currentTimeMillis(); | ||
|
|
||
| DurationSpec.LongSecondsBound repairTaskMinDuration = DatabaseDescriptor.getAutoRepairConfig().getRepairTaskMinDuration(); | ||
| // Ensure repair tasks don't artificially sleep | ||
| DatabaseDescriptor.getAutoRepairConfig().setRepairTaskMinDuration("0s"); | ||
|
|
||
|
driftx marked this conversation as resolved.
|
||
| // Truncate history table to start fresh | ||
| QueryProcessor.executeInternal(String.format( | ||
| "TRUNCATE %s.%s", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY)); | ||
|
|
||
| // Insert a recently completed repair so tooSoonToRunRepair would normally block | ||
| QueryProcessor.executeInternal(String.format( | ||
| "INSERT INTO %s.%s (repair_type, host_id, repair_start_ts, repair_finish_ts, force_repair) VALUES (?, ?, ?, ?, true)", | ||
| SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, SystemDistributedKeyspace.AUTO_REPAIR_HISTORY), | ||
| repairType.toString(), myId, new java.util.Date(now - 1000), new java.util.Date(now)); | ||
|
|
||
| // Record the finish time before repair runs | ||
| long finishTimeBefore = AutoRepairUtils.getLastRepairTimeForNode(repairType, myId); | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pleae verify that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // Invoke the full repair path; with force repair set, the interval check is bypassed | ||
| AutoRepair.instance.repair(repairType); | ||
|
driftx marked this conversation as resolved.
|
||
|
|
||
| // Verify that repair_finish_ts has advanced, proving repair actually ran | ||
| long finishTimeAfter = AutoRepairUtils.getLastRepairTimeForNode(repairType, myId); | ||
| assertTrue("repair_finish_ts should advance after force repair runs, but was " | ||
| + finishTimeBefore + " -> " + finishTimeAfter, | ||
| finishTimeAfter > finishTimeBefore); | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pleae verify that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // Restore original value | ||
| DatabaseDescriptor.getAutoRepairConfig().setRepairTaskMinDuration(repairTaskMinDuration.toString()); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.