From 0f78235b9450ed7a81313dd9c7b9d7dfa4b57ee3 Mon Sep 17 00:00:00 2001 From: Chris Hostetter Date: Tue, 15 Mar 2016 11:04:33 -0700 Subject: [PATCH] SOLR-8849: improve reproducibility in random order of chaosmonkey actions --- .../org/apache/solr/cloud/ChaosMonkey.java | 100 ++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java b/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java index 511fdf34b15..93a670ed434 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java @@ -85,6 +85,13 @@ public class ChaosMonkey { private List deadPool = new ArrayList<>(); private Thread monkeyThread; + + /** + * Our own Random, seeded from LuceneTestCase on init, so that we can produce a consistent sequence + * of random chaos regardless of if/how othe threads access the test randomness in other threads + * @see LuceneTestCase#random() + */ + private final Random chaosRandom; public ChaosMonkey(ZkTestServer zkServer, ZkStateReader zkStateReader, String collection, Map> shardToJetty, @@ -94,22 +101,22 @@ public class ChaosMonkey { this.zkServer = zkServer; this.zkStateReader = zkStateReader; this.collection = collection; + this.chaosRandom = new Random(LuceneTestCase.random().nextLong()); if (!MONKEY_ENABLED) { monkeyLog("The Monkey is Disabled and will not run"); return; } - Random random = LuceneTestCase.random(); if (EXP != null) { expireSessions = EXP; } else { - expireSessions = random.nextBoolean(); + expireSessions = chaosRandom.nextBoolean(); } if (CONN_LOSS != null) { causeConnectionLoss = CONN_LOSS; } else { - causeConnectionLoss = random.nextBoolean(); + causeConnectionLoss = chaosRandom.nextBoolean(); } @@ -326,7 +333,7 @@ public class ChaosMonkey { List sliceKeyList = new ArrayList<>(slices.size()); sliceKeyList.addAll(slices.keySet()); - String sliceName = sliceKeyList.get(LuceneTestCase.random().nextInt(sliceKeyList.size())); + String sliceName = sliceKeyList.get(chaosRandom.nextInt(sliceKeyList.size())); return sliceName; } @@ -365,8 +372,7 @@ public class ChaosMonkey { return null; } - Random random = LuceneTestCase.random(); - int chance = random.nextInt(10); + int chance = chaosRandom.nextInt(10); CloudJettyRunner cjetty; if (chance <= 5 && aggressivelyKillLeaders) { // if killLeader, really aggressively go after leaders @@ -374,7 +380,7 @@ public class ChaosMonkey { } else { // get random shard List jetties = shardToJetty.get(slice); - int index = random.nextInt(jetties.size()); + int index = chaosRandom.nextInt(jetties.size()); cjetty = jetties.get(index); ZkNodeProps leader = null; @@ -457,7 +463,7 @@ public class ChaosMonkey { monkeyLog("starting"); - if (LuceneTestCase.random().nextBoolean()) { + if (chaosRandom.nextBoolean()) { monkeyLog("Jetty will not commit on close"); DirectUpdateHandler2.commitOnClose = false; } @@ -474,43 +480,9 @@ public class ChaosMonkey { while (!stop) { try { - Random random = LuceneTestCase.random(); - Thread.sleep(random.nextInt(roundPauseUpperLimit)); - if (random.nextBoolean()) { - if (!deadPool.isEmpty()) { - int index = random.nextInt(deadPool.size()); - JettySolrRunner jetty = deadPool.get(index).jetty; - if (jetty.isStopped() && !ChaosMonkey.start(jetty)) { - continue; - } - //System.out.println("started on port:" + jetty.getLocalPort()); - deadPool.remove(index); - starts.incrementAndGet(); - continue; - } - } - - int rnd = random.nextInt(10); + Thread.sleep(chaosRandom.nextInt(roundPauseUpperLimit)); - if (expireSessions && rnd < EXPIRE_PERCENT) { - expireRandomSession(); - } - - if (causeConnectionLoss && rnd < CONLOSS_PERCENT) { - randomConnectionLoss(); - } - - CloudJettyRunner cjetty; - if (random.nextBoolean()) { - cjetty = stopRandomShard(); - } else { - cjetty = killRandomShard(); - } - if (cjetty == null) { - // we cannot kill - } else { - deadPool.add(cjetty); - } + causeSomeChaos(); } catch (InterruptedException e) { // @@ -549,6 +521,46 @@ public class ChaosMonkey { } } + /** + * causes some randomly selected chaos + */ + public void causeSomeChaos() throws Exception { + if (chaosRandom.nextBoolean()) { + if (!deadPool.isEmpty()) { + int index = chaosRandom.nextInt(deadPool.size()); + JettySolrRunner jetty = deadPool.get(index).jetty; + if (jetty.isStopped() && !ChaosMonkey.start(jetty)) { + return; + } + deadPool.remove(index); + starts.incrementAndGet(); + return; + } + } + + int rnd = chaosRandom.nextInt(10); + + if (expireSessions && rnd < EXPIRE_PERCENT) { + expireRandomSession(); + } + + if (causeConnectionLoss && rnd < CONLOSS_PERCENT) { + randomConnectionLoss(); + } + + CloudJettyRunner cjetty; + if (chaosRandom.nextBoolean()) { + cjetty = stopRandomShard(); + } else { + cjetty = killRandomShard(); + } + if (cjetty == null) { + // we cannot kill + } else { + deadPool.add(cjetty); + } + } + public int getStarts() { return starts.get(); }