This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/master by this push:
new b368a87 KARAF-6037 Adding support to tolerate lock lost (#710)
b368a87 is described below
commit b368a87cba0f0e235d5dae72fd6c3559b50fb75c
Author: Kaja Mohideen <[email protected]>
AuthorDate: Sun Jan 6 10:43:38 2019 +0530
KARAF-6037 Adding support to tolerate lock lost (#710)
[KARAF-6037] Support several attempt on lock (especially for JDBC) before
shutdown of the active instance
---
.../org/apache/karaf/main/ConfigProperties.java | 6 ++
main/src/main/java/org/apache/karaf/main/Main.java | 34 +++++--
.../org/apache/karaf/main/MainLockingTest.java | 100 ++++++++++++++++++++-
3 files changed, 129 insertions(+), 11 deletions(-)
diff --git a/main/src/main/java/org/apache/karaf/main/ConfigProperties.java
b/main/src/main/java/org/apache/karaf/main/ConfigProperties.java
index d3084dc..f3b35e5 100644
--- a/main/src/main/java/org/apache/karaf/main/ConfigProperties.java
+++ b/main/src/main/java/org/apache/karaf/main/ConfigProperties.java
@@ -121,6 +121,8 @@ public class ConfigProperties {
public static final String PROPERTY_LOCK_DELAY = "karaf.lock.delay";
+ public static final String PROPERTY_LOCK_LOST_THRESHOLD =
"karaf.lock.lostThreshold";
+
private static final String PROPERTY_LOCK_LEVEL = "karaf.lock.level";
private static final String PROPERTY_LOCK_SLAVE_BLOCK =
"karaf.lock.slave.block";
@@ -157,6 +159,8 @@ public class ConfigProperties {
public static final String DEFAULT_LOCK_DELAY = "1000";
+ public static final String DEFAULT_LOCK_LOST_THRESHOLD = "0";
+
/**
* If a lock should be used before starting the runtime
@@ -175,6 +179,7 @@ public class ConfigProperties {
int lockStartLevel = 1;
int lockDefaultBootLevel = 1;
int lockDelay;
+ int lockLostThreshold;
boolean lockSlaveBlock = false;
int shutdownTimeout = 5 * 60 * 1000;
boolean useLock;
@@ -231,6 +236,7 @@ public class ConfigProperties {
System.setProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL,
Integer.toString(this.defaultStartLevel));
this.lockStartLevel =
Integer.parseInt(props.getProperty(PROPERTY_LOCK_LEVEL,
Integer.toString(lockStartLevel)));
this.lockDelay =
Integer.parseInt(props.getProperty(PROPERTY_LOCK_DELAY, DEFAULT_LOCK_DELAY));
+ this.lockLostThreshold =
Integer.parseInt(props.getProperty(PROPERTY_LOCK_LOST_THRESHOLD,
DEFAULT_LOCK_LOST_THRESHOLD));
this.lockSlaveBlock =
Boolean.parseBoolean(props.getProperty(PROPERTY_LOCK_SLAVE_BLOCK, "false"));
this.props.setProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL,
Integer.toString(lockDefaultBootLevel));
this.shutdownTimeout =
Integer.parseInt(props.getProperty(KARAF_SHUTDOWN_TIMEOUT,
Integer.toString(shutdownTimeout)));
diff --git a/main/src/main/java/org/apache/karaf/main/Main.java
b/main/src/main/java/org/apache/karaf/main/Main.java
index 09c4a95..e8c9f69 100644
--- a/main/src/main/java/org/apache/karaf/main/Main.java
+++ b/main/src/main/java/org/apache/karaf/main/Main.java
@@ -387,9 +387,15 @@ public class Main {
private void doMonitor() throws Exception {
lock = createLock();
File dataDir = new
File(System.getProperty(ConfigProperties.PROP_KARAF_DATA));
+ int livenessFailureCount = 0;
+ boolean locked = false;
while (!exiting) {
if (lock.lock()) {
- lockCallback.lockAcquired();
+ livenessFailureCount = 0;
+ if (!locked) {
+ lockCallback.lockAcquired();
+ locked = true;
+ }
for (;;) {
if (!dataDir.isDirectory()) {
LOG.info("Data directory does not exist anymore,
halting");
@@ -407,17 +413,31 @@ public class Main {
}
}
if (!exiting) {
- lockCallback.lockLost();
+ livenessFailureCount++;
+ if (livenessFailureCount > config.lockLostThreshold) {
+ locked = false;
+ lockCallback.lockLost();
+ }
} else {
lockCallback.stopShutdownThread();
}
} else {
- if (config.lockSlaveBlock) {
- LOG.log(Level.SEVERE, "Can't lock, and lock is exclusive");
- System.err.println("Can't lock (another instance is
running), and lock is exclusive");
- System.exit(5);
+ if (locked) {
+ livenessFailureCount++;
+ if (livenessFailureCount <= config.lockLostThreshold) {
+ lockCallback.waitingForLock();
+ } else {
+ locked = false;
+ lockCallback.lockLost();
+ }
} else {
- lockCallback.waitingForLock();
+ if (config.lockSlaveBlock) {
+ LOG.log(Level.SEVERE, "Can't lock, and lock is
exclusive");
+ System.err.println("Can't lock (another instance is
running), and lock is exclusive");
+ System.exit(5);
+ } else {
+ lockCallback.waitingForLock();
+ }
}
}
try {
diff --git a/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
b/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
index 6362d8e..8a12fd4 100644
--- a/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
+++ b/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
@@ -18,8 +18,11 @@
*/
package org.apache.karaf.main;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
import java.io.File;
import java.io.IOException;
+
import org.apache.karaf.main.util.Utils;
import org.junit.After;
import org.junit.Assert;
@@ -31,8 +34,6 @@ import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.startlevel.FrameworkStartLevel;
-import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
-
public class MainLockingTest {
private File home;
@@ -71,6 +72,7 @@ public class MainLockingTest {
System.clearProperty("karaf.lock");
System.clearProperty("karaf.lock.delay");
+ System.clearProperty("karaf.lock.lostThreshold");
System.clearProperty("karaf.lock.class");
System.clearProperty("karaf.pid.file");
@@ -90,12 +92,59 @@ public class MainLockingTest {
.build( withBnd() )
);
+ bundle.start();
+
+ Thread.sleep(1000);
+
+ FrameworkStartLevel sl = framework.adapt(FrameworkStartLevel.class);
+
+ MockLock lock = (MockLock) main.getLock();
+
+ Assert.assertEquals(100, sl.getStartLevel());
+
+ // simulate losing a lock
+ lock.setIsAlive(false);
+ lock.setLock(false);
+
+ // lets wait until the start level change is complete
+ lock.waitForLock();
+ Assert.assertEquals(1, sl.getStartLevel());
+
+ Thread.sleep(1000);
+
+ // get lock back
+ lock.setIsAlive(true);
+ lock.setLock(true);
+
+ Thread.sleep(1000);
+
+ // exit framework + lock loop
+ main.destroy();
+ }
+
+ @Test
+ public void testRetainsMasterLockOverFluctuation() throws Exception {
+ System.setProperty("karaf.lock.lostThreshold", "3");
+
+ String[] args = new String[0];
+ Main main = new Main(args);
+ main.launch();
+ Framework framework = main.getFramework();
+ String activatorName =
TimeoutShutdownActivator.class.getName().replace('.', '/') + ".class";
+ Bundle bundle = framework.getBundleContext().installBundle("foo",
+ TinyBundles.bundle()
+ .set( Constants.BUNDLE_ACTIVATOR,
TimeoutShutdownActivator.class.getName() )
+ .add( activatorName,
getClass().getClassLoader().getResourceAsStream( activatorName ) )
+ .build( withBnd() )
+ );
+
bundle.start();
FrameworkStartLevel sl = framework.adapt(FrameworkStartLevel.class);
MockLock lock = (MockLock) main.getLock();
+ Thread.sleep(1000);
Assert.assertEquals(100, sl.getStartLevel());
// simulate losing a lock
@@ -104,7 +153,7 @@ public class MainLockingTest {
// lets wait until the start level change is complete
lock.waitForLock();
- Assert.assertEquals(1, sl.getStartLevel());
+ Assert.assertEquals(100, sl.getStartLevel());
Thread.sleep(1000);
@@ -117,7 +166,50 @@ public class MainLockingTest {
// exit framework + lock loop
main.destroy();
- }
+ }
+
+ @Test
+ public void testLostMasterLockAfterThreshold() throws Exception {
+ System.setProperty("karaf.lock.lostThreshold", "3");
+
+ String[] args = new String[0];
+ Main main = new Main(args);
+ main.launch();
+ Framework framework = main.getFramework();
+ String activatorName =
TimeoutShutdownActivator.class.getName().replace('.', '/') + ".class";
+ Bundle bundle = framework.getBundleContext().installBundle("foo",
+ TinyBundles.bundle().set(Constants.BUNDLE_ACTIVATOR,
TimeoutShutdownActivator.class.getName())
+ .add(activatorName,
getClass().getClassLoader().getResourceAsStream(activatorName))
+ .build(withBnd()));
+
+ bundle.start();
+
+ FrameworkStartLevel sl = framework.adapt(FrameworkStartLevel.class);
+
+ MockLock lock = (MockLock) main.getLock();
+
+ Assert.assertEquals(100, sl.getStartLevel());
+
+ // simulate losing a lock
+ lock.setIsAlive(false);
+ lock.setLock(false);
+
+ // lets wait until the start level change is complete - thrice
+ // (lostThreshold)
+ Thread.sleep(5000);
+ Assert.assertEquals(1, sl.getStartLevel());
+
+ Thread.sleep(1000);
+
+ // get lock back
+ lock.setIsAlive(true);
+ lock.setLock(true);
+
+ Thread.sleep(1000);
+
+ // exit framework + lock loop
+ main.destroy();
+ }
@Test
public void testMasterWritesPid() throws Exception {