fixing ratelimitable requests and speeding up unit tests

This commit is contained in:
David Goetz
2010年10月08日 11:00:22 -07:00
parent db4689689a
commit 8a47e82dc3

View File

@@ -80,6 +80,7 @@ class RateLimitMiddleware(object):
"""
last_func = None
if container_size:
container_size = int(container_size)
for size, rate, func in self.container_limits:
if container_size < size:
break
@@ -90,7 +91,8 @@ class RateLimitMiddleware(object):
return None
def _generate_key_rate_tuples(self, account_name, container_name, obj_name):
def get_ratelimitable_key_tuples(self, req_method,
account_name, container_name, obj_name):
"""
Returns a list of keys (to be used in memcache) that can be
generated given a path. Keys should be checked in order.
@@ -98,17 +100,21 @@ class RateLimitMiddleware(object):
:param path: path from request
"""
keys = []
if account_name:
if account_name and (
not (container_name or obj_name) or
(container_name and not obj_name and req_method == 'PUT')):
keys.append(("ratelimit/%s" % account_name,
self.account_rate_limit))
if account_name and container_name and not obj_name:
if account_name and container_name and (
(not obj_name and req_method in ('GET','HEAD')) or
(obj_name and req_method in ('PUT','DELETE'))):
container_size = None
memcache_key = get_container_memcache_key(account_name,
container_name)
container_info = self.memcache_client.get(memcache_key)
if type(container_info) == dict:
container_size = int(container_info.get('container_size', 0))
container_size = container_info.get('container_size', 0)
container_rate = self.get_container_maxrate(container_size)
if container_rate:
keys.append(("ratelimit/%s/%s" % (account_name,
@@ -157,9 +163,10 @@ class RateLimitMiddleware(object):
if account_name in self.rate_limit_whitelist:
return None
for key, max_rate in self._generate_key_rate_tuples(account_name,
container_name,
obj_name):
for key, max_rate in self.get_ratelimitable_key_tuples(req.method,
account_name,
container_name,
obj_name):
try:
need_to_sleep = self._get_sleep_time(key, max_rate)
if need_to_sleep > 0:

View File

@@ -877,6 +877,26 @@ class ContainerController(Controller):
self.account_name, self.container_name)
resp = self.GETorHEAD_base(req, 'Container', part, nodes,
req.path_info, self.app.container_ring.replica_count)
# set the memcache container size for ratelimiting
container_size = resp.headers.get('x-container-object-count')
status = resp.status_int
read_acl = None
write_acl = None
cache_key = get_container_memcache_key(self.account_name,
self.container_name)
cache_value = self.app.memcache.get(cache_key)
if hasattr(cache_value, '__iter__'):
if type(cache_value) == dict:
read_acl = cache_value['read_acl']
write_acl = cache_value['write_acl']
else:
status_was, read_acl, write_acl = cache_value
self.app.memcache.set(cache_key, {'status': status,
'read_acl': read_acl,
'write_acl': write_acl,
'container_size': container_size},
timeout=self.app.recheck_container_existence)
if 'swift.authorize' in req.environ:
req.acl = resp.headers.get('x-container-read')
aresp = req.environ['swift.authorize'](req)

View File

@@ -135,17 +135,44 @@ class TestRateLimit(unittest.TestCase):
self.assertEquals(test_ratelimit.get_container_maxrate(60), 72)
self.assertEquals(test_ratelimit.get_container_maxrate(160), 30)
def test_get_ratelimitable_key_tuples(self):
current_rate = 13
conf_dict = {'account_ratelimit': current_rate,
'container_limit_3': 200}
fake_memcache = FakeMemcache()
fake_memcache.store[get_container_memcache_key('a','c')] = \
{'container_size': 5}
the_app = ratelimit.RateLimitMiddleware(None, conf_dict,
logger=FakeLogger())
the_app.memcache_client = fake_memcache
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'GET', 'a', None, None)), 1)
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'POST','a', 'c', None)), 0)
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'PUT', 'a', 'c', None)), 1)
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'GET', 'a', 'c', None)), 1)
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'GET', 'a', 'c', 'o')), 0)
self.assertEquals(len(the_app.get_ratelimitable_key_tuples(
'PUT', 'a', 'c', 'o')), 1)
def test_ratelimit(self):
current_rate = 13
num_calls = 100
num_calls = 5
conf_dict = {'account_ratelimit': current_rate}
self.test_ratelimit = ratelimit.filter_factory(conf_dict)(FakeApp())
ratelimit.http_connect = mock_http_connect(204)
req = Request.blank('/v/a/c')
req = Request.blank('/v/a')
req.environ['swift.cache'] = FakeMemcache()
make_app_call = lambda: self.test_ratelimit(req.environ, start_response)
@@ -235,57 +262,16 @@ class TestRateLimit(unittest.TestCase):
self.assert_(round(time_took, 1) == 0)
def test_ratelimit_max_rate(self):
'''
Running 5 threads at rate 2 a sec. and max sleep of 2 seconds
Expect threads to be run as follows:
t1:0, t2:0, t3:1, t4:1.5, t5:2(Max Rate thrown)
'''
current_rate = 2
conf_dict = {'account_ratelimit': current_rate,
'max_sleep_time_seconds': 2}
self.test_ratelimit = dummy_filter_factory(conf_dict)(FakeApp())
ratelimit.http_connect = mock_http_connect(204)
req = Request.blank('/v/a/c')
req.environ['swift.cache'] = FakeMemcache()
class rate_caller(Thread):
def __init__(self, parent):
Thread.__init__(self)
self.parent = parent
def run(self):
self.result = self.parent.test_ratelimit(req.environ,
start_response)
nt = 5
begin = time.time()
threads = []
for i in range(nt):
rc = rate_caller(self)
rc.start()
threads.append(rc)
for thread in threads:
thread.join()
the_498s = [t for t in threads if \
''.join(t.result).startswith('Slow down')]
self.assertEquals(len(the_498s), 1)
time_took = time.time() - begin
# the 4th request will happen at 1.5
self.assert_(round(time_took, 1) == 1.5)
def test_ratelimit_max_rate_double(self):
current_rate = 2
conf_dict = {'account_ratelimit': current_rate,
'clock_accuracy': 100,
'max_sleep_time_seconds': 4}
'max_sleep_time_seconds': 1}
# making clock less accurate for nosetests running slow
self.test_ratelimit = dummy_filter_factory(conf_dict)(FakeApp())
ratelimit.http_connect = mock_http_connect(204)
req = Request.blank('/v/a/c')
req = Request.blank('/v/a')
req.environ['swift.cache'] = FakeMemcache()
begin = time.time()
@@ -300,8 +286,7 @@ class TestRateLimit(unittest.TestCase):
time.sleep(.1)
self.result2 = self.parent.test_ratelimit(req.environ,
start_response)
nt = 9
nt = 3
threads = []
for i in range(nt):
rc = rate_caller(self, "thread %s" % i)
@@ -313,14 +298,10 @@ class TestRateLimit(unittest.TestCase):
all_results = [''.join(t.result1) for t in threads]
all_results += [''.join(t.result2) for t in threads]
the_498s = [t for t in all_results if t.startswith('Slow down')]
self.assertEquals(len(the_498s), 2)
time_took = time.time() - begin
self.assert_(round(time_took, 1) == 7.5)
self.assert_(round(time_took, 1) == 1.5)
def test_ratelimit_max_rate_multiple_acc(self):
@@ -334,14 +315,16 @@ class TestRateLimit(unittest.TestCase):
the_app = ratelimit.RateLimitMiddleware(None, conf_dict,
logger=FakeLogger())
the_app.memcache_client = fake_memcache
req = lambda: None
req.method = 'GET'
class rate_caller(Thread):
def __init__(self, name):
self.myname = name
Thread.__init__(self)
def run(self):
for j in range(num_calls):
self.result = the_app.handle_rate_limit(None, self.myname,
self.result = the_app.handle_rate_limit(req, self.myname,
None, None)
nt = 15
Reference in New Issue
openstack/swift
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.

The note is not visible to the blocked user.