Make image upload tpool usage conditional
When running in eventlet mode we keep the original eventlet.tpool usage but when running in threading mode we call the functions directly on the thread of the caller. The original tpool_execute() call made the upload call running in a native tread as it has parts that are blocking and therefore running them in the current greenthread would make the other greenthreads starved. After this patch we preserve the same effect but with different syntax. We use tpool_wrap to wrap the function into a tpool.Proxy object and then call the proxy object. That proxy ensures that any call on the proxy object is run in a native thread. This change is useful for us in native threaded mode. There the tpool_wrap returns the function unchanged. So upload is executed in the caller's native thread. This is OK as in native threaded mode any concurrent tasks are also in native threads and native threads are preempted when needed. So other tasks will not be starved. Change-Id: Iddb8b317b7a883c6fd144a93aca862a792fcd1af Signed-off-by: Balazs Gibizer <gibi@redhat.com>
This commit is contained in:
@@ -585,11 +585,10 @@ class GlanceImageServiceV2(object):
|
||||
_reraise_translated_exception()
|
||||
|
||||
def _upload_data(self, context, image_id, data):
|
||||
# NOTE(aarents) offload upload in a native thread as it can block
|
||||
# coroutine in busy environment.
|
||||
utils.tpool_execute(self._client.call,
|
||||
context, 2, 'upload',
|
||||
args=(image_id, data))
|
||||
# NOTE(aarents) In eventlet mode offload upload in a native thread as
|
||||
# it can block coroutine in busy environment.
|
||||
utils.tpool_wrap(
|
||||
self._client.call)(context, 2, 'upload', args=(image_id, data))
|
||||
|
||||
return self._client.call(context, 2, 'get', args=(image_id,))
|
||||
|
||||
|
||||
@@ -1914,13 +1914,12 @@ class TestCreate(test.NoDBTestCase):
|
||||
class TestUpdate(test.NoDBTestCase):
|
||||
|
||||
"""Tests the update method of the GlanceImageServiceV2."""
|
||||
@mock.patch('nova.utils.tpool_execute',
|
||||
side_effect=nova.utils.tpool_execute)
|
||||
@mock.patch('nova.utils.tpool_wrap')
|
||||
@mock.patch('nova.image.glance.GlanceImageServiceV2.show')
|
||||
@mock.patch('nova.image.glance._translate_from_glance')
|
||||
@mock.patch('nova.image.glance._translate_to_glance')
|
||||
def test_update_success_v2(
|
||||
self, trans_to_mock, trans_from_mock, show_mock, texec_mock):
|
||||
self, trans_to_mock, trans_from_mock, show_mock, twrap_mock):
|
||||
image = {
|
||||
'id': mock.sentinel.image_id,
|
||||
'name': mock.sentinel.name,
|
||||
@@ -1937,6 +1936,7 @@ class TestUpdate(test.NoDBTestCase):
|
||||
trans_from_mock.return_value = mock.sentinel.trans_from
|
||||
client = mock.MagicMock()
|
||||
client.call.return_value = mock.sentinel.image_meta
|
||||
twrap_mock.return_value = client.call
|
||||
ctx = mock.sentinel.ctx
|
||||
show_mock.return_value = {
|
||||
'image_id': mock.sentinel.image_id,
|
||||
@@ -1969,8 +1969,9 @@ class TestUpdate(test.NoDBTestCase):
|
||||
data=mock.sentinel.data)
|
||||
|
||||
self.assertEqual(3, client.call.call_count)
|
||||
texec_mock.assert_called_once_with(
|
||||
client.call, ctx, 2, 'upload',
|
||||
twrap_mock.assert_called_once_with(client.call)
|
||||
twrap_mock.return_value.assert_any_call(
|
||||
ctx, 2, 'upload',
|
||||
args=(mock.sentinel.image_id,
|
||||
mock.sentinel.data))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user