Merge "x-newest cleanup code with test. Fixes bug 1037337"

This commit is contained in:
Jenkins
2012-08-28 20:09:00 +00:00
committed by Gerrit Code Review
2 changed files with 67 additions and 17 deletions

View File

@@ -504,20 +504,7 @@ class Controller(object):
queue.put(success) queue.put(success)
# Close-out the connection as best as possible. # Close-out the connection as best as possible.
if getattr(source, 'swift_conn', None): if getattr(source, 'swift_conn', None):
try: self.close_swift_conn(source)
source.swift_conn.close()
except Exception:
pass
source.swift_conn = None
try:
while source.read(self.app.object_chunk_size):
pass
except Exception:
pass
try:
source.close()
except Exception:
pass
def _make_app_iter(self, node, source, response): def _make_app_iter(self, node, source, response):
""" """
@@ -559,6 +546,22 @@ class Controller(object):
finally: finally:
response.app_iter = None response.app_iter = None
def close_swift_conn(self, src):
try:
src.swift_conn.close()
except Exception:
pass
src.swift_conn = None
try:
while src.read(self.app.object_chunk_size):
pass
except Exception:
pass
try:
src.close()
except Exception:
pass
def GETorHEAD_base(self, req, server_type, partition, nodes, path, def GETorHEAD_base(self, req, server_type, partition, nodes, path,
attempts): attempts):
""" """
@@ -576,6 +579,7 @@ class Controller(object):
reasons = [] reasons = []
bodies = [] bodies = []
source = None source = None
sources = []
newest = req.headers.get('x-newest', 'f').lower() in TRUE_VALUES newest = req.headers.get('x-newest', 'f').lower() in TRUE_VALUES
nodes = iter(nodes) nodes = iter(nodes)
while len(statuses) < attempts: while len(statuses) < attempts:
@@ -615,16 +619,19 @@ class Controller(object):
possible_source.read() possible_source.read()
continue continue
if newest: if newest:
if source: if sources:
ts = float(source.getheader('x-put-timestamp') or ts = float(source.getheader('x-put-timestamp') or
source.getheader('x-timestamp') or 0) source.getheader('x-timestamp') or 0)
pts = float( pts = float(
possible_source.getheader('x-put-timestamp') or possible_source.getheader('x-put-timestamp') or
possible_source.getheader('x-timestamp') or 0) possible_source.getheader('x-timestamp') or 0)
if pts > ts: if pts > ts:
source = possible_source sources.insert(0, possible_source)
else: else:
source = possible_source sources.append(possible_source)
else:
sources.insert(0, possible_source)
source = sources[0]
statuses.append(source.status) statuses.append(source.status)
reasons.append(source.reason) reasons.append(source.reason)
bodies.append('') bodies.append('')
@@ -643,6 +650,12 @@ class Controller(object):
if source: if source:
if req.method == 'GET' and \ if req.method == 'GET' and \
source.status in (HTTP_OK, HTTP_PARTIAL_CONTENT): source.status in (HTTP_OK, HTTP_PARTIAL_CONTENT):
if newest:
# we need to close all hanging swift_conns
sources.pop(0)
for src in sources:
self.close_swift_conn(src)
res = Response(request=req, conditional_response=True) res = Response(request=req, conditional_response=True)
res.app_iter = self._make_app_iter(node, source, res) res.app_iter = self._make_app_iter(node, source, res)
# See NOTE: swift_conn at top of file about this. # See NOTE: swift_conn at top of file about this.

View File

@@ -20,6 +20,7 @@ from logging.handlers import SysLogHandler
import os import os
import sys import sys
import unittest import unittest
import signal
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from contextlib import contextmanager from contextlib import contextmanager
from cStringIO import StringIO from cStringIO import StringIO
@@ -704,6 +705,42 @@ class TestObjectController(unittest.TestCase):
res = method(req) res = method(req)
self.assertEquals(res.status_int, expected) self.assertEquals(res.status_int, expected)
def test_GET_newest_large_file(self):
calls = [0]
def handler(_junk1, _junk2):
calls[0] += 1
try:
signal.signal(signal.SIGPIPE, handler)
prolis = _test_sockets[0]
prosrv = _test_servers[0]
sock = connect_tcp(('localhost', prolis.getsockname()[1]))
fd = sock.makefile()
obj = 'a' * (1024 * 1024)
path = '/v1/a/c/o.large'
fd.write('PUT %s HTTP/1.1\r\n'
'Host: localhost\r\n'
'Connection: close\r\n'
'X-Storage-Token: t\r\n'
'Content-Length: %s\r\n'
'Content-Type: application/octet-stream\r\n'
'\r\n%s' % (path, str(len(obj)), obj))
fd.flush()
headers = readuntil2crlfs(fd)
exp = 'HTTP/1.1 201'
self.assertEqual(headers[:len(exp)], exp)
req = Request.blank(path,
environ={'REQUEST_METHOD': 'GET'},
headers={'Content-Type': 'application/octet-stream',
'X-Newest':'true'})
res = req.get_response(prosrv)
self.assertEqual(res.status_int, 200)
self.assertEqual(res.body, obj)
self.assertEqual(calls[0], 0)
finally:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
def test_PUT_auto_content_type(self): def test_PUT_auto_content_type(self):
with save_globals(): with save_globals():
controller = proxy_server.ObjectController(self.app, 'account', controller = proxy_server.ObjectController(self.app, 'account',