Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/spdy/spdy_write_queue.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "base/logging.h"
     10 #include "net/spdy/spdy_buffer.h"
     11 #include "net/spdy/spdy_buffer_producer.h"
     12 #include "net/spdy/spdy_stream.h"
     13 
     14 namespace net {
     15 
     16 SpdyWriteQueue::PendingWrite::PendingWrite() : frame_producer(NULL) {}
     17 
     18 SpdyWriteQueue::PendingWrite::PendingWrite(
     19     SpdyFrameType frame_type,
     20     SpdyBufferProducer* frame_producer,
     21     const base::WeakPtr<SpdyStream>& stream)
     22     : frame_type(frame_type),
     23       frame_producer(frame_producer),
     24       stream(stream),
     25       has_stream(stream.get() != NULL) {}
     26 
     27 SpdyWriteQueue::PendingWrite::~PendingWrite() {}
     28 
     29 SpdyWriteQueue::SpdyWriteQueue() {}
     30 
     31 SpdyWriteQueue::~SpdyWriteQueue() {
     32   Clear();
     33 }
     34 
     35 bool SpdyWriteQueue::IsEmpty() const {
     36   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; i++) {
     37     if (!queue_[i].empty())
     38       return false;
     39   }
     40   return true;
     41 }
     42 
     43 void SpdyWriteQueue::Enqueue(RequestPriority priority,
     44                              SpdyFrameType frame_type,
     45                              scoped_ptr<SpdyBufferProducer> frame_producer,
     46                              const base::WeakPtr<SpdyStream>& stream) {
     47   CHECK_GE(priority, MINIMUM_PRIORITY);
     48   CHECK_LE(priority, MAXIMUM_PRIORITY);
     49   if (stream.get())
     50     DCHECK_EQ(stream->priority(), priority);
     51   queue_[priority].push_back(
     52       PendingWrite(frame_type, frame_producer.release(), stream));
     53 }
     54 
     55 bool SpdyWriteQueue::Dequeue(SpdyFrameType* frame_type,
     56                              scoped_ptr<SpdyBufferProducer>* frame_producer,
     57                              base::WeakPtr<SpdyStream>* stream) {
     58   for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
     59     if (!queue_[i].empty()) {
     60       PendingWrite pending_write = queue_[i].front();
     61       queue_[i].pop_front();
     62       *frame_type = pending_write.frame_type;
     63       frame_producer->reset(pending_write.frame_producer);
     64       *stream = pending_write.stream;
     65       if (pending_write.has_stream)
     66         DCHECK(stream->get());
     67       return true;
     68     }
     69   }
     70   return false;
     71 }
     72 
     73 void SpdyWriteQueue::RemovePendingWritesForStream(
     74     const base::WeakPtr<SpdyStream>& stream) {
     75   RequestPriority priority = stream->priority();
     76   CHECK_GE(priority, MINIMUM_PRIORITY);
     77   CHECK_LE(priority, MAXIMUM_PRIORITY);
     78 
     79   DCHECK(stream.get());
     80   if (DCHECK_IS_ON()) {
     81     // |stream| should not have pending writes in a queue not matching
     82     // its priority.
     83     for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
     84       if (priority == i)
     85         continue;
     86       for (std::deque<PendingWrite>::const_iterator it = queue_[i].begin();
     87            it != queue_[i].end(); ++it) {
     88         DCHECK_NE(it->stream.get(), stream.get());
     89       }
     90     }
     91   }
     92 
     93   // Do the actual deletion and removal, preserving FIFO-ness.
     94   std::deque<PendingWrite>* queue = &queue_[priority];
     95   std::deque<PendingWrite>::iterator out_it = queue->begin();
     96   for (std::deque<PendingWrite>::const_iterator it = queue->begin();
     97        it != queue->end(); ++it) {
     98     if (it->stream.get() == stream.get()) {
     99       delete it->frame_producer;
    100     } else {
    101       *out_it = *it;
    102       ++out_it;
    103     }
    104   }
    105   queue->erase(out_it, queue->end());
    106 }
    107 
    108 void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
    109     SpdyStreamId last_good_stream_id) {
    110   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
    111     // Do the actual deletion and removal, preserving FIFO-ness.
    112     std::deque<PendingWrite>* queue = &queue_[i];
    113     std::deque<PendingWrite>::iterator out_it = queue->begin();
    114     for (std::deque<PendingWrite>::const_iterator it = queue->begin();
    115          it != queue->end(); ++it) {
    116       if (it->stream.get() && (it->stream->stream_id() > last_good_stream_id ||
    117                                it->stream->stream_id() == 0)) {
    118         delete it->frame_producer;
    119       } else {
    120         *out_it = *it;
    121         ++out_it;
    122       }
    123     }
    124     queue->erase(out_it, queue->end());
    125   }
    126 }
    127 
    128 void SpdyWriteQueue::Clear() {
    129   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
    130     for (std::deque<PendingWrite>::iterator it = queue_[i].begin();
    131          it != queue_[i].end(); ++it) {
    132       delete it->frame_producer;
    133     }
    134     queue_[i].clear();
    135   }
    136 }
    137 
    138 }  // namespace net
    139