diff --git a/swift/proxy/controllers/obj.py b/swift/proxy/controllers/obj.py index 0d089fb2c8..99b939af9c 100644 --- a/swift/proxy/controllers/obj.py +++ b/swift/proxy/controllers/obj.py @@ -111,7 +111,7 @@ class SegmentedIterable(object): self.container = container self.listing = segment_listing_iter(listing) self.is_slo = is_slo - self.segment = 0 + self.ratelimit_index = 0 self.segment_dict = None self.segment_peek = None self.seek = 0 @@ -132,7 +132,7 @@ class SegmentedIterable(object): segment no longer matches SLO manifest specifications. """ try: - self.segment += 1 + self.ratelimit_index += 1 self.segment_dict = self.segment_peek or self.listing.next() self.segment_peek = None if self.container is None: @@ -147,7 +147,7 @@ class SegmentedIterable(object): if self.seek: req.range = 'bytes=%s-' % self.seek self.seek = 0 - if not self.is_slo and self.segment > \ + if not self.is_slo and self.ratelimit_index > \ self.controller.app.rate_limit_after_segment: sleep(max(self.next_get_time - time.time(), 0)) self.next_get_time = time.time() + \ @@ -246,7 +246,6 @@ class SegmentedIterable(object): if start: self.segment_peek = self.listing.next() while start >= self.position + self.segment_peek['bytes']: - self.segment += 1 self.position += self.segment_peek['bytes'] self.segment_peek = self.listing.next() self.seek = start - self.position diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 094a72edb3..ceec7e6ae6 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -5466,10 +5466,51 @@ class TestSegmentedIterable(unittest.TestCase): finally: swift.proxy.controllers.obj.sleep = orig_sleep + def test_load_next_segment_range_req_rate_limiting(self): + sleep_calls = [] + + def _stub_sleep(sleepy_time): + sleep_calls.append(sleepy_time) + orig_sleep = swift.proxy.controllers.obj.sleep + try: + swift.proxy.controllers.obj.sleep = _stub_sleep + segit = SegmentedIterable( + self.controller, 'lc', [ + {'name': 'o0', 'bytes': 5}, {'name': 'o1', 'bytes': 5}, + {'name': 'o2', 'bytes': 1}, {'name': 'o3'}, {'name': 'o4'}, + {'name': 'o5'}, {'name': 'o6'}]) + + # this tests for a range request which skips over the whole first + # segment, after that 3 segments will be read in because the + # rate_limit_after_segment == 3, then sleeping starts + segit_iter = segit.app_iter_range(10, None) + segit_iter.next() + for _ in xrange(2): + # this is set to 2 instead of 3 because o2 was loaded after + # o0 and o1 were skipped. + segit._load_next_segment() + self.assertEquals([], sleep_calls) + self.assertEquals(self.controller.GETorHEAD_base_args[4], + '/a/lc/o4') + + # Loading of next (5th) segment starts rate-limiting. + segit._load_next_segment() + self.assertAlmostEqual(0.5, sleep_calls[0], places=2) + self.assertEquals(self.controller.GETorHEAD_base_args[4], + '/a/lc/o5') + + sleep_calls = [] + segit._load_next_segment() + self.assertAlmostEqual(0.5, sleep_calls[0], places=2) + self.assertEquals(self.controller.GETorHEAD_base_args[4], + '/a/lc/o6') + finally: + swift.proxy.controllers.obj.sleep = orig_sleep + def test_load_next_segment_with_two_segments_skip_first(self): segit = SegmentedIterable(self.controller, 'lc', [{'name': 'o1'}, {'name': 'o2'}]) - segit.segment = 0 + segit.ratelimit_index = 0 segit.listing.next() segit._load_next_segment() self.assertEquals(self.controller.GETorHEAD_base_args[4], '/a/lc/o2') @@ -5479,7 +5520,7 @@ class TestSegmentedIterable(unittest.TestCase): def test_load_next_segment_with_seek(self): segit = SegmentedIterable(self.controller, 'lc', [{'name': 'o1'}, {'name': 'o2'}]) - segit.segment = 0 + segit.ratelimit_index = 0 segit.listing.next() segit.seek = 1 segit._load_next_segment()