Improve config system shutdown 77/36777/8
authorTom Pantelis <tpanteli@brocade.com>
Thu, 24 Mar 2016 15:53:39 +0000 (11:53 -0400)
committerAnil Vishnoi <vishnoianil@gmail.com>
Thu, 7 Apr 2016 03:15:01 +0000 (03:15 +0000)
commitc164056dbd60d7df05285ed098b74e85994071d5
treec91578886e5f36f13e718b6ebdff98a63276c250
parent57d7e4788a488d992b9868d44ebc392b06e317c5
Improve config system shutdown

On shutdown, the ModuleFactoryBundleTracker is invoked for every removed
bundle which executes the "blank" transaction which in turn calls
ConfigRegistryImpl#beginConfig. This method is synchronized and may block
if a config commit is in progress (which might be waiting on capabilities or
a ModuleFactory). The ModuleFactoryBundleTracker is invoked
synchronously so this can block karaf shut down. It can affect single feature
tests in particular which start and stop karaf quickly.

I'm not exactly sure what the blank tx is for - I think its purpose is to
indirectly cause the deactivated bundle's module(s) to be destroyed. On
shutdown, the ConfigManagerActivator stop method calls ConfigRegistryImpl#close
which destroys all the modules so we really don't need the blank tx to
run on every bundle on shutdown.

On shutdown, karaf first sends a STOPPING event for the system bundle
(id 0). So I added the ConfigManagerActivator as a bundle listener and when
the system bundle 0 transitions to STOPPING, it calls ConfigRegistryImpl#close.
I also added a closed flag in ConfigRegistryImpl which is checked by
beginConfig and commitConfig. In order to make this work right, I had to change
the synchronization in ConfigRegistryImpl, which really was over-synchronized on
"this". I removed synchronized from the beginConfig and close methods to
break the locking between the two and I made ConfigHolder and TransactionsHolder
classes thread-safe by using ConcurrentHashMap which allows close to access them
safely w/o synchronization.  If the closed flag is set, beginConfig
returns a no-op ObjectName, otherwise it calls the synchronized beginConfigSafe
method. In commitConfig, if closed is set or the ON is the no-op ObjectName,
it returns an an empty CommitStatus.

I also changed from synchronizing "this" to using a Lock to take advantage
of the tryLock functionality. As an added measure of safety against
prolonged blocking, if beginConfig is called with the blank tx flag set,
it tries to acquire the lock for 5 sec. If it fails it returns the no-op
ObjectName.

After the modules are destroyed by ConfigRegistryImpl#close. the container
will proceed to stop the rest of the bundles and the ModuleFactoryBundleTracker
will initiate blank transactions but they'll be no-ops and won't block.

The ModuleFactoryBundleTracker was also changed to only initiate a blank
transaction for bundles that contain a ModuleFactory (via Boolean state
stored with the BundleTracker).

With these changes, karaf shuts down noticeably faster.

The BlankTransactionServiceTracker also initiates a blank transaction
when services are added and removed. Since these are synchronous calls
we really shouldn't block the OSGi container. So I added a
single-threaded executor to process the blank transactions for the
service changes. The blank transaction on bundle removed has to be done
synchronously as it may still need access to the BundleContext which
becomes invalid after the bundle removed event.

Change-Id: I5482caa4182dcc64df9b6bafefac9b8f2d505d3e
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java
opendaylight/config/config-persister-impl/src/main/java/org/opendaylight/controller/config/persist/impl/osgi/ConfigPersisterActivator.java