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