Merge "Extract quorum-size calculation to utility method."
This commit is contained in:
commit
cbc29e43be
@ -1856,6 +1856,14 @@ def public(func):
|
||||
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):
|
||||
"""
|
||||
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.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.exceptions import ChunkReadTimeout, ConnectionTimeout
|
||||
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):
|
||||
hstatuses = \
|
||||
[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_index = statuses.index(status)
|
||||
resp.status = '%s %s' % (status, reasons[status_index])
|
||||
|
@ -37,7 +37,8 @@ from eventlet.queue import Queue
|
||||
from eventlet.timeout import Timeout
|
||||
|
||||
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.constraints import check_metadata, check_object_creation, \
|
||||
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)
|
||||
|
||||
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(
|
||||
_('Object PUT returning 503, %(conns)s/%(nodes)s '
|
||||
'required connections'),
|
||||
{'conns': len(conns), 'nodes': len(nodes) // 2 + 1})
|
||||
{'conns': len(conns), 'nodes': min_conns})
|
||||
return HTTPServiceUnavailable(request=req)
|
||||
bytes_transferred = 0
|
||||
try:
|
||||
@ -1047,11 +1049,11 @@ class ObjectController(Controller):
|
||||
if chunked else chunk)
|
||||
else:
|
||||
conns.remove(conn)
|
||||
if len(conns) <= len(nodes) / 2:
|
||||
if len(conns) < min_conns:
|
||||
self.app.logger.error(_(
|
||||
'Object PUT exceptions during'
|
||||
' 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)
|
||||
for conn in conns:
|
||||
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('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):
|
||||
self.assertEqual(utils.rsync_ip('127.0.0.1'), '127.0.0.1')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user