Skip to content

Loading…

Cache the entry points discovered within a namespace #3

Merged
merged 1 commit into from

3 participants

@dhellmann

Scanning the entry point registry is relatively expensive
and causes performance issues with unit tests of code
depending on stevedore. This change addresses the
performance issues by caching the entry points as
they are loaded from pkg_resources in a class attribute
in the base class of the extension managesr so they can
be reused by other instances.

Change-Id: Iba7bee6790cdedc94cb537e2ed6e12219c85f26a
Signed-off-by: Doug Hellmann doug.hellmann@dreamhost.com

@dhellmann dhellmann Cache the entry points discovered within a namespace
Scanning the entry point registry is relatively expensive
and causes performance issues with unit tests of code
depending on stevedore. This change addresses the
performance issues by caching the entry points as
they are loaded from pkg_resources in a class attribute
in the base class of the extension managesr so they can
be reused by other instances.

Change-Id: Iba7bee6790cdedc94cb537e2ed6e12219c85f26a
Signed-off-by: Doug Hellmann <doug.hellmann@dreamhost.com>
7bdc14c
@dhellmann

I've also sent this to Monty Taylor to review, so please don't merge until he's had a chance to look at it.

@emonty

I think this looks great!

@markmcclain markmcclain merged commit 2106ab5 into dreamhost:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 26, 2012
  1. @dhellmann

    Cache the entry points discovered within a namespace

    dhellmann committed
    Scanning the entry point registry is relatively expensive
    and causes performance issues with unit tests of code
    depending on stevedore. This change addresses the
    performance issues by caching the entry points as
    they are loaded from pkg_resources in a class attribute
    in the base class of the extension managesr so they can
    be reused by other instances.
    
    Change-Id: Iba7bee6790cdedc94cb537e2ed6e12219c85f26a
    Signed-off-by: Doug Hellmann <doug.hellmann@dreamhost.com>
This page is out of date. Refresh to see the latest.
Showing with 44 additions and 1 deletion.
  1. +9 −1 stevedore/extension.py
  2. +35 −0 stevedore/tests/test_extension.py
View
10 stevedore/extension.py
@@ -56,9 +56,17 @@ def __init__(self, namespace,
invoke_args,
invoke_kwds)
+ ENTRY_POINT_CACHE = {}
+
+ def _find_entry_points(self, namespace):
+ if namespace not in self.ENTRY_POINT_CACHE:
+ eps = list(pkg_resources.iter_entry_points(namespace))
+ self.ENTRY_POINT_CACHE[namespace] = eps
+ return self.ENTRY_POINT_CACHE[namespace]
+
def _load_plugins(self, invoke_on_load, invoke_args, invoke_kwds):
extensions = []
- for ep in pkg_resources.iter_entry_points(self.namespace):
+ for ep in self._find_entry_points(self.namespace):
LOG.debug('found extension %r', ep)
try:
ext = self._load_one_plugin(ep,
View
35 stevedore/tests/test_extension.py
@@ -1,6 +1,8 @@
"""Tests for stevedore.extension
"""
+import mock
+
from stevedore import extension
@@ -16,6 +18,39 @@ def test_detect_plugins():
assert names == ['t1', 't2']
+def test_load_multiple_times_entry_points():
+ # We expect to get the same EntryPoint object because we save them
+ # in the cache.
+ em1 = extension.ExtensionManager('stevedore.test.extension')
+ eps1 = [ext.entry_point for ext in em1]
+ em2 = extension.ExtensionManager('stevedore.test.extension')
+ eps2 = [ext.entry_point for ext in em2]
+ assert eps1[0] is eps2[0]
+
+
+def test_load_multiple_times_plugins():
+ # We expect to get the same plugin object (module or class)
+ # because the underlying import machinery will cache the values.
+ em1 = extension.ExtensionManager('stevedore.test.extension')
+ plugins1 = [ext.plugin for ext in em1]
+ em2 = extension.ExtensionManager('stevedore.test.extension')
+ plugins2 = [ext.plugin for ext in em2]
+ assert plugins1[0] is plugins2[0]
+
+
+def test_use_cache():
+ # If we insert something into the cache of entry points,
+ # the manager should not have to call into pkg_resources
+ # to find the plugins.
+ cache = extension.ExtensionManager.ENTRY_POINT_CACHE
+ cache['stevedore.test.faux'] = []
+ with mock.patch('pkg_resources.iter_entry_points',
+ side_effect=AssertionError('called iter_entry_points')):
+ em = extension.ExtensionManager('stevedore.test.faux')
+ names = em.names()
+ assert names == []
+
+
def test_iterable():
em = extension.ExtensionManager('stevedore.test.extension')
names = sorted(e.name for e in em)
Something went wrong with that request. Please try again.