From 39f4592ff9db28d8d04e6ecc5d6873d44dbb4378 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 27 Nov 2013 15:45:51 +0100 Subject: [PATCH] Moved Schema Aware logic from DataStore to SchemaAwareDataStore adapter All YANG schema logic necessary for proper function of DataStore for all components was moved to separate component which provides this functionality unified from one place for multiple datastores. Change-Id: I840f752b03e22047e8a7f3d2b7dbe3026fb087c9 Signed-off-by: Tony Tkacik --- .../binding/test/AbstractDataServiceTest.java | 84 ++++-- .../sal/common/api/data/DataChangeEvent.java | 18 +- .../impl/service/AbstractDataBroker.xtend | 9 + .../impl/service/DataChangeEventImpl.java | 12 + .../service/InitialDataChangeEventImpl.java | 75 ++++++ .../impl/util/AbstractLockableDelegator.java | 76 ++++++ .../sal/core/api/data/DataStore.java | 7 + .../md/sal/dom/impl/DomBrokerImplModule.java | 5 +- .../dom/broker/BrokerConfigActivator.xtend | 13 +- .../sal/dom/broker/DataBrokerImpl.java | 1 + .../broker/impl/DataStoreStatsWrapper.java | 137 ++++++++++ .../sal/dom/broker/impl/DataUtils.xtend | 50 ---- .../dom/broker/impl/HashMapDataStore.xtend | 26 +- .../broker/impl/SchemaAwareDataMerger.xtend | 13 + .../impl/SchemaAwareDataStoreAdapter.java | 245 ++++++++++++++++++ 15 files changed, 688 insertions(+), 83 deletions(-) create mode 100644 opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java create mode 100644 opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java delete mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index 5b35861e9d..9f3a6e8652 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -8,6 +8,7 @@ import java.util.Set; import javassist.ClassPool; +import org.junit.After; import org.junit.Before; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; @@ -15,78 +16,96 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndepende import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -public abstract class AbstractDataServiceTest { +public abstract class AbstractDataServiceTest { + private static Logger log = LoggerFactory.getLogger(AbstractDataServiceTest.class); + protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; protected DataProviderService baDataService; - + /** * Workaround for JUNIT sharing classloaders * */ protected static final ClassPool POOL = new ClassPool(); - + protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl; protected BindingIndependentMappingService mappingService; protected DataBrokerImpl baDataImpl; protected org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; protected ListeningExecutorService executor; protected BindingIndependentDataServiceConnector connectorServiceImpl; - protected HashMapDataStore dataStore; - - + protected HashMapDataStore rawDataStore; + private SchemaAwareDataStoreAdapter schemaAwareDataStore; + private DataStoreStatsWrapper dataStoreStats; + + protected DataStore dataStore; + @Before public void setUp() { executor = MoreExecutors.sameThreadExecutor(); baDataImpl = new DataBrokerImpl(); baDataService = baDataImpl; baDataImpl.setExecutor(executor); - + biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl(); - biDataService = biDataImpl; + biDataService = biDataImpl; biDataImpl.setExecutor(executor); - - dataStore = new HashMapDataStore(); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance(); + + rawDataStore = new HashMapDataStore(); + schemaAwareDataStore = new SchemaAwareDataStoreAdapter(); + schemaAwareDataStore.changeDelegate(rawDataStore); + dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore); + dataStore = dataStoreStats; + + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier + .builder().toInstance(); biDataImpl.registerConfigurationReader(treeRoot, dataStore); biDataImpl.registerOperationalReader(treeRoot, dataStore); biDataImpl.registerCommitHandler(treeRoot, dataStore); - + mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(); mappingServiceImpl.setPool(POOL); mappingService = mappingServiceImpl; File pathname = new File("target/gen-classes-debug"); - //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath()); + // System.out.println("Generated classes are captured in " + + // pathname.getAbsolutePath()); mappingServiceImpl.start(null); - //mappingServiceImpl.getBinding().setClassFileCapturePath(pathname); - + // mappingServiceImpl.getBinding().setClassFileCapturePath(pathname); + connectorServiceImpl = new BindingIndependentDataServiceConnector(); connectorServiceImpl.setBaDataService(baDataService); connectorServiceImpl.setBiDataService(biDataService); connectorServiceImpl.setMappingService(mappingServiceImpl); connectorServiceImpl.start(); - - String[] yangFiles= getModelFilenames(); - if(yangFiles != null && yangFiles.length > 0) { - mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles)); + + String[] yangFiles = getModelFilenames(); + if (yangFiles != null && yangFiles.length > 0) { + SchemaContext context = getContext(yangFiles); + mappingServiceImpl.onGlobalContextUpdated(context); + schemaAwareDataStore.onGlobalContextUpdated(context); } } - - protected String[] getModelFilenames() { + protected String[] getModelFilenames() { return getAllModelFilenames(); } - + public static String[] getAllModelFilenames() { Predicate predicate = new Predicate() { @Override @@ -94,11 +113,11 @@ public abstract class AbstractDataServiceTest { return input.endsWith(".yang"); } }; - Reflections reflection= new Reflections("META-INF.yang", new ResourcesScanner()); + Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner()); Set result = reflection.getResources(predicate); return (String[]) result.toArray(new String[result.size()]); } - + public static SchemaContext getContext(String[] yangFiles) { ClassLoader loader = AbstractDataServiceTest.class.getClassLoader(); @@ -114,4 +133,21 @@ public abstract class AbstractDataServiceTest { Set modules = parser.parseYangModelsFromStreams(streams); return parser.resolveSchemaContext(modules); } + + @After + public void afterTest() { + + log.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(), + dataStoreStats.getConfigurationReadAverageTime()); + + log.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(), + dataStoreStats.getOperationalReadAverageTime()); + + log.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(), + dataStoreStats.getRequestCommitAverageTime()); + + } } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java index 144a81b256..d62e176e62 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java @@ -11,15 +11,31 @@ import org.opendaylight.yangtools.concepts.Immutable; public interface DataChangeEvent extends DataChange, Immutable { + /** + * Returns a orignal subtree of data, which starts at the path + * where listener was registered. + * + */ + D getOriginalConfigurationSubtree(); + /** * Returns a new subtree of data, which starts at the path * where listener was registered. * */ + D getOriginalOperationalSubtree(); + + + + /** + * Returns a updated subtree of data, which starts at the path + * where listener was registered. + * + */ D getUpdatedConfigurationSubtree(); /** - * Returns a new subtree of data, which starts at the path + * Returns a udpated subtree of data, which starts at the path * where listener was registered. * */ diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend index e3d2b567a7..a18e5a9c82 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend @@ -38,6 +38,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegis import org.opendaylight.controller.md.sal.common.api.RegistrationListener import org.opendaylight.yangtools.concepts.util.ListenerRegistry import java.util.concurrent.atomic.AtomicLong +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // DataReader, // @@ -91,6 +92,10 @@ DataProvisionService { override final def registerDataChangeListener(P path, DCL listener) { val reg = new DataChangeListenerRegistration(path, listener, this); listeners.put(path, reg); + val initialConfig = dataReadRouter.readConfigurationData(path); + val initialOperational = dataReadRouter.readOperationalData(path); + val event = createInitialListenerEvent(path,initialConfig,initialOperational); + listener.onDataChanged(event); return reg; } @@ -108,6 +113,10 @@ DataProvisionService { return ret; } + protected def DataChangeEvent createInitialListenerEvent(P path,D initialConfig,D initialOperational) { + return new InitialDataChangeEventImpl(initialConfig,initialOperational); + + } protected final def removeListener(DataChangeListenerRegistration registration) { listeners.remove(registration.path, registration); diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java index 4eb9586fdf..68f9506c56 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -11,6 +11,8 @@ public class DataChangeEventImpl implements DataChangeEvent { private final DataChange dataChange; private final D originalConfigurationSubtree; + + private final D originalOperationalSubtree; private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; @@ -28,6 +30,16 @@ public class DataChangeEventImpl implements DataChangeEvent { this.updatedConfigurationSubtree = updatedConfigurationSubtree; } + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + @Override public D getUpdatedOperationalSubtree() { return updatedOperationalSubtree; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java new file mode 100644 index 0000000000..2764635720 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java @@ -0,0 +1,75 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; + +public class InitialDataChangeEventImpl implements DataChangeEvent { + + private final D originalOperationalTree; + private final D originalConfigurationTree; + + public InitialDataChangeEventImpl(D configTree, D operTree) { + originalConfigurationTree = configTree; + originalOperationalTree = operTree; + } + + @Override + public Map getCreatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getCreatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Map getOriginalConfigurationData() { + return Collections.emptyMap(); + } + @Override + public Map getOriginalOperationalData() { + return Collections.emptyMap(); + } + @Override + public Set

getRemovedConfigurationData() { + return Collections.emptySet(); + } + @Override + public Set

getRemovedOperationalData() { + return Collections.emptySet(); + } + @Override + public Map getUpdatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public D getUpdatedConfigurationSubtree() { + return originalConfigurationTree; + } + @Override + public D getUpdatedOperationalSubtree() { + return originalOperationalTree; + } + + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationTree; + } + + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalTree; + } + + @Override + public Map getUpdatedOperationalData() { + return Collections.emptyMap(); + } + + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java new file mode 100644 index 0000000000..61abe664aa --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java @@ -0,0 +1,76 @@ +package org.opendaylight.controller.md.sal.common.impl.util; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import org.opendaylight.yangtools.concepts.Delegator; + +import com.google.common.base.Preconditions; + +public class AbstractLockableDelegator implements Delegator { + + private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock(); + private final ReadLock delegateReadLock = delegateLock.readLock(); + private final WriteLock delegateWriteLock = delegateLock.writeLock(); + + + protected Lock getDelegateReadLock() { + return delegateReadLock; + } + + private T delegate; + + public AbstractLockableDelegator() { + // NOOP + } + + public AbstractLockableDelegator(T initialDelegate) { + delegate = initialDelegate; + } + + @Override + public T getDelegate() { + try { + delegateReadLock.lock(); + return delegate; + } finally { + delegateReadLock.unlock(); + } + } + + public T retrieveDelegate() { + try { + delegateReadLock.lock(); + Preconditions.checkState(delegate != null,"Delegate is null"); + return delegate; + } finally { + delegateReadLock.unlock(); + } + } + + /** + * + * @param newDelegate + * @return oldDelegate + */ + public final T changeDelegate(T newDelegate) { + try { + delegateWriteLock.lock(); + T oldDelegate = delegate; + delegate = newDelegate; + onDelegateChanged(oldDelegate, newDelegate); + return oldDelegate; + } finally { + delegateWriteLock.unlock(); + } + } + + + protected void onDelegateChanged(T oldDelegate, T newDelegate) { + // NOOP in abstract calss; + } +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java index 1062f5e535..87129d6863 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java @@ -8,5 +8,12 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public interface DataStore extends // DataReader, DataCommitHandler { + + + Iterable getStoredConfigurationPaths(); + Iterable getStoredOperationalPaths(); + + boolean containsConfigurationPath(InstanceIdentifier path); + boolean containsOperationalPath(InstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java index 9a4fc6ddc1..050966faa0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java @@ -13,6 +13,7 @@ import org.opendaylight.controller.sal.core.api.data.DataStore; import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator; import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.osgi.framework.BundleContext; +import static com.google.common.base.Preconditions.*; /** * @@ -33,8 +34,10 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi @Override public void validate(){ super.validate(); - // Add custom validation for module attributes here. + checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker"); } + + @Override public java.lang.AutoCloseable createInstance() { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index a6aa0ce32e..54c94dca9f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -12,6 +12,7 @@ import java.util.Hashtable import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.controller.sal.core.api.data.DataStore +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter class BrokerConfigActivator implements AutoCloseable { @@ -27,6 +28,8 @@ class BrokerConfigActivator implements AutoCloseable { private var SchemaServiceImpl schemaService; private var DataBrokerImpl dataService; private var MountPointManagerImpl mountService; + + SchemaAwareDataStoreAdapter wrappedStore public def void start(BrokerImpl broker,DataStore store,BundleContext context) { val emptyProperties = new Hashtable(); @@ -45,9 +48,13 @@ class BrokerConfigActivator implements AutoCloseable { dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); - dataService.registerConfigurationReader(ROOT, store); - dataService.registerCommitHandler(ROOT, store); - dataService.registerOperationalReader(ROOT, store); + wrappedStore = new SchemaAwareDataStoreAdapter(); + wrappedStore.changeDelegate(store); + wrappedStore.setValidationEnabled(false); + + dataService.registerConfigurationReader(ROOT, wrappedStore); + dataService.registerCommitHandler(ROOT, wrappedStore); + dataService.registerOperationalReader(ROOT, wrappedStore); mountService = new MountPointManagerImpl(); mountService.setDataBroker(dataService); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java index 1197ef34bd..ac5313a9ca 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.dom.broker; import java.util.concurrent.atomic.AtomicLong; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; import org.opendaylight.controller.sal.common.DataStoreIdentifier; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java new file mode 100644 index 0000000000..9116d50d9c --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java @@ -0,0 +1,137 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import java.util.concurrent.atomic.AtomicLong; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public class DataStoreStatsWrapper implements Delegator, DataStore { + + private final DataStore delegate; + + private AtomicLong cfgReadCount = new AtomicLong(); + private AtomicLong cfgReadTimeTotal = new AtomicLong(); + + private AtomicLong operReadCount = new AtomicLong(); + private AtomicLong operReadTimeTotal = new AtomicLong(); + + private AtomicLong requestCommitCount = new AtomicLong(); + private AtomicLong requestCommitTimeTotal = new AtomicLong(); + + public DataStoreStatsWrapper(DataStore store) { + delegate = store; + } + + @Override + public DataStore getDelegate() { + return delegate; + } + + @Override + public CompositeNode readConfigurationData(InstanceIdentifier path) { + cfgReadCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.readConfigurationData(path); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + cfgReadTimeTotal.addAndGet(runTime); + } + } + + @Override + public CompositeNode readOperationalData(InstanceIdentifier path) { + operReadCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.readOperationalData(path); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + cfgReadTimeTotal.addAndGet(runTime); + } + } + + public DataCommitTransaction requestCommit( + DataModification modification) { + requestCommitCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.requestCommit(modification); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + requestCommitTimeTotal.addAndGet(runTime); + } + }; + + @Override + public boolean containsConfigurationPath(InstanceIdentifier path) { + return delegate.containsConfigurationPath(path); + } + + public Iterable getStoredConfigurationPaths() { + return delegate.getStoredConfigurationPaths(); + } + + public Iterable getStoredOperationalPaths() { + return delegate.getStoredOperationalPaths(); + } + + public boolean containsOperationalPath(InstanceIdentifier path) { + return delegate.containsOperationalPath(path); + } + + public final long getConfigurationReadCount() { + return cfgReadCount.get(); + } + + public final long getOperationalReadCount() { + return operReadCount.get(); + } + + public final long getRequestCommitCount() { + return requestCommitCount.get(); + } + + public final long getConfigurationReadTotalTime() { + return cfgReadTimeTotal.get(); + } + + public final long getOperationalReadTotalTime() { + return operReadTimeTotal.get(); + } + + public final long getRequestCommitTotalTime() { + return requestCommitTimeTotal.get(); + } + + public final long getConfigurationReadAverageTime() { + long readCount = cfgReadCount.get(); + if(readCount == 0) { + return 0; + } + return cfgReadTimeTotal.get() / readCount; + } + + public final long getOperationalReadAverageTime() { + long readCount = operReadCount.get(); + if(readCount == 0) { + return 0; + } + return operReadTimeTotal.get() / readCount; + } + + public final long getRequestCommitAverageTime() { + long count = requestCommitCount.get(); + if(count == 0) { + return 0; + } + return requestCommitTimeTotal.get() / count; + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend deleted file mode 100644 index 1a2f947270..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend +++ /dev/null @@ -1,50 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker.impl - -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import java.util.Map -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier -import java.util.Map.Entry -import java.util.HashSet -import java.util.ArrayList -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl - -class DataUtils { - - static def CompositeNode read(Map map, InstanceIdentifier path) { - val root = map.get(path); - val childs = map.getChilds(path); - if(root === null && childs.empty) { - return null; - } - - return merge(path, root, childs); - } - - static def CompositeNode merge(InstanceIdentifier path, CompositeNode node, - HashSet> entries) { - val it = new ArrayList>(); - val qname = path.path.last.nodeType; - if (node != null) { - addAll(node.children); - } - for (entry : entries) { - val nesting = entry.key.path.size - path.path.size; - if (nesting === 1) { - add(entry.value); - } - } - return new CompositeNodeTOImpl(qname, null, it); - } - - static def getChilds(Map map, InstanceIdentifier path) { - val it = new HashSet>(); - for (entry : map.entrySet) { - if (path.contains(entry.key)) { - add(entry); - } - } - return it; - } - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend index e7445e6965..e9ed71a052 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend @@ -9,23 +9,41 @@ import org.opendaylight.controller.sal.common.util.Rpcs import java.util.Collections import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.CompositeNode -import static extension org.opendaylight.controller.sal.dom.broker.impl.DataUtils.*; import org.opendaylight.controller.sal.core.api.data.DataStore import java.util.HashSet class HashMapDataStore implements DataStore, AutoCloseable { + val Map configuration = new ConcurrentHashMap(); val Map operational = new ConcurrentHashMap(); + + + + override containsConfigurationPath(InstanceIdentifier path) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + override containsOperationalPath(InstanceIdentifier path) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getStoredConfigurationPaths() { + configuration.keySet + } + + override getStoredOperationalPaths() { + operational.keySet + } override readConfigurationData(InstanceIdentifier path) { - configuration.read(path); + configuration.get(path); } override readOperationalData(InstanceIdentifier path) { - operational.read(path); + operational.get(path); } - diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend new file mode 100644 index 0000000000..8cdbf9225d --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.dom.broker.impl + +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.yangtools.yang.data.api.CompositeNode + +class SchemaAwareDataMerger { + + private SchemaContext schema; + + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java new file mode 100644 index 0000000000..1f908140b0 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -0,0 +1,245 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import java.awt.PageAttributes.OriginType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; + +import static com.google.common.base.Preconditions.*; + +public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // + DataStore, // + SchemaServiceListener, // + AutoCloseable { + + private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class); + + private SchemaContext schema = null; + private boolean validationEnabled = false; + private SchemaAwareDataMerger dataMerger = null; + private DataReader reader = new MergeFirstLevelReader(); + + @Override + public boolean containsConfigurationPath(InstanceIdentifier path) { + try { + getDelegateReadLock().lock(); + return getDelegate().containsConfigurationPath(path); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public boolean containsOperationalPath(InstanceIdentifier path) { + try { + getDelegateReadLock().lock(); + return getDelegate().containsOperationalPath(path); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public Iterable getStoredConfigurationPaths() { + try { + getDelegateReadLock().lock(); + return getDelegate().getStoredConfigurationPaths(); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public Iterable getStoredOperationalPaths() { + try { + getDelegateReadLock().lock(); + return getDelegate().getStoredOperationalPaths(); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public CompositeNode readConfigurationData(InstanceIdentifier path) { + return reader.readConfigurationData(path); + } + + @Override + public CompositeNode readOperationalData(InstanceIdentifier path) { + return reader.readOperationalData(path); + } + + @Override + public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction requestCommit( + DataModification modification) { + validateAgainstSchema(modification); + DataModification cleanedUp = prepareMergedTransaction(modification); + return retrieveDelegate().requestCommit(cleanedUp); + } + + public boolean isValidationEnabled() { + return validationEnabled; + } + + public void setValidationEnabled(boolean validationEnabled) { + this.validationEnabled = validationEnabled; + } + + private void validateAgainstSchema(DataModification modification) { + if (!validationEnabled) { + return; + } + + if (schema == null) { + LOG.info("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier()); + return; + } + } + + @Override + protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) { + // NOOP + } + + @Override + public void onGlobalContextUpdated(SchemaContext context) { + this.schema = context; + } + + @Override + public void close() throws Exception { + this.schema = null; + } + + private DataModification prepareMergedTransaction( + DataModification original) { + // NOOP for now + return original; + } + + private final Comparator> preparationComparator = new Comparator>() { + @Override + public int compare(Entry o1, Entry o2) { + InstanceIdentifier o1Key = o1.getKey(); + InstanceIdentifier o2Key = o2.getKey(); + return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size()); + } + }; + + private class MergeFirstLevelReader implements DataReader { + + @Override + public CompositeNode readConfigurationData(final InstanceIdentifier path) { + getDelegateReadLock().lock(); + try { + if (path.getPath().isEmpty()) { + return null; + } + QName qname = null; + CompositeNode original = getDelegate().readConfigurationData(path); + ArrayList> childNodes = new ArrayList>(); + if (original != null) { + childNodes.addAll(original.getChildren()); + qname = original.getNodeType(); + } else { + qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); + } + + FluentIterable directChildren = FluentIterable.from(getStoredConfigurationPaths()) + .filter(new Predicate() { + @Override + public boolean apply(InstanceIdentifier input) { + if (path.contains(input)) { + int nesting = input.getPath().size() - path.getPath().size(); + if (nesting == 1) { + return true; + } + } + return false; + } + }); + for (InstanceIdentifier instanceIdentifier : directChildren) { + childNodes.add(getDelegate().readConfigurationData(instanceIdentifier)); + } + if (original == null && childNodes.isEmpty()) { + return null; + } + + return new CompositeNodeTOImpl(qname, null, childNodes); + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public CompositeNode readOperationalData(final InstanceIdentifier path) { + getDelegateReadLock().lock(); + try { + if (path.getPath().isEmpty()) { + return null; + } + QName qname = null; + CompositeNode original = getDelegate().readOperationalData(path); + ArrayList> childNodes = new ArrayList>(); + if (original != null) { + childNodes.addAll(original.getChildren()); + qname = original.getNodeType(); + } else { + qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); + } + + FluentIterable directChildren = FluentIterable.from(getStoredOperationalPaths()) + .filter(new Predicate() { + @Override + public boolean apply(InstanceIdentifier input) { + if (path.contains(input)) { + int nesting = input.getPath().size() - path.getPath().size(); + if (nesting == 1) { + return true; + } + } + return false; + } + }); + + for (InstanceIdentifier instanceIdentifier : directChildren) { + childNodes.add(getDelegate().readOperationalData(instanceIdentifier)); + } + if (original == null && childNodes.isEmpty()) { + return null; + } + + return new CompositeNodeTOImpl(qname, null, childNodes); + } finally { + getDelegateReadLock().unlock(); + } + } + } +} -- 2.36.6