You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by st...@apache.org on 2021/09/14 12:26:17 UTC

[jackrabbit-oak] branch trunk updated: OAK-9568 : Support custom osgi LeaseFailureHandler (#364)

This is an automated email from the ASF dual-hosted git repository.

stefanegli pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 3446052  OAK-9568 : Support custom osgi LeaseFailureHandler (#364)
3446052 is described below

commit 3446052ad5f3316d75d4f05cc75e523dde9a1afd
Author: stefan-egli <st...@apache.org>
AuthorDate: Tue Sep 14 14:26:09 2021 +0200

    OAK-9568 : Support custom osgi LeaseFailureHandler (#364)
    
    * OAK-9535 related : trying to increase mvn memory
    
    * OAK-9568 : Support custom osgi LeaseFailureHandler
    
    * releng : avoid pushing Jenkinsfile changes
    
    * OAK-9568 : custom LeaseFailureHandler support test added
    
    * OAK-9568 : fixing failing test setups
    
    * OAK-9568 : moved LeaseFailureHandler to dedicated, exported, versioned package
    
    * OAK-9568 : LeaseFailureHandler added to bundle's Export-Package, plus IT added
---
 .../org/apache/jackrabbit/oak/osgi/OSGiIT.java     | 12 ++++
 oak-store-document/pom.xml                         |  1 +
 .../oak/plugins/document/ClusterNodeInfo.java      |  5 ++
 .../plugins/document/DocumentNodeStoreBuilder.java |  1 +
 .../plugins/document/DocumentNodeStoreService.java | 64 +++++++++++++++++-----
 .../{ => spi/lease}/LeaseFailureHandler.java       |  2 +-
 .../plugins/document/spi/lease/package-info.java   | 28 ++++++++++
 .../oak/plugins/document/ClusterNodeInfoTest.java  |  1 +
 .../document/DocumentNodeStoreServiceTest.java     | 50 +++++++++++++++++
 .../document/mongo/LeaseUpdateSocketTimeoutIT.java |  2 +-
 10 files changed, 150 insertions(+), 16 deletions(-)

diff --git a/oak-it-osgi/src/test/java/org/apache/jackrabbit/oak/osgi/OSGiIT.java b/oak-it-osgi/src/test/java/org/apache/jackrabbit/oak/osgi/OSGiIT.java
index c5d8e45..896b43e 100644
--- a/oak-it-osgi/src/test/java/org/apache/jackrabbit/oak/osgi/OSGiIT.java
+++ b/oak-it-osgi/src/test/java/org/apache/jackrabbit/oak/osgi/OSGiIT.java
@@ -34,6 +34,7 @@ import javax.inject.Inject;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -151,4 +152,15 @@ public class OSGiIT {
         System.out.println(repository.getDescriptor(Repository.REP_NAME_DESC));
     }
 
+    @Test
+    public void testLeaseFailureHandlerIsExported() {
+        LeaseFailureHandler handler = new LeaseFailureHandler() {
+            @Override
+            public void handleLeaseFailure() {
+                // this empty block is okay
+            }
+        };
+        context.registerService("org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler",
+                handler, null);
+    }
 }
diff --git a/oak-store-document/pom.xml b/oak-store-document/pom.xml
index d1d7238..0868820 100644
--- a/oak-store-document/pom.xml
+++ b/oak-store-document/pom.xml
@@ -50,6 +50,7 @@
             </Import-Package>
             <Export-Package>
               org.apache.jackrabbit.oak.plugins.document.spi,
+              org.apache.jackrabbit.oak.plugins.document.spi.lease
             </Export-Package>
             <Embed-Dependency>quartz;inline=org/quartz/CronExpression*|org/quartz/ValueSet*</Embed-Dependency>
           </instructions>
diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java
index eca976c..02679d2 100644
--- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java
@@ -43,6 +43,7 @@ import java.util.concurrent.TimeUnit;
 import com.google.common.base.Stopwatch;
 
 import org.apache.jackrabbit.oak.commons.StringUtils;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.plugins.document.util.SystemPropertySupplier;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.jetbrains.annotations.NotNull;
@@ -1120,6 +1121,10 @@ public class ClusterNodeInfo {
         return leaseEndTime;
     }
 
+    LeaseFailureHandler getLeaseFailureHandler() {
+        return leaseFailureHandler;
+    }
+
     public void setLeaseFailureHandler(LeaseFailureHandler leaseFailureHandler) {
         this.leaseFailureHandler = leaseFailureHandler;
     }
diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
index 7987dc8..8ada1f4 100644
--- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
@@ -48,6 +48,7 @@ import org.apache.jackrabbit.oak.plugins.document.persistentCache.CacheType;
 import org.apache.jackrabbit.oak.plugins.document.persistentCache.EvictionListener;
 import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCache;
 import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCacheStats;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.plugins.document.util.RevisionsKey;
 import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
 import org.apache.jackrabbit.oak.spi.blob.AbstractBlobStore;
diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
index 1c36fc2..758c0ab 100644
--- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
@@ -39,6 +39,7 @@ import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -66,6 +67,7 @@ import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentNodeStoreBu
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStoreMetrics;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentNodeStoreBuilder;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.commit.ObserverTracker;
 import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
@@ -97,6 +99,7 @@ import org.apache.jackrabbit.oak.spi.state.RevisionGC;
 import org.apache.jackrabbit.oak.spi.state.RevisionGCMBean;
 import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker;
 import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Tracker;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
@@ -402,9 +405,34 @@ public class DocumentNodeStoreService {
             nodeStore, props);
     }
 
+    private LeaseFailureHandler createDefaultLeaseFailureHandler() {
+        return new LeaseFailureHandler() {
+            @Override
+            public void handleLeaseFailure() {
+                Bundle bundle = context.getBundleContext().getBundle();
+                String bundleName = bundle.getSymbolicName();
+                try {
+                    // plan A: try stopping oak-store-document
+                    log.error("handleLeaseFailure: stopping {}...", bundleName);
+                    bundle.stop(Bundle.STOP_TRANSIENT);
+                    log.error("handleLeaseFailure: stopped {}.", bundleName);
+                    // plan A worked, perfect!
+                } catch (BundleException e) {
+                    log.error("handleLeaseFailure: exception while stopping " + bundleName + ": " + e, e);
+                    // plan B: stop only DocumentNodeStoreService (to stop the background threads)
+                    log.error("handleLeaseFailure: stopping DocumentNodeStoreService...");
+                    context.disableComponent(DocumentNodeStoreService.class.getName());
+                    log.error("handleLeaseFailure: stopped DocumentNodeStoreService");
+                    // plan B succeeded.
+                }
+            }
+        };
+    }
+
     private void configureBuilder(DocumentNodeStoreBuilder<?> builder) {
         String persistentCache = resolvePath(config.persistentCache(), DEFAULT_PERSISTENT_CACHE);
         String journalCache = resolvePath(config.journalCache(), DEFAULT_JOURNAL_CACHE);
+        final Tracker<LeaseFailureHandler> leaseFailureHandlerTracker = whiteboard.track(LeaseFailureHandler.class);
         builder.setStatisticsProvider(statisticsProvider).
                 setExecutor(executor).
                 memoryCacheSize(config.cache() * MB).
@@ -420,23 +448,31 @@ public class DocumentNodeStoreService {
                 setLeaseCheckMode(ClusterNodeInfo.DEFAULT_LEASE_CHECK_DISABLED ? LeaseCheckMode.DISABLED : LeaseCheckMode.valueOf(config.leaseCheckMode())).
                 setLeaseFailureHandler(new LeaseFailureHandler() {
 
+                    private final LeaseFailureHandler defaultLeaseFailureHandler = createDefaultLeaseFailureHandler();
+
                     @Override
                     public void handleLeaseFailure() {
-                        Bundle bundle = context.getBundleContext().getBundle();
-                        String bundleName = bundle.getSymbolicName();
+                        boolean handled = false;
                         try {
-                            // plan A: try stopping oak-store-document
-                            log.error("handleLeaseFailure: stopping {}...", bundleName);
-                            bundle.stop(Bundle.STOP_TRANSIENT);
-                            log.error("handleLeaseFailure: stopped {}.", bundleName);
-                            // plan A worked, perfect!
-                        } catch (BundleException e) {
-                            log.error("handleLeaseFailure: exception while stopping " + bundleName + ": " + e, e);
-                            // plan B: stop only DocumentNodeStoreService (to stop the background threads)
-                            log.error("handleLeaseFailure: stopping DocumentNodeStoreService...");
-                            context.disableComponent(DocumentNodeStoreService.class.getName());
-                            log.error("handleLeaseFailure: stopped DocumentNodeStoreService");
-                            // plan B succeeded.
+                            if (leaseFailureHandlerTracker != null) {
+                                final List<LeaseFailureHandler> handlers = leaseFailureHandlerTracker.getServices();
+                                if (handlers != null && handlers.size() > 0) {
+                                    // go through the list, but only execute the first one
+                                    for (LeaseFailureHandler handler : handlers) {
+                                        if (handler != null) {
+                                            log.info("handleLeaseFailure: invoking handler " + handler);
+                                            handler.handleLeaseFailure();
+                                            handled = true;
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                        } finally {
+                            if (!handled) {
+                                log.info("handleLeaseFailure: invoking default handler");
+                                defaultLeaseFailureHandler.handleLeaseFailure();
+                            }
                         }
                     }
                 }).
diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LeaseFailureHandler.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/LeaseFailureHandler.java
similarity index 96%
rename from oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LeaseFailureHandler.java
rename to oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/LeaseFailureHandler.java
index b348845..8f2b36e 100644
--- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LeaseFailureHandler.java
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/LeaseFailureHandler.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.plugins.document;
+package org.apache.jackrabbit.oak.plugins.document.spi.lease;
 
 /**
  * A LeaseFailureHandler can be provided to the DocumentMK.Builder 
diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/package-info.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/package-info.java
new file mode 100644
index 0000000..d6a9a4e
--- /dev/null
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/spi/lease/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Provides extensibility with regards to DocumentNodeStore leases.
+ *
+ * @version 1.0.0
+ */
+@Version("1.0.0")
+package org.apache.jackrabbit.oak.plugins.document.spi.lease;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java
index cfba4d9..0f3ed5f 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java
@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
 
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.junit.After;
 import org.junit.Before;
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
index 999659b..2292ff0 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugins.document;
 import java.io.File;
 import java.lang.reflect.Field;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 
 import com.google.common.collect.Maps;
@@ -28,6 +29,7 @@ import org.apache.commons.io.FilenameUtils;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStoreTestHelper;
 import org.apache.jackrabbit.oak.plugins.document.spi.JournalPropertyService;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
@@ -260,6 +262,54 @@ public class DocumentNodeStoreServiceTest {
     }
 
     @Test
+    public void defaultLeaseFailureHandlerCheck() {
+        Map<String, Object> config = newConfig(repoHome);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
+        DocumentNodeStore dns = context.getService(DocumentNodeStore.class);
+        assertNotNull(dns);
+        ClusterNodeInfo clusterInfo = dns.getClusterInfo();
+        LeaseFailureHandler leaseFailureHandler = clusterInfo.getLeaseFailureHandler();
+        assertNotNull(leaseFailureHandler);
+        try {
+            leaseFailureHandler.handleLeaseFailure();
+            fail("default leaseFailureHandler should call bundle.stop(), which is not supported");
+        } catch (UnsupportedOperationException u) {
+            // the default LeaseFailureHandler should fail, as it calls bundle.stop()
+            // and that is not supported (throws UnsupportedOperationExceptino)
+        }
+    }
+
+    @Test
+    public void customLeaseFailureHandlerCheck() {
+        final AtomicInteger counter = new AtomicInteger(0);
+        LeaseFailureHandler customLeaseFailureHandler = new LeaseFailureHandler() {
+            @Override
+            public void handleLeaseFailure() {
+                counter.incrementAndGet();
+            }
+        };
+        context.registerService(LeaseFailureHandler.class, customLeaseFailureHandler);
+        Map<String, Object> config = newConfig(repoHome);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
+        DocumentNodeStore dns = context.getService(DocumentNodeStore.class);
+        assertNotNull(dns);
+        ClusterNodeInfo clusterInfo = dns.getClusterInfo();
+        LeaseFailureHandler leaseFailureHandler = clusterInfo.getLeaseFailureHandler();
+        assertNotNull(leaseFailureHandler);
+        assertEquals(0, counter.get());
+        for(int i = 0; i < 10; i++) {
+            // now the custom LeaseFailureHandler should be used,
+            // which just increments a counter.
+            // but more importantly: it should no longer fail,
+            // as does the default LeaseFailureHandler
+            leaseFailureHandler.handleLeaseFailure();
+            assertEquals(i + 1, counter.get());
+        }
+    }
+
+    @Test
     public void revisionGcDelayFactorCheckMode() {
         Map<String, Object> config = newConfig(repoHome);
         double delayFactor = 0.25;
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/LeaseUpdateSocketTimeoutIT.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/LeaseUpdateSocketTimeoutIT.java
index 3c61b1a..83f3b97 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/LeaseUpdateSocketTimeoutIT.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/LeaseUpdateSocketTimeoutIT.java
@@ -26,9 +26,9 @@ import org.apache.jackrabbit.oak.commons.CIHelper;
 import org.apache.jackrabbit.oak.plugins.document.ClusterNodeInfo;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
-import org.apache.jackrabbit.oak.plugins.document.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.plugins.document.SimpleRecoveryHandler;
 import org.apache.jackrabbit.oak.plugins.document.TestUtils;
+import org.apache.jackrabbit.oak.plugins.document.spi.lease.LeaseFailureHandler;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.junit.After;
 import org.junit.Before;