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.
5 #include "net/tools/flip_server/output_ordering.h"
7 #include "net/tools/flip_server/flip_config.h"
8 #include "net/tools/flip_server/sm_connection.h"
13 OutputOrdering::PriorityMapPointer::PriorityMapPointer()
15 alarm_enabled(false) {
19 double OutputOrdering::server_think_time_in_s_
= 0.0;
21 OutputOrdering::OutputOrdering(SMConnectionInterface
* connection
)
22 : first_data_senders_threshold_(kInitialDataSendersThreshold
),
23 connection_(connection
) {
25 epoll_server_
= connection
->epoll_server();
28 OutputOrdering::~OutputOrdering() {}
30 void OutputOrdering::Reset() {
31 while (!stream_ids_
.empty()) {
32 StreamIdToPriorityMap::iterator sitpmi
= stream_ids_
.begin();
33 PriorityMapPointer
& pmp
= sitpmi
->second
;
34 if (pmp
.alarm_enabled
) {
35 epoll_server_
->UnregisterAlarm(pmp
.alarm_token
);
37 stream_ids_
.erase(sitpmi
);
39 priority_map_
.clear();
40 first_data_senders_
.clear();
43 bool OutputOrdering::ExistsInPriorityMaps(uint32 stream_id
) {
44 StreamIdToPriorityMap::iterator sitpmi
= stream_ids_
.find(stream_id
);
45 return sitpmi
!= stream_ids_
.end();
48 OutputOrdering::BeginOutputtingAlarm::BeginOutputtingAlarm(
50 OutputOrdering::PriorityMapPointer
* pmp
,
51 const MemCacheIter
& mci
)
52 : output_ordering_(oo
),
58 OutputOrdering::BeginOutputtingAlarm::~BeginOutputtingAlarm() {
59 if (epoll_server_
&& pmp_
->alarm_enabled
)
60 epoll_server_
->UnregisterAlarm(pmp_
->alarm_token
);
63 int64
OutputOrdering::BeginOutputtingAlarm::OnAlarm() {
65 output_ordering_
->MoveToActive(pmp_
, mci_
);
66 VLOG(2) << "ON ALARM! Should now start to output...";
71 void OutputOrdering::BeginOutputtingAlarm::OnRegistration(
72 const EpollServer::AlarmRegToken
& tok
,
75 pmp_
->alarm_token
= tok
;
76 pmp_
->alarm_enabled
= true;
79 void OutputOrdering::BeginOutputtingAlarm::OnUnregistration() {
80 pmp_
->alarm_enabled
= false;
83 void OutputOrdering::BeginOutputtingAlarm::OnShutdown(EpollServer
* eps
) {
87 void OutputOrdering::MoveToActive(PriorityMapPointer
* pmp
, MemCacheIter mci
) {
88 VLOG(2) << "Moving to active!";
89 first_data_senders_
.push_back(mci
);
90 pmp
->ring
= &first_data_senders_
;
91 pmp
->it
= first_data_senders_
.end();
93 connection_
->ReadyToSend();
96 void OutputOrdering::AddToOutputOrder(const MemCacheIter
& mci
) {
97 if (ExistsInPriorityMaps(mci
.stream_id
))
98 LOG(ERROR
) << "OOps, already was inserted here?!";
100 double think_time_in_s
= server_think_time_in_s_
;
101 std::string x_server_latency
=
102 mci
.file_data
->headers()->GetHeader("X-Server-Latency").as_string();
103 if (!x_server_latency
.empty()) {
105 double tmp_think_time_in_s
= strtod(x_server_latency
.c_str(), &endp
);
106 if (endp
!= x_server_latency
.c_str() + x_server_latency
.size()) {
107 LOG(ERROR
) << "Unable to understand X-Server-Latency of: "
108 << x_server_latency
<< " for resource: "
109 << mci
.file_data
->filename().c_str();
111 think_time_in_s
= tmp_think_time_in_s
;
114 StreamIdToPriorityMap::iterator sitpmi
;
115 sitpmi
= stream_ids_
.insert(
116 std::pair
<uint32
, PriorityMapPointer
>(mci
.stream_id
,
117 PriorityMapPointer())).first
;
118 PriorityMapPointer
& pmp
= sitpmi
->second
;
120 BeginOutputtingAlarm
* boa
= new BeginOutputtingAlarm(this, &pmp
, mci
);
121 VLOG(1) << "Server think time: " << think_time_in_s
;
122 epoll_server_
->RegisterAlarmApproximateDelta(
123 think_time_in_s
* 1000000, boa
);
126 void OutputOrdering::SpliceToPriorityRing(PriorityRing::iterator pri
) {
127 MemCacheIter
& mci
= *pri
;
128 PriorityMap::iterator pmi
= priority_map_
.find(mci
.priority
);
129 if (pmi
== priority_map_
.end()) {
130 pmi
= priority_map_
.insert(
131 std::pair
<uint32
, PriorityRing
>(mci
.priority
, PriorityRing())).first
;
134 pmi
->second
.splice(pmi
->second
.end(),
137 StreamIdToPriorityMap::iterator sitpmi
= stream_ids_
.find(mci
.stream_id
);
138 sitpmi
->second
.ring
= &(pmi
->second
);
141 MemCacheIter
* OutputOrdering::GetIter() {
142 while (!first_data_senders_
.empty()) {
143 MemCacheIter
& mci
= first_data_senders_
.front();
144 if (mci
.bytes_sent
>= first_data_senders_threshold_
) {
145 SpliceToPriorityRing(first_data_senders_
.begin());
147 first_data_senders_
.splice(first_data_senders_
.end(),
149 first_data_senders_
.begin());
150 mci
.max_segment_size
= kInitialDataSendersThreshold
;
154 while (!priority_map_
.empty()) {
155 PriorityRing
& first_ring
= priority_map_
.begin()->second
;
156 if (first_ring
.empty()) {
157 priority_map_
.erase(priority_map_
.begin());
160 MemCacheIter
& mci
= first_ring
.front();
161 first_ring
.splice(first_ring
.end(),
164 mci
.max_segment_size
= kSpdySegmentSize
;
170 void OutputOrdering::RemoveStreamId(uint32 stream_id
) {
171 StreamIdToPriorityMap::iterator sitpmi
= stream_ids_
.find(stream_id
);
172 if (sitpmi
== stream_ids_
.end())
175 PriorityMapPointer
& pmp
= sitpmi
->second
;
176 if (pmp
.alarm_enabled
)
177 epoll_server_
->UnregisterAlarm(pmp
.alarm_token
);
179 pmp
.ring
->erase(pmp
.it
);
180 stream_ids_
.erase(sitpmi
);