From: Robert Varga Date: Fri, 28 Apr 2017 14:56:48 +0000 (+0200) Subject: BUG-8327: GlobalBundleScanningSchemaServiceImpl should be a proxy X-Git-Tag: release/nitrogen~300 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=97c07b8e5078fc6bf5b396ad55b672eea228a87f BUG-8327: GlobalBundleScanningSchemaServiceImpl should be a proxy We are currently running to separate services which assemble the GlobalSchemaContext, which hurts our startup performance and leads to wasted memory. This is an artefact of the mdsal split, hence we should be getting the service from the MD-SAL and just proxy to old interfaces. This lowers the startup time for feature:install odl-restconf odl-bgpcep-bgp odl-bgpcep-data-change-counter odl-netconf-topology from 86s down to 67s (22%). Final retained heap size is also lowered from 217MiB to 181MiB (16%) Change-Id: I549e9512538bd83d86cfd2164d03e34bc9130c1e Signed-off-by: Robert Varga --- diff --git a/opendaylight/md-sal/sal-schema-service/pom.xml b/opendaylight/md-sal/sal-schema-service/pom.xml index d86351f1c4..4c01859eb1 100644 --- a/opendaylight/md-sal/sal-schema-service/pom.xml +++ b/opendaylight/md-sal/sal-schema-service/pom.xml @@ -51,22 +51,6 @@ - - - - org.apache.felix - maven-bundle-plugin - true - - - ${project.groupId}.${project.artifactId} - org.opendaylight.controller.sal.schema.service.impl.SchemaServiceActivator - - - - - - scm:git:http://git.opendaylight.org/gerrit/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git diff --git a/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/GlobalBundleScanningSchemaServiceImpl.java b/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/GlobalBundleScanningSchemaServiceImpl.java index 32a6291e5f..4a4ae3b82a 100644 --- a/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/GlobalBundleScanningSchemaServiceImpl.java +++ b/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/GlobalBundleScanningSchemaServiceImpl.java @@ -7,105 +7,54 @@ */ package org.opendaylight.controller.sal.schema.service.impl; -import static com.google.common.base.Preconditions.checkState; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.common.util.concurrent.CheckedFuture; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; +import com.google.common.util.concurrent.Futures; +import java.util.HashSet; +import java.util.Set; import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.api.model.YangTextSourceProvider; +import org.opendaylight.mdsal.dom.api.DOMSchemaService; +import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.util.ListenerRegistry; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; +import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; -import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.BundleTracker; -import org.osgi.util.tracker.BundleTrackerCustomizer; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, - ServiceTrackerCustomizer, YangTextSourceProvider, AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class); - private static final long FRAMEWORK_BUNDLE_ID = 0; +public final class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, + YangTextSourceProvider, AutoCloseable { - @GuardedBy(value = "lock") - private final ListenerRegistry listeners = new ListenerRegistry<>(); - private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle"); - private final BundleScanner scanner = new BundleScanner(); + @GuardedBy("lock") + private final Set> listeners = new HashSet<>(); private final Object lock = new Object(); - private final BundleContext context; - - private ServiceTracker listenerTracker; - private BundleTracker> bundleTracker; - private boolean starting = true; - - private volatile boolean stopping; - - private GlobalBundleScanningSchemaServiceImpl(final BundleContext context) { - this.context = Preconditions.checkNotNull(context); - } + private final DOMSchemaService schemaService; + private final DOMYangTextSourceProvider yangProvider; - public static GlobalBundleScanningSchemaServiceImpl createInstance(final BundleContext ctx) { - GlobalBundleScanningSchemaServiceImpl instance = new GlobalBundleScanningSchemaServiceImpl(ctx); - instance.start(); - return instance; + private GlobalBundleScanningSchemaServiceImpl(final DOMSchemaService schemaService) { + this.schemaService = Preconditions.checkNotNull(schemaService); + this.yangProvider = (DOMYangTextSourceProvider) schemaService.getSupportedExtensions() + .get(DOMYangTextSourceProvider.class); } - public BundleContext getContext() { - return context; - } - - private void start() { - checkState(context != null); - LOG.debug("start() starting"); - - listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, this); - bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING | - Bundle.STOPPING | Bundle.ACTIVE, scanner); - - synchronized (lock) { - bundleTracker.open(); - - LOG.debug("BundleTracker.open() complete"); - if (Iterables.size(listeners.getListeners()) > 0) { - tryToUpdateSchemaContext(); - } - } - - listenerTracker.open(); - starting = false; - - LOG.debug("start() complete"); + public static GlobalBundleScanningSchemaServiceImpl createInstance(final DOMSchemaService schemaService) { + return new GlobalBundleScanningSchemaServiceImpl(schemaService); } @Override public SchemaContext getSchemaContext() { - return getGlobalContext(); + return schemaService.getGlobalContext(); } @Override public SchemaContext getGlobalContext() { - return contextResolver.getSchemaContext().orNull(); + return schemaService.getGlobalContext(); } @Override @@ -127,168 +76,44 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi public ListenerRegistration registerSchemaContextListener( final SchemaContextListener listener) { synchronized (lock) { - Optional potentialCtx = contextResolver.getSchemaContext(); - if(potentialCtx.isPresent()) { - listener.onGlobalContextUpdated(potentialCtx.get()); - } - return listeners.register(listener); + final ListenerRegistration reg = schemaService.registerSchemaContextListener( + listener); + + final ListenerRegistration ret = + new AbstractListenerRegistration(listener) { + @Override + protected void removeRegistration() { + synchronized (lock) { + listeners.remove(this); + } + reg.close(); + } + }; + + listeners.add(ret); + return ret; } } @Override public void close() { synchronized (lock) { - stopping = true; - if (bundleTracker != null) { - bundleTracker.close(); - bundleTracker = null; - } - if (listenerTracker != null) { - listenerTracker.close(); - listenerTracker = null; - } - - for (ListenerRegistration l : listeners.getListeners()) { + for (ListenerRegistration l : listeners) { l.close(); } + listeners.clear(); } } - @GuardedBy("lock") - private void notifyListeners(final SchemaContext snapshot) { - Object[] services = listenerTracker.getServices(); - for (ListenerRegistration listener : listeners) { - try { - listener.getInstance().onGlobalContextUpdated(snapshot); - } catch (Exception e) { - LOG.error("Exception occured during invoking listener", e); - } - } - if (services != null) { - for (Object rawListener : services) { - final SchemaContextListener listener = (SchemaContextListener) rawListener; - try { - listener.onGlobalContextUpdated(snapshot); - } catch (Exception e) { - LOG.error("Exception occured during invoking listener {}", listener, e); - } - } - } - } - + @SuppressWarnings("unchecked") @Override public CheckedFuture getSource( final SourceIdentifier sourceIdentifier) { - return contextResolver.getSource(sourceIdentifier); - } - - private class BundleScanner implements BundleTrackerCustomizer> { - @Override - public Iterable addingBundle(final Bundle bundle, final BundleEvent event) { - if (bundle.getBundleId() == FRAMEWORK_BUNDLE_ID) { - return Collections.emptyList(); - } - - final Enumeration enumeration = bundle.findEntries("META-INF/yang", "*.yang", false); - if (enumeration == null) { - return Collections.emptyList(); - } - - final List urls = new ArrayList<>(); - while (enumeration.hasMoreElements()) { - final URL u = enumeration.nextElement(); - try { - urls.add(contextResolver.registerSource(u)); - LOG.debug("Registered {}", u); - } catch (Exception e) { - LOG.warn("Failed to register {}, ignoring it", e); - } - } - - if (!urls.isEmpty()) { - LOG.debug("Loaded {} new URLs from bundle {}, attempting to rebuild schema context", - urls.size(), bundle.getSymbolicName()); - tryToUpdateSchemaContext(); - } - - return ImmutableList.copyOf(urls); - } - - @Override - public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Iterable object) { - if (bundle.getBundleId() == FRAMEWORK_BUNDLE_ID) { - LOG.debug("Framework bundle {} got event {}", bundle, event.getType()); - if ((event.getType() & BundleEvent.STOPPING) != 0) { - LOG.info("OSGi framework is being stopped, halting bundle scanning"); - stopping = true; - } - } - } - - /** - * If removing YANG files makes yang store inconsistent, method - * {@link #getYangStoreSnapshot()} will throw exception. There is no - * rollback. - */ - @Override - public void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable urls) { - for (Registration url : urls) { - try { - url.close(); - } catch (Exception e) { - LOG.warn("Failed do unregister URL {}, proceeding", url, e); - } - } - - int numUrls = Iterables.size(urls); - if(numUrls > 0 ) { - if(LOG.isDebugEnabled()) { - LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(), bundle.getState(), - numUrls); - } - - tryToUpdateSchemaContext(); - } + if (yangProvider == null) { + return Futures.immediateFailedCheckedFuture(new MissingSchemaSourceException( + "Source provider is not available", sourceIdentifier)); } - } - @Override - public SchemaContextListener addingService(final ServiceReference reference) { - - SchemaContextListener listener = context.getService(reference); - SchemaContext _ctxContext = getGlobalContext(); - if (getContext() != null && _ctxContext != null) { - listener.onGlobalContextUpdated(_ctxContext); - } - return listener; - } - - public void tryToUpdateSchemaContext() { - if (starting || stopping) { - return; - } - - synchronized (lock) { - Optional schema = contextResolver.getSchemaContext(); - if (schema.isPresent()) { - if (LOG.isDebugEnabled()) { - LOG.debug("Got new SchemaContext: # of modules {}", schema.get().getAllModuleIdentifiers().size()); - } - - notifyListeners(schema.get()); - } - } - } - - @Override - public void modifiedService(final ServiceReference reference, - final SchemaContextListener service) { - // NOOP - } - - @Override - public void removedService(final ServiceReference reference, - final SchemaContextListener service) { - context.ungetService(reference); + return (CheckedFuture) yangProvider.getSource(sourceIdentifier); } } diff --git a/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/SchemaServiceActivator.java b/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/SchemaServiceActivator.java deleted file mode 100644 index a13a872e9c..0000000000 --- a/opendaylight/md-sal/sal-schema-service/src/main/java/org/opendaylight/controller/sal/schema/service/impl/SchemaServiceActivator.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.schema.service.impl; - -import java.util.Hashtable; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.controller.sal.core.api.model.YangTextSourceProvider; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -public class SchemaServiceActivator implements BundleActivator { - private ServiceRegistration schemaServiceReg; - private ServiceRegistration schemaSourceReg; - private GlobalBundleScanningSchemaServiceImpl schemaService; - - @Override - public void start(final BundleContext context) { - schemaService = GlobalBundleScanningSchemaServiceImpl.createInstance(context); - schemaServiceReg = context.registerService(SchemaService.class, schemaService, new Hashtable()); - schemaSourceReg = context.registerService(YangTextSourceProvider.class, schemaService, new Hashtable()); - } - - @Override - public void stop(final BundleContext context) { - schemaServiceReg.unregister(); - schemaSourceReg.unregister(); - schemaService.close(); - } -} diff --git a/opendaylight/md-sal/sal-schema-service/src/main/resources/org/opendaylight/blueprint/sal-schema-service.xml b/opendaylight/md-sal/sal-schema-service/src/main/resources/org/opendaylight/blueprint/sal-schema-service.xml new file mode 100644 index 0000000000..a9a1bdbb19 --- /dev/null +++ b/opendaylight/md-sal/sal-schema-service/src/main/resources/org/opendaylight/blueprint/sal-schema-service.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + org.opendaylight.controller.sal.core.api.model.SchemaService + org.opendaylight.controller.sal.core.api.model.YangTextSourceProvider + + +