You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:26:33 UTC
[sling-org-apache-sling-discovery-commons] 30/38: SLING-4603 : even
more aggressively clearing the idMap-cache to avoid stale entries : now
registering an EventHandler that listens on /var/discovery/../idMap and
clears the cache on any change therein
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.discovery.commons-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-discovery-commons.git
commit 2e5938fec21a783060cfb5f0c0c90f76caa46f97
Author: Stefan Egli <st...@apache.org>
AuthorDate: Fri Oct 23 08:48:17 2015 +0000
SLING-4603 : even more aggressively clearing the idMap-cache to avoid stale entries : now registering an EventHandler that listens on /var/discovery/../idMap and clears the cache on any change therein
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/discovery/commons@1710144 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 8 ++
.../commons/providers/spi/base/IdMapService.java | 117 +++++++++++++++++++--
2 files changed, 116 insertions(+), 9 deletions(-)
diff --git a/pom.xml b/pom.xml
index e395218..438bd24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,6 +133,14 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-core</artifactId>
<version>1.3.7</version>
diff --git a/src/main/java/org/apache/sling/discovery/commons/providers/spi/base/IdMapService.java b/src/main/java/org/apache/sling/discovery/commons/providers/spi/base/IdMapService.java
index 12e8db7..1ec4583 100644
--- a/src/main/java/org/apache/sling/discovery/commons/providers/spi/base/IdMapService.java
+++ b/src/main/java/org/apache/sling/discovery/commons/providers/spi/base/IdMapService.java
@@ -18,14 +18,20 @@
*/
package org.apache.sling.discovery.commons.providers.spi.base;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
@@ -36,6 +42,12 @@ import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.discovery.commons.providers.util.ResourceHelper;
import org.apache.sling.settings.SlingSettingsService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
/**
* The IdMapService is responsible for storing a slingId-clusterNodeId
@@ -43,8 +55,8 @@ import org.apache.sling.settings.SlingSettingsService;
* do the same can map clusterNodeIds to slingIds (or vice-versa)
*/
@Component(immediate = false)
-@Service(value = IdMapService.class)
-public class IdMapService extends AbstractServiceWithBackgroundCheck {
+@Service(value = { IdMapService.class })
+public class IdMapService extends AbstractServiceWithBackgroundCheck implements EventHandler {
@Reference
private ResourceResolverFactory resourceResolverFactory;
@@ -61,8 +73,15 @@ public class IdMapService extends AbstractServiceWithBackgroundCheck {
private long me;
+ private final Map<Integer, String> oldIdMapCache = new HashMap<Integer, String>();
private final Map<Integer, String> idMapCache = new HashMap<Integer, String>();
+ private long lastCacheInvalidation = -1;
+
+ private BundleContext bundleContext;
+
+ private ServiceRegistration eventHandlerRegistration;
+
/** test-only constructor **/
public static IdMapService testConstructor(
DiscoveryLiteConfig commonsConfig,
@@ -72,12 +91,15 @@ public class IdMapService extends AbstractServiceWithBackgroundCheck {
service.commonsConfig = commonsConfig;
service.settingsService = settingsService;
service.resourceResolverFactory = resourceResolverFactory;
- service.activate();
+ service.activate(null);
return service;
}
@Activate
- protected void activate() {
+ protected void activate(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ registerEventHandler();
+
startBackgroundCheck("IdMapService-initializer", new BackgroundCheck() {
@Override
@@ -92,6 +114,32 @@ public class IdMapService extends AbstractServiceWithBackgroundCheck {
}, null, -1, 1000 /* = 1sec interval */);
}
+ @Deactivate
+ protected void deactivate() {
+ if (eventHandlerRegistration != null) {
+ eventHandlerRegistration.unregister();
+ eventHandlerRegistration = null;
+ }
+ }
+
+ private void registerEventHandler() {
+ if (bundleContext == null) {
+ logger.info("registerEventHandler: bundleContext is null - cannot register");
+ return;
+ }
+ Dictionary<String,Object> properties = new Hashtable<String,Object>();
+ properties.put(Constants.SERVICE_DESCRIPTION, "IdMap Change Listener.");
+ String[] topics = new String[] {
+ SlingConstants.TOPIC_RESOURCE_ADDED,
+ SlingConstants.TOPIC_RESOURCE_CHANGED,
+ SlingConstants.TOPIC_RESOURCE_REMOVED };
+ properties.put(EventConstants.EVENT_TOPIC, topics);
+ String path = getIdMapPath().endsWith("/") ? getIdMapPath() + "*" : getIdMapPath() + "/*";
+ properties.put(EventConstants.EVENT_FILTER, "(&(path="+path+"))");
+ eventHandlerRegistration = bundleContext.registerService(
+ EventHandler.class.getName(), this, properties);
+ }
+
/** Get or create a ResourceResolver **/
private ResourceResolver getResourceResolver() throws LoginException {
return resourceResolverFactory.getAdministrativeResourceResolver(null);
@@ -194,20 +242,55 @@ public class IdMapService extends AbstractServiceWithBackgroundCheck {
}
public synchronized void clearCache() {
- logger.info("clearCache: clearing idmap cache");
- idMapCache.clear();
+ if (!idMapCache.isEmpty()) {
+ logger.debug("clearCache: clearing idmap cache");
+ oldIdMapCache.clear();
+ oldIdMapCache.putAll(idMapCache);
+ idMapCache.clear();
+ } else {
+ logger.debug("clearCache: cache was already emtpy");
+ }
+ lastCacheInvalidation = System.currentTimeMillis();
}
public synchronized String toSlingId(int clusterNodeId, ResourceResolver resourceResolver) throws PersistenceException {
+ if (System.currentTimeMillis() - lastCacheInvalidation > 30000) {
+ // since upon a restart of an instance it could opt to have changed
+ // the slingId, we might not be able to catch that change if we
+ // noticed the view change before that (the view change would
+ // force a cache invalidation).
+ // we can either rely on observation - or combine that with
+ // an invalidation of once per minute
+ // (note that this means we'll be reading
+ // /var/discovery/oak/idMap once per minute - but that sounds
+ // perfectly fine)
+ clearCache();
+ }
String slingId = idMapCache.get(clusterNodeId);
if (slingId!=null) {
// cache-hit
return slingId;
}
// cache-miss
+ logger.debug("toSlingId: cache miss, refreshing idmap cache");
Map<Integer, String> readMap = readIdMap(resourceResolver);
- logger.info("toSlingId: cache miss, refreshing idmap cache");
- idMapCache.putAll(readMap);
+ Set<Entry<Integer, String>> newEntries = readMap.entrySet();
+ for (Entry<Integer, String> newEntry : newEntries) {
+ String oldValue = oldIdMapCache.get(newEntry.getKey());
+ if (oldValue == null || !oldValue.equals(newEntry.getValue())) {
+ logger.info("toSlingId: mapping for "+newEntry.getKey()+" to "+newEntry.getValue() + " was newly added.");
+ } else if (!oldValue.equals(newEntry.getValue())) {
+ logger.info("toSlingId: mapping for "+newEntry.getKey()+" changed from "+oldValue+" to "+newEntry.getValue());
+ }
+ idMapCache.put(newEntry.getKey(), newEntry.getValue());
+ }
+ Set<Entry<Integer, String>> oldEntries = oldIdMapCache.entrySet();
+ for (Entry<Integer, String> oldEntry : oldEntries) {
+ if (!idMapCache.containsKey(oldEntry.getKey())) {
+ logger.info("toSlingId: mapping for "+oldEntry.getKey()+" to "+oldEntry.getValue()+" disappeared.");
+ }
+ }
+
return idMapCache.get(clusterNodeId);
}
@@ -229,4 +312,20 @@ public class IdMapService extends AbstractServiceWithBackgroundCheck {
return commonsConfig.getIdMapPath();
}
-}
+ @Override
+ public void handleEvent(Event event) {
+ final String resourcePath = (String) event.getProperty("path");
+ if (resourcePath == null) {
+ // not of my business
+ return;
+ }
+
+ if (!resourcePath.startsWith(getIdMapPath())) {
+ // not of my business
+ return;
+ }
+ logger.debug("handleEvent: got event for path: {}, event: {}", resourcePath, event);
+ clearCache();
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.