'Handles the UPDATES step of an SSYNC request.
Receives a set of PUT and DELETE subrequests that will be
routed to the object server itself for processing. These
contain the information requested by the MISSING_CHECK step.
The PUT and DELETE subrequests are formatted pretty much
exactly like regular HTTP requests, excepting the HTTP
version on the first request line.
The process is generally:
1. Sender sends `:UPDATES: START` and begins sending the
PUT and DELETE subrequests.
2. Receiver gets `:UPDATES: START` and begins routing the
subrequests to the object server.
3. Sender sends `:UPDATES: END`.
4. Receiver gets `:UPDATES: END` and sends `:UPDATES:
START` and `:UPDATES: END` (assuming no errors).
5. Sender gets `:UPDATES: START` and `:UPDATES: END`.
If too many subrequests fail, as configured by
replication_failure_threshold and replication_failure_ratio,
the receiver will hang up the request early so as to not
waste any more time.
At step 4, the receiver will send back an error if there were
any failures (that didn\'t cause a hangup due to the above
thresholds) so the sender knows the whole was not entirely a
success. This is so the sender knows if it can remove an out
of place partition, for example.'

def updates(self):

    with exceptions.MessageTimeout(self.app.client_timeout, 'updates    start'):
        line = self.fp.readline(self.app.network_chunk_size)
    if (line.strip() != ':UPDATES:    START'):
        raise Exception(('Looking    for    :UPDATES:    START    got    %r' % line[:1024]))
    successes = 0
    failures = 0
    while True:
        with exceptions.MessageTimeout(self.app.client_timeout, 'updates    line'):
            line = self.fp.readline(self.app.network_chunk_size)
        if ((not line) or (line.strip() == ':UPDATES:    END')):
            break
        (method, path) = line.strip().split('    ', 1)
        subreq = swob.Request.blank(('/%s/%s%s' % (self.device, self.partition, path)), environ={'REQUEST_METHOD': method})
        content_length = None
        replication_headers = []
        while True:
            with exceptions.MessageTimeout(self.app.client_timeout):
                line = self.fp.readline(self.app.network_chunk_size)
            if (not line):
                raise Exception(('Got    no    headers    for    %s    %s' % (method, path)))
            line = line.strip()
            if (not line):
                break
            (header, value) = line.split(':', 1)
            header = header.strip().lower()
            value = value.strip()
            subreq.headers[header] = value
            if (header != 'etag'):
                replication_headers.append(header)
            if (header == 'content-length'):
                content_length = int(value)
        if (method in ('DELETE', 'POST')):
            if (content_length not in (None, 0)):
                raise Exception(('%s    subrequest    with    content-length    %s' % (method, path)))
        elif (method == 'PUT'):
            if (content_length is None):
                raise Exception(('No    content-length    sent    for    %s    %s' % (method, path)))
            def subreq_iter():
                left = content_length
                while (left > 0):
                    with exceptions.MessageTimeout(self.app.client_timeout, 'updates    content'):
                        chunk = self.fp.read(min(left, self.app.network_chunk_size))
                    if (not chunk):
                        raise exceptions.ChunkReadError(('Early    termination    for    %s    %s' % (method, path)))
                    left -= len(chunk)
                    (yield chunk)
            subreq.environ['wsgi.input'] = utils.FileLikeIter(subreq_iter())
        else:
            raise Exception(('Invalid    subrequest    method    %s' % method))
        subreq.headers['X-Backend-Storage-Policy-Index'] = int(self.policy)
        subreq.headers['X-Backend-Replication'] = 'True'
        if (self.node_index is not None):
            subreq.headers['X-Backend-Ssync-Frag-Index'] = self.node_index
        if replication_headers:
            subreq.headers['X-Backend-Replication-Headers'] = '    '.join(replication_headers)
        resp = subreq.get_response(self.app)
        if (http.is_success(resp.status_int) or (resp.status_int == http.HTTP_NOT_FOUND)):
            successes += 1
        else:
            self.app.logger.warning(('ssync    subrequest    failed    with    %s:    %s    %s' % (resp.status_int, method, subreq.path)))
            failures += 1
        if ((failures >= self.app.replication_failure_threshold) and ((not successes) or ((float(failures) / successes) > self.app.replication_failure_ratio))):
            raise Exception(('Too    many    %d    failures    to    %d    successes' % (failures, successes)))
        for junk in subreq.environ['wsgi.input']:
            pass
    if failures:
        raise swob.HTTPInternalServerError(('ERROR:    With    :UPDATES:    %d    failures    to    %d    successes' % (failures, successes)))
    (yield ':UPDATES:    START\r\n')
    (yield ':UPDATES:    END\r\n')
