use of org.apache.cassandra.utils.concurrent.Condition in project cassandra by apache.
the class PreviewRepairTest method testFinishingNonIntersectingIncRepairDuringPreview.
/**
* Same as testFinishingIncRepairDuringPreview but the previewed range does not intersect the incremental repair
* so both preview and incremental repair should finish fine (without any mismatches)
*/
@Test
public void testFinishingNonIntersectingIncRepairDuringPreview() throws IOException, InterruptedException, ExecutionException {
ExecutorService es = Executors.newSingleThreadExecutor();
try (Cluster cluster = init(Cluster.build(2).withConfig(config -> config.with(GOSSIP).with(NETWORK)).start())) {
cluster.schemaChange("create table " + KEYSPACE + ".tbl (id int primary key, t int)");
insert(cluster.coordinator(1), 0, 100);
cluster.forEach((node) -> node.flush(KEYSPACE));
assertTrue(cluster.get(1).callOnInstance(repair(options(false, false))).success);
insert(cluster.coordinator(1), 100, 100);
cluster.forEach((node) -> node.flush(KEYSPACE));
// pause preview repair validation messages on node2 until node1 has finished
Condition previewRepairStarted = newOneTimeCondition();
Condition continuePreviewRepair = newOneTimeCondition();
DelayFirstRepairTypeMessageFilter filter = validationRequest(previewRepairStarted, continuePreviewRepair);
cluster.filters().outbound().verbs(VALIDATION_REQ.id).from(1).to(2).messagesMatching(filter).drop();
// get local ranges to repair two separate ranges:
List<String> localRanges = cluster.get(1).callOnInstance(() -> {
List<String> res = new ArrayList<>();
for (Range<Token> r : instance.getLocalReplicas(KEYSPACE).ranges()) res.add(r.left.getTokenValue() + ":" + r.right.getTokenValue());
return res;
});
assertEquals(2, localRanges.size());
Future<RepairResult> repairStatusFuture = es.submit(() -> cluster.get(1).callOnInstance(repair(options(true, false, localRanges.get(0)))));
// wait for node1 to start validation compaction
previewRepairStarted.await();
// this needs to finish before the preview repair is unpaused on node2
assertTrue(cluster.get(1).callOnInstance(repair(options(false, false, localRanges.get(1)))).success);
continuePreviewRepair.signalAll();
RepairResult rs = repairStatusFuture.get();
// repair should succeed
assertTrue(rs.success);
// and no mismatches
assertFalse(rs.wasInconsistent);
} finally {
es.shutdown();
}
}
use of org.apache.cassandra.utils.concurrent.Condition in project cassandra by apache.
the class ReadRepairTest method readRepairRTRangeMovementTest.
@Test
public void readRepairRTRangeMovementTest() throws Throwable {
ExecutorService es = Executors.newFixedThreadPool(1);
String key = "test1";
try (Cluster cluster = init(Cluster.build().withConfig(config -> config.with(Feature.GOSSIP, Feature.NETWORK).set("read_request_timeout", String.format("%dms", Integer.MAX_VALUE))).withTokenSupplier(TokenSupplier.evenlyDistributedTokens(4)).withNodeIdTopology(NetworkTopology.singleDcNetworkTopology(4, "dc0", "rack0")).withNodes(3).start())) {
cluster.schemaChange("CREATE TABLE distributed_test_keyspace.tbl (\n" + " key text,\n" + " column1 int,\n" + " PRIMARY KEY (key, column1)\n" + ") WITH CLUSTERING ORDER BY (column1 ASC)");
cluster.forEach(i -> i.runOnInstance(() -> open(KEYSPACE).getColumnFamilyStore("tbl").disableAutoCompaction()));
for (int i = 1; i <= 2; i++) {
cluster.get(i).executeInternal("DELETE FROM distributed_test_keyspace.tbl USING TIMESTAMP 50 WHERE key=?;", key);
cluster.get(i).executeInternal("DELETE FROM distributed_test_keyspace.tbl USING TIMESTAMP 80 WHERE key=? and column1 >= ? and column1 < ?;", key, 10, 100);
cluster.get(i).executeInternal("DELETE FROM distributed_test_keyspace.tbl USING TIMESTAMP 70 WHERE key=? and column1 = ?;", key, 30);
cluster.get(i).flush(KEYSPACE);
}
cluster.get(3).executeInternal("DELETE FROM distributed_test_keyspace.tbl USING TIMESTAMP 100 WHERE key=?;", key);
cluster.get(3).flush(KEYSPACE);
// pause the read until we have bootstrapped a new node below
Condition continueRead = newOneTimeCondition();
Condition readStarted = newOneTimeCondition();
cluster.filters().outbound().from(3).to(1, 2).verbs(READ_REQ.id).messagesMatching((i, i1, iMessage) -> {
try {
readStarted.signalAll();
continueRead.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return false;
}).drop();
Future<Object[][]> read = es.submit(() -> cluster.coordinator(3).execute("SELECT * FROM distributed_test_keyspace.tbl WHERE key=? and column1 >= ? and column1 <= ?", ALL, key, 20, 40));
readStarted.await();
IInstanceConfig config = cluster.newInstanceConfig();
config.set("auto_bootstrap", true);
cluster.bootstrap(config).startup();
continueRead.signalAll();
read.get();
} finally {
es.shutdown();
}
}
use of org.apache.cassandra.utils.concurrent.Condition in project cassandra by apache.
the class RepairBoundaryTest method singleTokenRangeRepair.
@Test
public void singleTokenRangeRepair() {
populate();
verify();
delete(cluster.get(1), 999, 1000);
delete(cluster.get(3), 1001);
cluster.get(2).runOnInstance(() -> {
try {
Map<String, String> options = new HashMap<>();
options.put("ranges", "999:1000");
options.put("incremental", "false");
Condition await = newOneTimeCondition();
instance.repair(KEYSPACE, options, of((tag, event) -> {
if (event.getType() == COMPLETE)
await.signalAll();
})).right.get();
await.await(1L, MINUTES);
} catch (Exception e) {
}
});
assertRows(c2Row(999, 1001, 1999, 2000, 3001), cluster.get(2).executeInternal(ALL));
}
use of org.apache.cassandra.utils.concurrent.Condition in project cassandra by apache.
the class ActiveRepairServiceTest method testQueueWhenPoolFullStrategy.
@Test
public void testQueueWhenPoolFullStrategy() throws InterruptedException {
// Using RepairCommandPoolFullStrategy.queue, the pool is initialized to
// repair_command_pool_size and any tasks which cannot immediately be
// serviced are queued
ExecutorService validationExecutor = ActiveRepairService.initializeExecutor(2, Config.RepairCommandPoolFullStrategy.queue);
try {
Condition allSubmitted = newOneTimeCondition();
Condition blocked = newOneTimeCondition();
CountDownLatch completed = new CountDownLatch(5);
ExecutorService testExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
if (i < 4)
testExecutor.submit(() -> validationExecutor.submit(new Task(blocked, completed)));
else
testExecutor.submit(() -> {
validationExecutor.submit(new Task(blocked, completed));
allSubmitted.signalAll();
});
}
// Make sure all tasks have been submitted to the validation executor
allSubmitted.await(TASK_SECONDS + 1, TimeUnit.SECONDS);
// Give the tasks we expect to execute immediately chance to be scheduled
Util.spinAssertEquals(2, ((ExecutorPlus) validationExecutor)::getActiveTaskCount, 1);
Util.spinAssertEquals(3, ((ExecutorPlus) validationExecutor)::getPendingTaskCount, 1);
// verify that we've reached a steady state with 2 threads actively processing and 3 queued tasks
Assert.assertEquals(2, ((ExecutorPlus) validationExecutor).getActiveTaskCount());
Assert.assertEquals(3, ((ExecutorPlus) validationExecutor).getPendingTaskCount());
// allow executing tests to complete
blocked.signalAll();
completed.await(TASK_SECONDS + 1, TimeUnit.SECONDS);
} finally {
// necessary to unregister mbean
validationExecutor.shutdownNow();
}
}
use of org.apache.cassandra.utils.concurrent.Condition in project cassandra by apache.
the class ActiveRepairServiceTest method testRejectWhenPoolFullStrategy.
@Test
public void testRejectWhenPoolFullStrategy() throws InterruptedException {
// Using RepairCommandPoolFullStrategy.reject, new threads are spawned up to
// repair_command_pool_size, at which point futher submissions are rejected
ExecutorService validationExecutor = ActiveRepairService.initializeExecutor(2, Config.RepairCommandPoolFullStrategy.reject);
try {
Condition blocked = newOneTimeCondition();
CountDownLatch completed = new CountDownLatch(2);
/*
* CASSANDRA-16685 This is a Java bug. When the underlying executor's queue is a SynchronousQueue, there can
* be races just after the ThreadPool's initialization while juggling and spinning up threads internally
* leading to false rejections. That queue needs a thread ready to pick up the task immediately or it will
* produce a reject exception upon 'offer()' method call on the executor's code. If the executor is still
* initializing or threads are not ready to take work you can get false rejections.
*
* A sleep has been added to give time to the thread pool to be ready to get work.
*/
Thread.sleep(250);
validationExecutor.submit(new Task(blocked, completed));
validationExecutor.submit(new Task(blocked, completed));
try {
validationExecutor.submit(new Task(blocked, completed));
Assert.fail("Expected task submission to be rejected");
} catch (RejectedExecutionException e) {
// expected
}
// allow executing tests to complete
blocked.signalAll();
completed.await(TASK_SECONDS + 1, TimeUnit.SECONDS);
// Submission is unblocked
Thread.sleep(250);
validationExecutor.submit(() -> {
});
} finally {
// necessary to unregister mbean
validationExecutor.shutdownNow();
}
}
Aggregations