• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 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/tools/flip_server/output_ordering.h"
6 
7 #include <utility>
8 
9 #include "net/tools/flip_server/flip_config.h"
10 #include "net/tools/flip_server/sm_connection.h"
11 
12 namespace net {
13 
PriorityMapPointer()14 OutputOrdering::PriorityMapPointer::PriorityMapPointer()
15     : ring(NULL), alarm_enabled(false) {}
16 
~PriorityMapPointer()17 OutputOrdering::PriorityMapPointer::~PriorityMapPointer() {}
18 
19 // static
20 double OutputOrdering::server_think_time_in_s_ = 0.0;
21 
OutputOrdering(SMConnectionInterface * connection)22 OutputOrdering::OutputOrdering(SMConnectionInterface* connection)
23     : first_data_senders_threshold_(kInitialDataSendersThreshold),
24       connection_(connection) {
25   if (connection)
26     epoll_server_ = connection->epoll_server();
27 }
28 
~OutputOrdering()29 OutputOrdering::~OutputOrdering() { Reset(); }
30 
Reset()31 void OutputOrdering::Reset() {
32   while (!stream_ids_.empty()) {
33     StreamIdToPriorityMap::iterator sitpmi = stream_ids_.begin();
34     PriorityMapPointer& pmp = sitpmi->second;
35     if (pmp.alarm_enabled) {
36       epoll_server_->UnregisterAlarm(pmp.alarm_token);
37     }
38     stream_ids_.erase(sitpmi);
39   }
40   priority_map_.clear();
41   first_data_senders_.clear();
42 }
43 
ExistsInPriorityMaps(uint32 stream_id) const44 bool OutputOrdering::ExistsInPriorityMaps(uint32 stream_id) const {
45   StreamIdToPriorityMap::const_iterator sitpmi = stream_ids_.find(stream_id);
46   return sitpmi != stream_ids_.end();
47 }
48 
BeginOutputtingAlarm(OutputOrdering * oo,OutputOrdering::PriorityMapPointer * pmp,const MemCacheIter & mci)49 OutputOrdering::BeginOutputtingAlarm::BeginOutputtingAlarm(
50     OutputOrdering* oo,
51     OutputOrdering::PriorityMapPointer* pmp,
52     const MemCacheIter& mci)
53     : output_ordering_(oo), pmp_(pmp), mci_(mci), epoll_server_(NULL) {}
54 
~BeginOutputtingAlarm()55 OutputOrdering::BeginOutputtingAlarm::~BeginOutputtingAlarm() {
56   if (epoll_server_ && pmp_->alarm_enabled)
57     epoll_server_->UnregisterAlarm(pmp_->alarm_token);
58 }
59 
OnAlarm()60 int64 OutputOrdering::BeginOutputtingAlarm::OnAlarm() {
61   OnUnregistration();
62   output_ordering_->MoveToActive(pmp_, mci_);
63   VLOG(2) << "ON ALARM! Should now start to output...";
64   delete this;
65   return 0;
66 }
67 
OnRegistration(const EpollServer::AlarmRegToken & tok,EpollServer * eps)68 void OutputOrdering::BeginOutputtingAlarm::OnRegistration(
69     const EpollServer::AlarmRegToken& tok,
70     EpollServer* eps) {
71   epoll_server_ = eps;
72   pmp_->alarm_token = tok;
73   pmp_->alarm_enabled = true;
74 }
75 
OnUnregistration()76 void OutputOrdering::BeginOutputtingAlarm::OnUnregistration() {
77   pmp_->alarm_enabled = false;
78   delete this;
79 }
80 
OnShutdown(EpollServer * eps)81 void OutputOrdering::BeginOutputtingAlarm::OnShutdown(EpollServer* eps) {
82   OnUnregistration();
83 }
84 
MoveToActive(PriorityMapPointer * pmp,MemCacheIter mci)85 void OutputOrdering::MoveToActive(PriorityMapPointer* pmp, MemCacheIter mci) {
86   VLOG(2) << "Moving to active!";
87   first_data_senders_.push_back(mci);
88   pmp->ring = &first_data_senders_;
89   pmp->it = first_data_senders_.end();
90   --pmp->it;
91   connection_->ReadyToSend();
92 }
93 
AddToOutputOrder(const MemCacheIter & mci)94 void OutputOrdering::AddToOutputOrder(const MemCacheIter& mci) {
95   if (ExistsInPriorityMaps(mci.stream_id))
96     LOG(ERROR) << "OOps, already was inserted here?!";
97 
98   double think_time_in_s = server_think_time_in_s_;
99   std::string x_server_latency =
100       mci.file_data->headers()->GetHeader("X-Server-Latency").as_string();
101   if (!x_server_latency.empty()) {
102     char* endp;
103     double tmp_think_time_in_s = strtod(x_server_latency.c_str(), &endp);
104     if (endp != x_server_latency.c_str() + x_server_latency.size()) {
105       LOG(ERROR) << "Unable to understand X-Server-Latency of: "
106                  << x_server_latency
107                  << " for resource: " << mci.file_data->filename().c_str();
108     } else {
109       think_time_in_s = tmp_think_time_in_s;
110     }
111   }
112   StreamIdToPriorityMap::iterator sitpmi;
113   sitpmi = stream_ids_.insert(std::pair<uint32, PriorityMapPointer>(
114                                   mci.stream_id, PriorityMapPointer())).first;
115   PriorityMapPointer& pmp = sitpmi->second;
116 
117   BeginOutputtingAlarm* boa = new BeginOutputtingAlarm(this, &pmp, mci);
118   VLOG(1) << "Server think time: " << think_time_in_s;
119   epoll_server_->RegisterAlarmApproximateDelta(think_time_in_s * 1000000, boa);
120 }
121 
SpliceToPriorityRing(PriorityRing::iterator pri)122 void OutputOrdering::SpliceToPriorityRing(PriorityRing::iterator pri) {
123   MemCacheIter& mci = *pri;
124   PriorityMap::iterator pmi = priority_map_.find(mci.priority);
125   if (pmi == priority_map_.end()) {
126     pmi = priority_map_.insert(std::pair<uint32, PriorityRing>(
127                                    mci.priority, PriorityRing())).first;
128   }
129 
130   pmi->second.splice(pmi->second.end(), first_data_senders_, pri);
131   StreamIdToPriorityMap::iterator sitpmi = stream_ids_.find(mci.stream_id);
132   sitpmi->second.ring = &(pmi->second);
133 }
134 
GetIter()135 MemCacheIter* OutputOrdering::GetIter() {
136   while (!first_data_senders_.empty()) {
137     MemCacheIter& mci = first_data_senders_.front();
138     if (mci.bytes_sent >= first_data_senders_threshold_) {
139       SpliceToPriorityRing(first_data_senders_.begin());
140     } else {
141       first_data_senders_.splice(first_data_senders_.end(),
142                                  first_data_senders_,
143                                  first_data_senders_.begin());
144       mci.max_segment_size = kInitialDataSendersThreshold;
145       return &mci;
146     }
147   }
148   while (!priority_map_.empty()) {
149     PriorityRing& first_ring = priority_map_.begin()->second;
150     if (first_ring.empty()) {
151       priority_map_.erase(priority_map_.begin());
152       continue;
153     }
154     MemCacheIter& mci = first_ring.front();
155     first_ring.splice(first_ring.end(), first_ring, first_ring.begin());
156     mci.max_segment_size = kSpdySegmentSize;
157     return &mci;
158   }
159   return NULL;
160 }
161 
RemoveStreamId(uint32 stream_id)162 void OutputOrdering::RemoveStreamId(uint32 stream_id) {
163   StreamIdToPriorityMap::iterator sitpmi = stream_ids_.find(stream_id);
164   if (sitpmi == stream_ids_.end())
165     return;
166 
167   PriorityMapPointer& pmp = sitpmi->second;
168   if (pmp.alarm_enabled)
169     epoll_server_->UnregisterAlarm(pmp.alarm_token);
170   else
171     pmp.ring->erase(pmp.it);
172   stream_ids_.erase(sitpmi);
173 }
174 
175 }  // namespace net
176