| // 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 "kudu/mini-cluster/webui_checker.h" |
| |
| #include <algorithm> |
| #include <atomic> |
| #include <cstdint> |
| #include <iostream> |
| #include <random> |
| #include <string> |
| #include <thread> |
| #include <utility> |
| #include <vector> |
| |
| #include <glog/logging.h> |
| |
| #include "kudu/gutil/strings/substitute.h" |
| #include "kudu/mini-cluster/external_mini_cluster.h" |
| #include "kudu/util/curl_util.h" |
| #include "kudu/util/faststring.h" |
| #include "kudu/util/monotime.h" |
| #include "kudu/util/net/net_util.h" |
| #include "kudu/util/status.h" |
| |
| using std::string; |
| using std::thread; |
| using std::vector; |
| using strings::Substitute; |
| |
| namespace kudu { |
| |
| PeriodicWebUIChecker::PeriodicWebUIChecker( |
| const cluster::ExternalMiniCluster& cluster, |
| MonoDelta period, |
| const string& tablet_id, |
| const vector<string>& master_pages, |
| const vector<string>& ts_pages) |
| : period_(period), |
| is_running_(true) { |
| // List of tserver web pages to fetch. |
| vector<string> ts_pages_spec(ts_pages); |
| if (tablet_id.empty()) { |
| ts_pages_spec.emplace_back("/transactions"); |
| } else { |
| ts_pages_spec.emplace_back( |
| Substitute("/transactions?tablet_id=$0", tablet_id)); |
| } |
| |
| // Generate list of urls for each master and tablet server |
| for (int i = 0; i < cluster.num_masters(); i++) { |
| for (const auto& page : master_pages) { |
| urls_.emplace_back(Substitute( |
| "http://$0$1", |
| cluster.master(i)->bound_http_hostport().ToString(), |
| page)); |
| } |
| } |
| for (int i = 0; i < cluster.num_tablet_servers(); i++) { |
| for (const auto& page : ts_pages_spec) { |
| urls_.emplace_back(Substitute( |
| "http://$0$1", |
| cluster.tablet_server(i)->bound_http_hostport().ToString(), |
| page)); |
| } |
| } |
| std::random_device rdev; |
| std::mt19937 gen(rdev()); |
| std::shuffle(urls_.begin(), urls_.end(), gen); |
| checker_ = thread([this]() { this->CheckThread(); }); |
| } |
| |
| PeriodicWebUIChecker::~PeriodicWebUIChecker() { |
| LOG(INFO) << "shutting down CURL thread"; |
| is_running_ = false; |
| checker_.join(); |
| } |
| |
| void PeriodicWebUIChecker::CheckThread() { |
| EasyCurl curl; |
| curl.set_timeout(MonoDelta::FromSeconds(120)); |
| std::ostringstream ostr; |
| ostr << "curl thread will poll the following URLs every " |
| << period_.ToString() << ":\n"; |
| for (const auto& url : urls_) { |
| ostr << " " << url << "\n"; |
| } |
| LOG(INFO) << ostr.str(); |
| faststring dst; |
| while (is_running_) { |
| // Poll all of the URLs. |
| const MonoTime start = MonoTime::Now(); |
| bool compression_enabled = true; |
| for (const auto& url : urls_) { |
| // Switch compression back and forth. |
| Status s = compression_enabled |
| ? curl.FetchURL(url, &dst, {"Accept-Encoding: gzip"}) |
| : curl.FetchURL(url, &dst); |
| compression_enabled = !compression_enabled; |
| if (s.ok()) { |
| CHECK_GT(dst.length(), 0); |
| } |
| CHECK(!s.IsTimedOut()) << Substitute( |
| "could not fetch $0 ($1 compression, $2 connections): $3", |
| url, compression_enabled ? "gzip" : "no", curl.num_connects(), s.ToString()); |
| } |
| // Sleep until the next period |
| const MonoDelta elapsed = MonoTime::Now() - start; |
| const int64_t sleep_ns = period_.ToNanoseconds() - elapsed.ToNanoseconds(); |
| if (sleep_ns > 0) { |
| SleepFor(MonoDelta::FromNanoseconds(sleep_ns)); |
| } |
| } |
| } |
| |
| } // namespace kudu |