From 247ada2d94e519411bc0c07dc5e54c8190f04f07 Mon Sep 17 00:00:00 2001 From: sridevik Date: Mon, 26 Aug 2013 05:23:34 -0500 Subject: [PATCH] Introduced DB pooling for non blocking DB calls The DbApi module is wrapped with the tpool wrapper if the configuration is enabled. use_tpool is disabled (False) by default Related to bp mysql-thread-pool Change-Id: Ie7274ac855549b96c581c3eb0bcf79f3c74be0ed --- glance/db/__init__.py | 28 ++++++++++- glance/tests/functional/db/test_db_api.py | 60 +++++++++++++++++++++++ test-requirements.txt | 1 + 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 glance/tests/functional/db/test_db_api.py diff --git a/glance/db/__init__.py b/glance/db/__init__.py index 2ab16fdf10..73f5dfa135 100644 --- a/glance/db/__init__.py +++ b/glance/db/__init__.py @@ -17,6 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. +import functools from oslo.config import cfg from glance.common import crypt @@ -25,13 +26,20 @@ import glance.domain import glance.domain.proxy from glance.openstack.common import importutils +db_opt = cfg.BoolOpt('use_tpool', + default=False, + help='Enable the use of thread pooling for ' + 'all DB API calls') CONF = cfg.CONF CONF.import_opt('metadata_encryption_key', 'glance.common.config') +CONF.register_opt(db_opt) def get_api(): - return importutils.import_module(CONF.data_api) + if not CONF.use_tpool: + return importutils.import_module(CONF.data_api) + return ThreadPoolWrapper(CONF.data_api) # attributes common to all models @@ -260,3 +268,21 @@ class ImageMemberRepo(object): image_member = self._format_image_member_from_db( db_api_image_member[0]) return image_member + + +class ThreadPoolWrapper(object): + + def __init__(self, wrapped): + self.wrapped = importutils.import_module(wrapped) + + def __getattr__(self, key): + original = getattr(self.wrapped, key) + if not callable(original): + return original + + @functools.wraps(original) + def wrapper(*args, **kwargs): + from eventlet import tpool + output = tpool.execute(original, *args, **kwargs) + return output + return wrapper diff --git a/glance/tests/functional/db/test_db_api.py b/glance/tests/functional/db/test_db_api.py new file mode 100644 index 0000000000..76ae0e5bfc --- /dev/null +++ b/glance/tests/functional/db/test_db_api.py @@ -0,0 +1,60 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from mock import Mock +from oslo.config import cfg +import testtools + +from glance import db as db_api +from glance.openstack.common import importutils + +CONF = cfg.CONF +CONF.import_opt('use_tpool', 'glance.db') +CONF.import_opt('data_api', 'glance.db') + + +class DbApiTest(testtools.TestCase): + def test_get_dbapi_when_db_pool_is_enabled(self): + CONF.set_override('use_tpool', True) + dbapi = db_api.get_api() + self.assertTrue(isinstance(dbapi, db_api.ThreadPoolWrapper)) + + def test_get_dbapi_when_db_pool_is_disabled(self): + CONF.set_override('use_tpool', False) + dbapi = db_api.get_api() + self.assertFalse(isinstance(dbapi, db_api.ThreadPoolWrapper)) + self.assertEqual(importutils.import_module(CONF.data_api), dbapi) + + +def method_for_test_1(*args, **kwargs): + return args, kwargs + + +class ThreadPoolWrapper(testtools.TestCase): + def test_thread_pool(self): + module = importutils.import_module('glance.tests.functional.db.' + 'test_db_api') + CONF.set_override('use_tpool', True) + CONF.set_override('data_api', 'glance.tests.functional.db.' + 'test_db_api') + dbapi = db_api.get_api() + + from eventlet import tpool + tpool.execute = Mock() + + dbapi.method_for_test_1(1, 2, kwarg='arg') + tpool.execute.assert_called_with(method_for_test_1, 1, 2, kwarg='arg') diff --git a/test-requirements.txt b/test-requirements.txt index 84ec717045..22731691fd 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -14,6 +14,7 @@ mox>=0.5.3 nose nose-exclude openstack.nose_plugin>=0.7 +mock>=1.0 nosehtmloutput>=0.0.3 sphinx>=1.1.2 requests>=1.1