Extract quorum-size calculation to utility method.
The behavior's the same as before; this just makes the code (IMHO) a little easier to read. Change-Id: Ie54d836d81af7410057219f60b72b840c9ce51b9
This commit is contained in:
parent
e759dad84f
commit
885e02102d
@ -1856,6 +1856,14 @@ def public(func):
|
|||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
|
def quorum_size(n):
|
||||||
|
"""
|
||||||
|
Number of successful backend requests needed for the proxy to consider
|
||||||
|
the client request successful.
|
||||||
|
"""
|
||||||
|
return (n // 2) + 1
|
||||||
|
|
||||||
|
|
||||||
def rsync_ip(ip):
|
def rsync_ip(ip):
|
||||||
"""
|
"""
|
||||||
Transform ip string to an rsync-compatible form
|
Transform ip string to an rsync-compatible form
|
||||||
|
@ -37,7 +37,8 @@ from eventlet.timeout import Timeout
|
|||||||
|
|
||||||
from swift.common.wsgi import make_pre_authed_env
|
from swift.common.wsgi import make_pre_authed_env
|
||||||
from swift.common.utils import normalize_timestamp, config_true_value, \
|
from swift.common.utils import normalize_timestamp, config_true_value, \
|
||||||
public, split_path, list_from_csv, GreenthreadSafeIterator
|
public, split_path, list_from_csv, GreenthreadSafeIterator, \
|
||||||
|
quorum_size
|
||||||
from swift.common.bufferedhttp import http_connect
|
from swift.common.bufferedhttp import http_connect
|
||||||
from swift.common.exceptions import ChunkReadTimeout, ConnectionTimeout
|
from swift.common.exceptions import ChunkReadTimeout, ConnectionTimeout
|
||||||
from swift.common.http import is_informational, is_success, is_redirection, \
|
from swift.common.http import is_informational, is_success, is_redirection, \
|
||||||
@ -749,7 +750,7 @@ class Controller(object):
|
|||||||
for hundred in (HTTP_OK, HTTP_MULTIPLE_CHOICES, HTTP_BAD_REQUEST):
|
for hundred in (HTTP_OK, HTTP_MULTIPLE_CHOICES, HTTP_BAD_REQUEST):
|
||||||
hstatuses = \
|
hstatuses = \
|
||||||
[s for s in statuses if hundred <= s < hundred + 100]
|
[s for s in statuses if hundred <= s < hundred + 100]
|
||||||
if len(hstatuses) > len(statuses) / 2:
|
if len(hstatuses) >= quorum_size(len(statuses)):
|
||||||
status = max(hstatuses)
|
status = max(hstatuses)
|
||||||
status_index = statuses.index(status)
|
status_index = statuses.index(status)
|
||||||
resp.status = '%s %s' % (status, reasons[status_index])
|
resp.status = '%s %s' % (status, reasons[status_index])
|
||||||
|
@ -37,7 +37,8 @@ from eventlet.queue import Queue
|
|||||||
from eventlet.timeout import Timeout
|
from eventlet.timeout import Timeout
|
||||||
|
|
||||||
from swift.common.utils import ContextPool, normalize_timestamp, \
|
from swift.common.utils import ContextPool, normalize_timestamp, \
|
||||||
config_true_value, public, json, csv_append, GreenthreadSafeIterator
|
config_true_value, public, json, csv_append, GreenthreadSafeIterator, \
|
||||||
|
quorum_size
|
||||||
from swift.common.bufferedhttp import http_connect
|
from swift.common.bufferedhttp import http_connect
|
||||||
from swift.common.constraints import check_metadata, check_object_creation, \
|
from swift.common.constraints import check_metadata, check_object_creation, \
|
||||||
CONTAINER_LISTING_LIMIT, MAX_FILE_SIZE, MAX_BUFFERED_SLO_SEGMENTS
|
CONTAINER_LISTING_LIMIT, MAX_FILE_SIZE, MAX_BUFFERED_SLO_SEGMENTS
|
||||||
@ -1016,11 +1017,12 @@ class ObjectController(Controller):
|
|||||||
req.path_info, nheaders, self.app.logger.thread_locals)
|
req.path_info, nheaders, self.app.logger.thread_locals)
|
||||||
|
|
||||||
conns = [conn for conn in pile if conn]
|
conns = [conn for conn in pile if conn]
|
||||||
if len(conns) <= len(nodes) / 2:
|
min_conns = quorum_size(len(nodes))
|
||||||
|
if len(conns) < min_conns:
|
||||||
self.app.logger.error(
|
self.app.logger.error(
|
||||||
_('Object PUT returning 503, %(conns)s/%(nodes)s '
|
_('Object PUT returning 503, %(conns)s/%(nodes)s '
|
||||||
'required connections'),
|
'required connections'),
|
||||||
{'conns': len(conns), 'nodes': len(nodes) // 2 + 1})
|
{'conns': len(conns), 'nodes': min_conns})
|
||||||
return HTTPServiceUnavailable(request=req)
|
return HTTPServiceUnavailable(request=req)
|
||||||
bytes_transferred = 0
|
bytes_transferred = 0
|
||||||
try:
|
try:
|
||||||
@ -1047,11 +1049,11 @@ class ObjectController(Controller):
|
|||||||
if chunked else chunk)
|
if chunked else chunk)
|
||||||
else:
|
else:
|
||||||
conns.remove(conn)
|
conns.remove(conn)
|
||||||
if len(conns) <= len(nodes) / 2:
|
if len(conns) < min_conns:
|
||||||
self.app.logger.error(_(
|
self.app.logger.error(_(
|
||||||
'Object PUT exceptions during'
|
'Object PUT exceptions during'
|
||||||
' send, %(conns)s/%(nodes)s required connections'),
|
' send, %(conns)s/%(nodes)s required connections'),
|
||||||
{'conns': len(conns), 'nodes': len(nodes) / 2 + 1})
|
{'conns': len(conns), 'nodes': min_conns})
|
||||||
return HTTPServiceUnavailable(request=req)
|
return HTTPServiceUnavailable(request=req)
|
||||||
for conn in conns:
|
for conn in conns:
|
||||||
if conn.queue.unfinished_tasks:
|
if conn.queue.unfinished_tasks:
|
||||||
|
@ -1126,6 +1126,15 @@ log_name = %(yarr)s'''
|
|||||||
self.assertFalse(utils.streq_const_time('a', 'aaaaa'))
|
self.assertFalse(utils.streq_const_time('a', 'aaaaa'))
|
||||||
self.assertFalse(utils.streq_const_time('ABC123', 'abc123'))
|
self.assertFalse(utils.streq_const_time('ABC123', 'abc123'))
|
||||||
|
|
||||||
|
def test_quorum_size(self):
|
||||||
|
expected_sizes = {1: 1,
|
||||||
|
2: 2,
|
||||||
|
3: 2,
|
||||||
|
4: 3,
|
||||||
|
5: 3}
|
||||||
|
got_sizes = dict([(n, utils.quorum_size(n)) for n in expected_sizes])
|
||||||
|
self.assertEqual(expected_sizes, got_sizes)
|
||||||
|
|
||||||
def test_rsync_ip_ipv4_localhost(self):
|
def test_rsync_ip_ipv4_localhost(self):
|
||||||
self.assertEqual(utils.rsync_ip('127.0.0.1'), '127.0.0.1')
|
self.assertEqual(utils.rsync_ip('127.0.0.1'), '127.0.0.1')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user