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 {

Reply via email to