azkaban-developers

added test case to mimick the deadlock that happened when TriggerScannerThread

1/28/2014 6:12:50 PM

Details

diff --git a/unit/java/azkaban/test/trigger/MockTriggerLoader.java b/unit/java/azkaban/test/trigger/MockTriggerLoader.java
new file mode 100644
index 0000000..67ef5c7
--- /dev/null
+++ b/unit/java/azkaban/test/trigger/MockTriggerLoader.java
@@ -0,0 +1,53 @@
+package azkaban.test.trigger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import azkaban.trigger.Trigger;
+import azkaban.trigger.TriggerLoader;
+import azkaban.trigger.TriggerLoaderException;
+
+public class MockTriggerLoader implements TriggerLoader {
+
+	Map<Integer, Trigger> triggers = new HashMap<Integer, Trigger>();
+	int triggerCount = 0;
+	
+	@Override
+	public synchronized void addTrigger(Trigger t) throws TriggerLoaderException {
+		t.setTriggerId(triggerCount);
+		t.setLastModifyTime(System.currentTimeMillis());
+		triggers.put(t.getTriggerId(), t);
+		triggerCount++;
+	}
+
+	@Override
+	public synchronized void removeTrigger(Trigger s) throws TriggerLoaderException {
+		triggers.remove(s);
+	}
+
+	@Override
+	public synchronized void updateTrigger(Trigger t) throws TriggerLoaderException {
+		t.setLastModifyTime(System.currentTimeMillis());
+		triggers.put(t.getTriggerId(), t);
+	}
+
+	@Override
+	public synchronized List<Trigger> loadTriggers() throws TriggerLoaderException {
+		return new ArrayList<Trigger>(triggers.values());
+	}
+
+	@Override
+	public synchronized Trigger loadTrigger(int triggerId) throws TriggerLoaderException {
+		return triggers.get(triggerId);
+	}
+
+	@Override
+	public List<Trigger> getUpdatedTriggers(long lastUpdateTime)
+			throws TriggerLoaderException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
diff --git a/unit/java/azkaban/test/trigger/TriggerManagerDeadlockTest.java b/unit/java/azkaban/test/trigger/TriggerManagerDeadlockTest.java
new file mode 100644
index 0000000..02c7cc1
--- /dev/null
+++ b/unit/java/azkaban/test/trigger/TriggerManagerDeadlockTest.java
@@ -0,0 +1,186 @@
+package azkaban.test.trigger;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import azkaban.alert.Alerter;
+import azkaban.executor.ExecutorLoader;
+import azkaban.executor.ExecutorManager;
+import azkaban.executor.ExecutorManagerException;
+import azkaban.test.execapp.MockExecutorLoader;
+import azkaban.trigger.Condition;
+import azkaban.trigger.ConditionChecker;
+import azkaban.trigger.Trigger;
+import azkaban.trigger.TriggerAction;
+import azkaban.trigger.TriggerLoader;
+import azkaban.trigger.TriggerLoaderException;
+import azkaban.trigger.TriggerManager;
+import azkaban.trigger.TriggerManagerException;
+import azkaban.trigger.builtin.CreateTriggerAction;
+import azkaban.utils.Props;
+
+public class TriggerManagerDeadlockTest {
+	
+	TriggerLoader loader;
+	TriggerManager triggerManager;
+	ExecutorLoader execLoader;
+	
+	@Before
+	public void setup() throws ExecutorManagerException, TriggerManagerException {
+		loader = new MockTriggerLoader();
+		Props props = new Props();
+		props.put("trigger.scan.interval", 1000);
+		props.put("executor.port", 12321);
+		execLoader = new MockExecutorLoader();
+		Map<String, Alerter> alerters = new HashMap<String, Alerter>();
+		ExecutorManager executorManager = new ExecutorManager(props, execLoader, alerters);
+		triggerManager = new TriggerManager(props, loader, executorManager);
+	}
+
+	@After
+	public void tearDown() {
+		
+	}
+	
+	@Test
+	public void deadlockTest() throws TriggerLoaderException, TriggerManagerException {
+		// this should well saturate it
+		for(int i = 0; i < 1000; i++) {
+			Trigger t = createSelfRegenTrigger();
+			loader.addTrigger(t);
+		}
+		// keep going and add more
+		for(int i = 0; i < 10000; i++) {
+			Trigger d = createDummyTrigger();
+			triggerManager.insertTrigger(d);
+			triggerManager.removeTrigger(d);
+		}
+		
+		System.out.println("No dead lock.");
+	}
+	
+	public class AlwaysOnChecker implements ConditionChecker {
+
+		public static final String type = "AlwaysOnChecker";
+		
+		private final String id;
+		private final Boolean alwaysOn;
+		
+		public AlwaysOnChecker(String id, Boolean alwaysOn) {
+			this.id = id;
+			this.alwaysOn = alwaysOn;
+		}
+		
+		@Override
+		public Object eval() {
+			// TODO Auto-generated method stub
+			return alwaysOn;
+		}
+
+		@Override
+		public Object getNum() {
+			// TODO Auto-generated method stub
+			return null;
+		}
+
+		@Override
+		public void reset() {
+			// TODO Auto-generated method stub
+			
+		}
+
+		@Override
+		public String getId() {
+			return id;
+		}
+
+		@Override
+		public String getType() {
+			// TODO Auto-generated method stub
+			return type;
+		}
+
+		@Override
+		public ConditionChecker fromJson(Object obj) throws Exception {
+			// TODO Auto-generated method stub
+			return null;
+		}
+
+		@Override
+		public Object toJson() {
+			// TODO Auto-generated method stub
+			return null;
+		}
+
+		@Override
+		public void stopChecker() {
+			// TODO Auto-generated method stub
+			
+		}
+
+		@Override
+		public void setContext(Map<String, Object> context) {
+			// TODO Auto-generated method stub
+			
+		}
+
+		@Override
+		public long getNextCheckTime() {
+			// TODO Auto-generated method stub
+			return 0;
+		}
+		
+	}
+	
+	private Trigger createSelfRegenTrigger() {
+		ConditionChecker alwaysOnChecker = new AlwaysOnChecker("alwaysOn", Boolean.TRUE);
+		String triggerExpr = alwaysOnChecker.getId() + ".eval()";
+		Map<String, ConditionChecker> triggerCheckers = new HashMap<String, ConditionChecker>();
+		triggerCheckers.put(alwaysOnChecker.getId(), alwaysOnChecker);
+		Condition triggerCond = new Condition(triggerCheckers, triggerExpr);
+		
+		TriggerAction triggerAct = new CreateTriggerAction("dummyTrigger", createDummyTrigger());
+		List<TriggerAction> actions = new ArrayList<TriggerAction>();
+		actions.add(triggerAct);
+		
+		ConditionChecker alwaysOffChecker = new AlwaysOnChecker("alwaysOff", Boolean.FALSE);
+		String expireExpr = alwaysOffChecker.getId() + ".eval()";
+		Map<String, ConditionChecker> expireCheckers = new HashMap<String, ConditionChecker>();
+		expireCheckers.put(alwaysOffChecker.getId(), alwaysOffChecker);
+		Condition expireCond = new Condition(expireCheckers, expireExpr);
+			
+		Trigger t = new Trigger("azkaban", "azkabanTest", triggerCond, expireCond, actions);
+		return t;
+	}
+
+	private Trigger createDummyTrigger() {
+		ConditionChecker alwaysOnChecker = new AlwaysOnChecker("alwaysOn", Boolean.TRUE);
+		String triggerExpr = alwaysOnChecker.getId() + ".eval()";
+		Map<String, ConditionChecker> triggerCheckers = new HashMap<String, ConditionChecker>();
+		triggerCheckers.put(alwaysOnChecker.getId(), alwaysOnChecker);
+		Condition triggerCond = new Condition(triggerCheckers, triggerExpr);
+		
+		TriggerAction triggerAct = new DummyTriggerAction("howdy!");
+		List<TriggerAction> actions = new ArrayList<TriggerAction>();
+		actions.add(triggerAct);
+		
+		ConditionChecker alwaysOffChecker = new AlwaysOnChecker("alwaysOff", Boolean.FALSE);
+		String expireExpr = alwaysOffChecker.getId() + ".eval()";
+		Map<String, ConditionChecker> expireCheckers = new HashMap<String, ConditionChecker>();
+		expireCheckers.put(alwaysOffChecker.getId(), alwaysOffChecker);
+		Condition expireCond = new Condition(expireCheckers, expireExpr);
+
+		Trigger t = new Trigger("azkaban", "azkabanTest", triggerCond, expireCond, actions);
+		return t;
+	}
+	
+}