This is an automated email from the ASF dual-hosted git repository. maskit pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new aa319a4 Fix H2 internal counters aa319a4 is described below commit aa319a461c8326724ea10a42ae474fcdac7fc849 Author: Masakazu Kitajo <mas...@apache.org> AuthorDate: Sat Aug 17 00:29:30 2019 +0900 Fix H2 internal counters --- .gitignore | 1 + proxy/http2/Http2ConnectionState.cc | 56 +----- proxy/http2/Http2ConnectionState.h | 17 +- proxy/http2/Http2FrequencyCounter.cc | 55 ++++++ proxy/http2/Http2FrequencyCounter.h | 38 ++++ proxy/http2/Makefile.am | 17 ++ .../http2/unit_tests/test_Http2FrequencyCounter.cc | 219 +++++++++++++++++++++ 7 files changed, 343 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 6ac08e2..c683ae3 100644 --- a/.gitignore +++ b/.gitignore @@ -130,6 +130,7 @@ proxy/hdrs/test_Huffmancode proxy/hdrs/test_XPACK proxy/http/test_proxy_http proxy/http2/test_Http2DependencyTree +proxy/http2/test_Http2FrequencyCounter proxy/http2/test_HPACK proxy/http2/hpack-tests/results proxy/http3/test_libhttp3 diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc index fecb360..b26e61e 100644 --- a/proxy/http2/Http2ConnectionState.cc +++ b/proxy/http2/Http2ConnectionState.cc @@ -1901,89 +1901,49 @@ Http2ConnectionState::send_window_update_frame(Http2StreamId id, uint32_t size) void Http2ConnectionState::increment_received_settings_count(uint32_t count) { - ink_hrtime hrtime_sec = Thread::get_hrtime() / HRTIME_SECOND; - uint8_t counter_index = ((hrtime_sec % 60) >= 30); - - if ((hrtime_sec - 60) > this->settings_count_last_update) { - this->settings_count[0] = 0; - this->settings_count[1] = 0; - } else if (counter_index != ((this->settings_count_last_update % 60) >= 30)) { - this->settings_count[counter_index] = 0; - } - this->settings_count[counter_index] += count; - this->settings_count_last_update = hrtime_sec; + this->_received_settings_counter.increment(count); } uint32_t Http2ConnectionState::get_received_settings_count() { - return this->settings_count[0] + this->settings_count[1]; + return this->_received_settings_counter.get_count(); } void Http2ConnectionState::increment_received_settings_frame_count() { - ink_hrtime hrtime_sec = Thread::get_hrtime() / HRTIME_SECOND; - uint8_t counter_index = ((hrtime_sec % 60) >= 30); - - if ((hrtime_sec - 60) > this->settings_frame_count_last_update) { - this->settings_frame_count[0] = 0; - this->settings_frame_count[1] = 0; - } else if (counter_index != ((this->settings_frame_count_last_update % 60) >= 30)) { - this->settings_frame_count[counter_index] = 0; - } - ++this->settings_frame_count[counter_index]; - this->settings_frame_count_last_update = hrtime_sec; + this->_received_settings_frame_counter.increment(); } uint32_t Http2ConnectionState::get_received_settings_frame_count() { - return this->settings_frame_count[0] + this->settings_frame_count[1]; + return this->_received_settings_frame_counter.get_count(); } void Http2ConnectionState::increment_received_ping_frame_count() { - ink_hrtime hrtime_sec = Thread::get_hrtime() / HRTIME_SECOND; - uint8_t counter_index = ((hrtime_sec % 60) >= 30); - - if ((hrtime_sec - 60) > this->ping_frame_count_last_update) { - this->ping_frame_count[0] = 0; - this->ping_frame_count[1] = 0; - } else if (counter_index != ((this->ping_frame_count_last_update % 60) >= 30)) { - this->ping_frame_count[counter_index] = 0; - } - ++this->ping_frame_count[counter_index]; - this->ping_frame_count_last_update = hrtime_sec; + this->_received_ping_frame_counter.increment(); } uint32_t Http2ConnectionState::get_received_ping_frame_count() { - return this->ping_frame_count[0] + this->ping_frame_count[1]; + return this->_received_ping_frame_counter.get_count(); } void Http2ConnectionState::increment_received_priority_frame_count() { - ink_hrtime hrtime_sec = Thread::get_hrtime() / HRTIME_SECOND; - uint8_t counter_index = ((hrtime_sec % 60) >= 30); - - if ((hrtime_sec - 60) > this->priority_frame_count_last_update) { - this->priority_frame_count[0] = 0; - this->priority_frame_count[1] = 0; - } else if (counter_index != ((this->priority_frame_count_last_update % 60) >= 30)) { - this->priority_frame_count[counter_index] = 0; - } - ++this->priority_frame_count[counter_index]; - this->priority_frame_count_last_update = hrtime_sec; + this->_received_priority_frame_counter.increment(); } uint32_t Http2ConnectionState::get_received_priority_frame_count() { - return this->priority_frame_count[0] + this->priority_frame_count[1]; + return this->_received_priority_frame_counter.get_count(); } // Return min_concurrent_streams_in when current client streams number is larger than max_active_streams_in. diff --git a/proxy/http2/Http2ConnectionState.h b/proxy/http2/Http2ConnectionState.h index 9938483..01c80cf 100644 --- a/proxy/http2/Http2ConnectionState.h +++ b/proxy/http2/Http2ConnectionState.h @@ -28,6 +28,7 @@ #include "HPACK.h" #include "Http2Stream.h" #include "Http2DependencyTree.h" +#include "Http2FrequencyCounter.h" class Http2ClientSession; @@ -358,18 +359,10 @@ private: std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX}; int _recent_rwnd_increment_index = 0; - // Counter for settings received within last 60 seconds - // Each item holds a count for 30 seconds. - uint16_t settings_count[2] = {0}; - ink_hrtime settings_count_last_update = 0; - // Counters for frames received within last 60 seconds - // Each item in an array holds a count for 30 seconds. - uint16_t settings_frame_count[2] = {0}; - ink_hrtime settings_frame_count_last_update = 0; - uint16_t ping_frame_count[2] = {0}; - ink_hrtime ping_frame_count_last_update = 0; - uint16_t priority_frame_count[2] = {0}; - ink_hrtime priority_frame_count_last_update = 0; + Http2FrequencyCounter _received_settings_counter; + Http2FrequencyCounter _received_settings_frame_counter; + Http2FrequencyCounter _received_ping_frame_counter; + Http2FrequencyCounter _received_priority_frame_counter; // NOTE: Id of stream which MUST receive CONTINUATION frame. // - [RFC 7540] 6.2 HEADERS diff --git a/proxy/http2/Http2FrequencyCounter.cc b/proxy/http2/Http2FrequencyCounter.cc new file mode 100644 index 0000000..dfe08b9 --- /dev/null +++ b/proxy/http2/Http2FrequencyCounter.cc @@ -0,0 +1,55 @@ +/** @file + + Http2FrequencyCounter + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "Http2FrequencyCounter.h" + +void +Http2FrequencyCounter::increment(uint16_t amount) +{ + ink_hrtime hrtime_sec = ink_hrtime_to_sec(Thread::get_hrtime()); + uint8_t counter_index = ((hrtime_sec % 60) >= 30); + uint8_t last_index = ((this->_last_update % 60) >= 30); + + if (hrtime_sec - this->_last_update > 60) { + this->_count[0] = 0; + this->_count[1] = 0; + } else if (hrtime_sec - this->_last_update > 30) { + if (counter_index == last_index) { + this->_count[0] = 0; + this->_count[1] = 0; + } else { + this->_count[counter_index] = 0; + } + } else if (counter_index != last_index) { // hrtime_sec - this->_last_update is less than 30 + this->_count[counter_index] = 0; + } + + this->_count[counter_index] += amount; + this->_last_update = hrtime_sec; +} + +uint32_t +Http2FrequencyCounter::get_count() +{ + return this->_count[0] + this->_count[1]; +} diff --git a/proxy/http2/Http2FrequencyCounter.h b/proxy/http2/Http2FrequencyCounter.h new file mode 100644 index 0000000..9d2ed73 --- /dev/null +++ b/proxy/http2/Http2FrequencyCounter.h @@ -0,0 +1,38 @@ +/** @file + + Http2FrequencyCounter + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include "I_EventSystem.h" + +class Http2FrequencyCounter +{ +public: + void increment(uint16_t amount = 1); + uint32_t get_count(); + +protected: + uint16_t _count[2] = {0}; + ink_hrtime _last_update = 0; +}; diff --git a/proxy/http2/Makefile.am b/proxy/http2/Makefile.am index ccc0d2d..3b33d36 100644 --- a/proxy/http2/Makefile.am +++ b/proxy/http2/Makefile.am @@ -45,6 +45,8 @@ libhttp2_a_SOURCES = \ Http2DebugNames.cc \ Http2DebugNames.h \ Http2DependencyTree.h \ + Http2FrequencyCounter.h \ + Http2FrequencyCounter.cc \ Http2Stream.cc \ Http2Stream.h \ Http2SessionAccept.cc \ @@ -57,10 +59,12 @@ endif check_PROGRAMS = \ test_Http2DependencyTree \ + test_Http2FrequencyCounter \ test_HPACK TESTS = \ test_Http2DependencyTree \ + test_Http2FrequencyCounter \ test_HPACK test_Http2DependencyTree_LDADD = \ @@ -74,6 +78,19 @@ test_Http2DependencyTree_SOURCES = \ unit_tests/test_Http2DependencyTree.cc \ Http2DependencyTree.h +test_Http2FrequencyCounter_LDADD = \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la + +test_Http2FrequencyCounter_CPPFLAGS = $(AM_CPPFLAGS)\ + -I$(abs_top_srcdir)/tests/include + +test_Http2FrequencyCounter_SOURCES = \ + unit_tests/test_Http2FrequencyCounter.cc \ + Http2FrequencyCounter.cc \ + Http2FequencyCounter.h + test_HPACK_LDADD = \ $(top_builddir)/proxy/hdrs/libhdrs.a \ $(top_builddir)/src/tscore/libtscore.la \ diff --git a/proxy/http2/unit_tests/test_Http2FrequencyCounter.cc b/proxy/http2/unit_tests/test_Http2FrequencyCounter.cc new file mode 100644 index 0000000..a1c0487 --- /dev/null +++ b/proxy/http2/unit_tests/test_Http2FrequencyCounter.cc @@ -0,0 +1,219 @@ +/** @file + + Unit tests for Http2FrequencyCounter + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include "Http2FrequencyCounter.h" + +class TestHttp2FrequencyCounter : public Http2FrequencyCounter +{ +public: + void + set_internal_state(ink_hrtime last_update_sec, uint16_t count_0, uint16_t count_1) + { + this->_last_update = last_update_sec; + this->_count[0] = count_0; + this->_count[1] = count_1; + } +}; + +TEST_CASE("Http2FrequencyCounter_basic", "[http2][Http2FrequencyCounter]") +{ + TestHttp2FrequencyCounter counter; + + SECTION("basic") + { + REQUIRE(counter.get_count() == 0); + counter.increment(); + REQUIRE(counter.get_count() == 1); + counter.increment(2); + REQUIRE(counter.get_count() == 3); + + counter.set_internal_state(ink_hrtime_to_sec(Thread::get_hrtime()) - 10, 1, 2); + REQUIRE(counter.get_count() == 3); + } + + SECTION("Update at 0") + { + ink_hrtime now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + while (now % 60 != 0) { + sleep(1); + now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + } + + counter.set_internal_state(now - 5, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 10, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 20, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 30, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 40, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 50, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 60, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 70, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + } + + SECTION("Update at 10") + { + ink_hrtime now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + while (now % 60 != 10) { + sleep(1); + now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + } + + counter.set_internal_state(now - 5, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 4); + + counter.set_internal_state(now - 10, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 4); + + counter.set_internal_state(now - 20, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 30, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 40, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 3); + + counter.set_internal_state(now - 50, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 60, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 70, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + } + + SECTION("Update at 30") + { + ink_hrtime now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + while (now % 60 != 30) { + sleep(1); + now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + } + + counter.set_internal_state(now - 5, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 10, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 20, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 30, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 40, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 50, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 60, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 70, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + } + + SECTION("Update at 40") + { + ink_hrtime now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + while (now % 60 != 40) { + sleep(1); + now = ink_hrtime_to_sec(Thread::get_hrtime_updated()); + } + + counter.set_internal_state(now - 5, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 4); + + counter.set_internal_state(now - 10, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 4); + + counter.set_internal_state(now - 20, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 30, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 40, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 2); + + counter.set_internal_state(now - 50, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 60, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + + counter.set_internal_state(now - 70, 1, 2); + counter.increment(); + CHECK(counter.get_count() == 1); + } +}