You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by st...@apache.org on 2015/11/10 09:36:22 UTC
svn commit: r1713589 - in /sling/trunk/bundles/extensions/discovery:
base/src/test/java/org/apache/sling/discovery/base/its/
impl/src/main/java/org/apache/sling/discovery/impl/
impl/src/main/resources/OSGI-INF/metatype/
impl/src/test/java/org/apache/sl...
Author: stefanegli
Date: Tue Nov 10 08:36:21 2015
New Revision: 1713589
URL: http://svn.apache.org/viewvc?rev=1713589&view=rev
Log:
SLING-5251 : add config parameter useSyncTokenService that enables usage of a SyncTokenService if available. This increases synchronization QoS when for topology changes
Added:
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java (with props)
Modified:
sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractTopologyEventTest.java
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
sling/trunk/bundles/extensions/discovery/impl/src/main/resources/OSGI-INF/metatype/metatype.properties
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/FullJR2VirtualInstanceBuilder.java
Modified: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractTopologyEventTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractTopologyEventTest.java?rev=1713589&r1=1713588&r2=1713589&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractTopologyEventTest.java (original)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractTopologyEventTest.java Tue Nov 10 08:36:21 2015
@@ -33,6 +33,7 @@ import org.apache.sling.discovery.base.i
import org.apache.sling.discovery.base.its.setup.mock.AssertingTopologyEventListener;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -152,7 +153,12 @@ public abstract class AbstractTopologyEv
assertEquals(0, l1.getUnexpectedCount());
assertEquals(2, l1.getEvents().size());
assertEquals(0, l2.getUnexpectedCount());
- assertEquals(1, l2.getEvents().size());
+ // with the switch to use the SyncTokenService in discovery.impl tests
+ // by default, the following check is no longer possible:
+// assertEquals(1, l2.getEvents().size());
+ // (this is due to the fact that synching requires some more time
+ // and we're a bit early at this stage - the below same check
+ // is the only one that we can do here really - and that one must work)
assertEquals(0, l1Two.getUnexpectedCount());
assertEquals(2, l1Two.getEvents().size());
Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java?rev=1713589&r1=1713588&r2=1713589&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java Tue Nov 10 08:36:21 2015
@@ -49,6 +49,12 @@ public class Config implements BaseConfi
/** resource used to keep instance information such as last heartbeat, properties, incoming announcements **/
private static final String CLUSTERINSTANCES_RESOURCE = "clusterInstances";
+ /** resource used to store the sync tokens as part of a topology change **/
+ private static final String SYNC_TOKEN_RESOURCE = "syncTokens";
+
+ /** resource used to store the clusterNodeIds to slingIds map **/
+ private static final String ID_MAP_RESOURCE = "idMap";
+
/** resource used to keep the currently established view **/
private static final String ESTABLISHED_VIEW_RESOURCE = "establishedView";
@@ -168,6 +174,13 @@ public class Config implements BaseConfi
@Property
private static final String BACKOFF_STABLE_FACTOR = "backoffStableFactor";
private static final int DEFAULT_BACKOFF_STABLE_FACTOR = 5;
+
+ /**
+ * when set to true and the syncTokenService (of discovery.commons) is available,
+ * then it is used
+ */
+ @Property(boolValue=true)
+ private static final String USE_SYNC_TOKEN_SERVICE_ENABLED = "useSyncTokenService";
private String leaderElectionRepositoryDescriptor ;
@@ -207,6 +220,12 @@ public class Config implements BaseConfi
/** the maximum backoff factor to be used for stable connectors **/
private int backoffStableFactor = DEFAULT_BACKOFF_STABLE_FACTOR;
+ /**
+ * when set to true and the syncTokenService (of discovery.commons) is available,
+ * then it is used.
+ */
+ private boolean useSyncTokenService = true;
+
@Activate
protected void activate(final Map<String, Object> properties) {
logger.debug("activate: config activated.");
@@ -319,6 +338,8 @@ public class Config implements BaseConfi
DEFAULT_BACKOFF_STANDBY_FACTOR);
backoffStableFactor = PropertiesUtil.toInteger(properties.get(BACKOFF_STABLE_FACTOR),
DEFAULT_BACKOFF_STABLE_FACTOR);
+
+ useSyncTokenService = PropertiesUtil.toBoolean(properties.get(USE_SYNC_TOKEN_SERVICE_ENABLED), true);
}
/**
@@ -534,12 +555,12 @@ public class Config implements BaseConfi
@Override
public String getSyncTokenPath() {
- return getDiscoveryResourcePath() + "/synctokens";
+ return getDiscoveryResourcePath() + SYNC_TOKEN_RESOURCE;
}
@Override
public String getIdMapPath() {
- return getDiscoveryResourcePath() + "/idmaps";
+ return getDiscoveryResourcePath() + ID_MAP_RESOURCE;
}
@Override
@@ -552,4 +573,8 @@ public class Config implements BaseConfi
return 1000;
}
+ public boolean useSyncTokenService() {
+ return useSyncTokenService;
+ }
+
}
Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java?rev=1713589&r1=1713588&r2=1713589&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java Tue Nov 10 08:36:21 2015
@@ -26,6 +26,7 @@ import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -51,8 +52,8 @@ import org.apache.sling.discovery.Discov
import org.apache.sling.discovery.InstanceDescription;
import org.apache.sling.discovery.PropertyProvider;
import org.apache.sling.discovery.TopologyEvent;
-import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.TopologyEvent.Type;
+import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.base.commons.BaseDiscoveryService;
import org.apache.sling.discovery.base.commons.ClusterViewService;
import org.apache.sling.discovery.base.commons.DefaultTopologyView;
@@ -67,6 +68,7 @@ import org.apache.sling.discovery.common
import org.apache.sling.discovery.commons.providers.base.ViewStateManagerFactory;
import org.apache.sling.discovery.commons.providers.spi.ClusterSyncService;
import org.apache.sling.discovery.commons.providers.spi.LocalClusterView;
+import org.apache.sling.discovery.commons.providers.spi.base.SyncTokenService;
import org.apache.sling.discovery.commons.providers.util.PropertyNameHelper;
import org.apache.sling.discovery.commons.providers.util.ResourceHelper;
import org.apache.sling.discovery.impl.cluster.ClusterViewServiceImpl;
@@ -89,6 +91,25 @@ public class DiscoveryServiceImpl extend
private final static Logger logger = LoggerFactory.getLogger(DiscoveryServiceImpl.class);
+ /**
+ * This ClusterSyncService just 'passes the call through', ie it doesn't actually
+ * do anything in sync but just calls callback.run() immediately. It therefore
+ * also doesn't have to do anything on cancelling.
+ */
+ private static final ClusterSyncService PASS_THROUGH_CLUSTER_SYNC_SERVICE = new ClusterSyncService() {
+
+ @Override
+ public void sync(BaseTopologyView view, Runnable callback) {
+ logger.debug("sync: no syncToken applicable");
+ callback.run();
+ }
+
+ @Override
+ public void cancelSync() {
+ // cancelling not applicable
+ }
+ };
+
@Reference
private SlingSettingsService settingsService;
@@ -131,6 +152,9 @@ public class DiscoveryServiceImpl extend
@Reference
private Config config;
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
+ private SyncTokenService syncTokenService;
+
/** the slingId of the local instance **/
private String slingId;
@@ -138,8 +162,10 @@ public class DiscoveryServiceImpl extend
private ViewStateManager viewStateManager;
- private ReentrantLock viewStateManagerLock;
+ private final ReentrantLock viewStateManagerLock = new ReentrantLock();
+ private final List<TopologyEventListener> pendingListeners = new LinkedList<TopologyEventListener>();
+
private TopologyEventListener changePropagationListener = new TopologyEventListener() {
public void handleTopologyEvent(TopologyEvent event) {
@@ -160,7 +186,8 @@ public class DiscoveryServiceImpl extend
HeartbeatHandler heartbeatHandler,
SlingSettingsService settingsService,
Scheduler scheduler,
- Config config) {
+ Config config,
+ SyncTokenService syncTokenServiceOrNull) {
DiscoveryServiceImpl discoService = new DiscoveryServiceImpl();
discoService.resourceResolverFactory = resourceResolverFactory;
discoService.announcementRegistry = announcementRegistry;
@@ -170,25 +197,11 @@ public class DiscoveryServiceImpl extend
discoService.settingsService = settingsService;
discoService.scheduler = scheduler;
discoService.config = config;
+ discoService.syncTokenService = syncTokenServiceOrNull;
return discoService;
}
public DiscoveryServiceImpl() {
- viewStateManagerLock = new ReentrantLock();
- final ClusterSyncService consistencyService = new ClusterSyncService() {
-
- @Override
- public void sync(BaseTopologyView view, Runnable callback) {
- logger.debug("sync: no syncToken applicable");
- callback.run();
- }
-
- @Override
- public void cancelSync() {
- // cancelling not applicable
- }
- };
- viewStateManager = ViewStateManagerFactory.newViewStateManager(viewStateManagerLock, consistencyService);
}
protected void registerMBean(BundleContext bundleContext) {
@@ -248,6 +261,19 @@ public class DiscoveryServiceImpl extend
slingId = settingsService.getSlingId();
+ final ClusterSyncService clusterSyncService;
+ if (!config.useSyncTokenService()) {
+ logger.info("activate: useSyncTokenService is configured to false. Using pass-through cluster-sync-service.");
+ clusterSyncService = PASS_THROUGH_CLUSTER_SYNC_SERVICE;
+ } else if (syncTokenService == null) {
+ logger.warn("activate: useSyncTokenService is configured to true but there's no SyncTokenService! Using pass-through cluster-sync-service instead.");
+ clusterSyncService = syncTokenService;
+ } else {
+ logger.info("activate: useSyncTokenService is configured to true, using the available SyncTokenService: " + syncTokenService);
+ clusterSyncService = syncTokenService;
+ }
+ viewStateManager = ViewStateManagerFactory.newViewStateManager(viewStateManagerLock, clusterSyncService);
+
if (config.getMinEventDelay()>0) {
viewStateManager.installMinEventDelayHandler(this, scheduler, config.getMinEventDelay());
}
@@ -295,6 +321,13 @@ public class DiscoveryServiceImpl extend
activated = true;
setOldView(newView);
+ // in case bind got called before activate we now have pending listeners,
+ // bind them to the viewstatemanager too
+ for (TopologyEventListener listener : pendingListeners) {
+ viewStateManager.bind(listener);
+ }
+ pendingListeners.clear();
+
viewStateManager.bind(changePropagationListener);
} finally {
if (viewStateManagerLock!=null) {
@@ -330,9 +363,10 @@ public class DiscoveryServiceImpl extend
logger.debug("DiscoveryServiceImpl deactivated.");
viewStateManagerLock.lock();
try{
- viewStateManager.unbind(changePropagationListener);
-
- viewStateManager.handleDeactivated();
+ if (viewStateManager != null) {
+ viewStateManager.unbind(changePropagationListener);
+ viewStateManager.handleDeactivated();
+ }
activated = false;
} finally {
@@ -354,14 +388,36 @@ public class DiscoveryServiceImpl extend
* bind a topology event listener
*/
protected void bindTopologyEventListener(final TopologyEventListener eventListener) {
- viewStateManager.bind(eventListener);
+ viewStateManagerLock.lock();
+ try{
+ if (!activated) {
+ pendingListeners.add(eventListener);
+ } else {
+ viewStateManager.bind(eventListener);
+ }
+ } finally {
+ if (viewStateManagerLock!=null) {
+ viewStateManagerLock.unlock();
+ }
+ }
}
/**
* Unbind a topology event listener
*/
protected void unbindTopologyEventListener(final TopologyEventListener eventListener) {
- viewStateManager.unbind(eventListener);
+ viewStateManagerLock.lock();
+ try{
+ if (!activated) {
+ pendingListeners.remove(eventListener);
+ } else {
+ viewStateManager.unbind(eventListener);
+ }
+ } finally {
+ if (viewStateManagerLock!=null) {
+ viewStateManagerLock.unlock();
+ }
+ }
}
/**
@@ -681,8 +737,19 @@ public class DiscoveryServiceImpl extend
* Handle the fact that the topology has started to change - inform the listeners asap
*/
public void handleTopologyChanging() {
- logger.debug("handleTopologyChanging: invoking viewStateManager.handlechanging");
- viewStateManager.handleChanging();
+ viewStateManagerLock.lock();
+ try{
+ if (!activated) {
+ logger.error("handleTopologyChanging: not yet activated!");
+ return;
+ }
+ logger.debug("handleTopologyChanging: invoking viewStateManager.handlechanging");
+ viewStateManager.handleChanging();
+ } finally {
+ if (viewStateManagerLock!=null) {
+ viewStateManagerLock.unlock();
+ }
+ }
}
/** SLING-2901 : send a TOPOLOGY_CHANGING event and shutdown the service thereafter **/
Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1713589&r1=1713588&r2=1713589&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/resources/OSGI-INF/metatype/metatype.properties Tue Nov 10 08:36:21 2015
@@ -63,6 +63,12 @@ invertRepositoryDescriptor.description =
repository descriptor value that is obtained via the configured 'leaderElectionRepositoryDescriptor' \
(thus only applies if that is configured). Default is 'false' (don't invert).
+useSyncTokenService.name = Enable Use of SyncTokenService
+useSyncTokenService.description = If enabled (and a SyncTokenService is available, which it \
+ is in discovery.commons), then switching the view will first be going via that SyncTokenService. \
+ This will ensure that all TopologyEventListeners will have received a \
+ TOPOLOGY_CHANGING before a TOPOLOGY_CHANGED is sent - for all instances in the local cluster.
+
autoStopLocalLoopEnabled.name = Auto-Stop Local-Loops
autoStopLocalLoopEnabled.description = If true, and the discovery.impl detects a local-looping \
topology connector, the corresponding topology connector will be automatically stopped. \
Added: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java?rev=1713589&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java Tue Nov 10 08:36:21 2015
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+package org.apache.sling.discovery.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sling.discovery.TopologyEvent;
+import org.apache.sling.discovery.TopologyEventListener;
+import org.apache.sling.discovery.base.its.setup.VirtualInstance;
+import org.apache.sling.discovery.impl.setup.FullJR2VirtualInstanceBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DiscoveryWithSyncTokenTest {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ List<VirtualInstance> instances;
+
+ @Before
+ public void setup() throws Exception {
+ logger.info("setup: start");
+ instances = new LinkedList<VirtualInstance>();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ logger.info("teardown: start");
+ for (VirtualInstance virtualInstance : instances) {
+ virtualInstance.stop();
+ }
+ logger.info("teardown: end");
+ }
+
+ @Test
+ public void testTwoNodes() throws Throwable {
+ logger.info("testTwoNodes: start");
+
+ FullJR2VirtualInstanceBuilder b1 = new FullJR2VirtualInstanceBuilder();
+ b1.setDebugName("i1").newRepository("/var/twon/", true);
+ b1.setConnectorPingInterval(1).setMinEventDelay(1).setConnectorPingTimeout(60);
+ VirtualInstance i1 = b1.build();
+ i1.bindTopologyEventListener(new TopologyEventListener() {
+
+ @Override
+ public void handleTopologyEvent(TopologyEvent event) {
+ logger.info("GOT EVENT: "+event);
+ }
+ });
+
+ FullJR2VirtualInstanceBuilder b2 = new FullJR2VirtualInstanceBuilder();
+ b2.setDebugName("i2").useRepositoryOf(i1);
+ b2.setConnectorPingInterval(1).setMinEventDelay(1).setConnectorPingTimeout(60);
+ VirtualInstance i2 = b2.build();
+
+ i1.heartbeatsAndCheckView();
+ i2.heartbeatsAndCheckView();
+ i1.heartbeatsAndCheckView();
+ i2.heartbeatsAndCheckView();
+
+ Thread.sleep(99999);
+ }
+}
Propchange: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/DiscoveryWithSyncTokenTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/FullJR2VirtualInstanceBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/FullJR2VirtualInstanceBuilder.java?rev=1713589&r1=1713588&r2=1713589&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/FullJR2VirtualInstanceBuilder.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/FullJR2VirtualInstanceBuilder.java Tue Nov 10 08:36:21 2015
@@ -35,6 +35,7 @@ import org.apache.sling.discovery.base.i
import org.apache.sling.discovery.base.its.setup.VirtualInstance;
import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
import org.apache.sling.discovery.base.its.setup.mock.DummyResourceResolverFactory;
+import org.apache.sling.discovery.commons.providers.spi.base.SyncTokenService;
import org.apache.sling.discovery.impl.DiscoveryServiceImpl;
import org.apache.sling.discovery.impl.cluster.ClusterViewServiceImpl;
import org.apache.sling.discovery.impl.cluster.voting.VotingHandler;
@@ -55,6 +56,8 @@ public class FullJR2VirtualInstanceBuild
private VotingHandler votingHandler;
+ private SyncTokenService syncTokenService;
+
@Override
public VirtualInstanceBuilder createNewRepository() throws Exception {
DummyResourceResolverFactory dummyFactory = new DummyResourceResolverFactory();
@@ -110,9 +113,20 @@ public class FullJR2VirtualInstanceBuild
return HeartbeatHandler.testConstructor(getSlingSettingsService(), getResourceResolverFactory(), getAnnouncementRegistry(), getConnectorRegistry(), getConfig(), getScheduler(), getVotingHandler());
}
+ private SyncTokenService getSyncTokenService() throws Exception {
+ if (syncTokenService == null) {
+ syncTokenService = createSyncTokenService();
+ }
+ return syncTokenService;
+ }
+
+ private SyncTokenService createSyncTokenService() {
+ return SyncTokenService.testConstructorAndActivate(getConfig(), getResourceResolverFactory(), getSlingSettingsService());
+ }
+
@Override
protected BaseDiscoveryService createDiscoveryService() throws Exception {
- return DiscoveryServiceImpl.testConstructor(getResourceResolverFactory(), getAnnouncementRegistry(), getConnectorRegistry(), (ClusterViewServiceImpl) getClusterViewService(), getHeartbeatHandler(), getSlingSettingsService(), getScheduler(), getConfig());
+ return DiscoveryServiceImpl.testConstructor(getResourceResolverFactory(), getAnnouncementRegistry(), getConnectorRegistry(), (ClusterViewServiceImpl) getClusterViewService(), getHeartbeatHandler(), getSlingSettingsService(), getScheduler(), getConfig(), getSyncTokenService());
}
@Override