You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by wd...@apache.org on 2019/02/15 23:37:51 UTC
[kudu] 01/02: [server] Add start_time in server description
This is an automated email from the ASF dual-hosted git repository.
wdberkeley pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
commit c72a45c49435b6800fa435aab6ed73adac288baf
Author: Yingchun Lai <40...@qq.com>
AuthorDate: Wed Jan 30 14:22:52 2019 +0800
[server] Add start_time in server description
Add `start_time` to describe the start time of a server in
localtime format, like `2019-01-01 00:00:00 UTC`. We can use
this information to acknowledge the last start time of a server,
both master and tserver, to check whether there is an unexpect
restarting, the server joined time, etc. We can get `start_time`
of servers from both web-ui and command line `kudu tserver/master
list`.
Change-Id: I041467014499ad00c07398ad8f61c6d6ca1ceeca
Reviewed-on: http://gerrit.cloudera.org:8080/12304
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>
---
src/kudu/common/wire_protocol.cc | 19 ++++++++++++++++++-
src/kudu/common/wire_protocol.h | 5 +++++
src/kudu/common/wire_protocol.proto | 3 +++
src/kudu/integration-tests/registration-test.cc | 20 ++++++++++++++++++++
src/kudu/master/master-test.cc | 23 +++++++++++++++++++++++
src/kudu/master/master.cc | 1 +
src/kudu/master/master_path_handlers.cc | 11 +++++++++--
src/kudu/master/ts_descriptor-test.cc | 1 +
src/kudu/server/server_base.cc | 3 +++
src/kudu/server/server_base.h | 6 ++++++
src/kudu/tools/tool_action_master.cc | 10 +++++++---
src/kudu/tools/tool_action_tserver.cc | 9 ++++++---
src/kudu/tserver/heartbeater.cc | 1 +
src/kudu/util/pb_util.cc | 1 -
src/kudu/util/pb_util.h | 4 ++--
www/masters.mustache | 2 ++
www/tablet-servers.mustache | 2 ++
17 files changed, 109 insertions(+), 12 deletions(-)
diff --git a/src/kudu/common/wire_protocol.cc b/src/kudu/common/wire_protocol.cc
index 2aab6f0..dc7b1f2 100644
--- a/src/kudu/common/wire_protocol.cc
+++ b/src/kudu/common/wire_protocol.cc
@@ -17,6 +17,8 @@
#include "kudu/common/wire_protocol.h"
+#include <time.h>
+
#include <cstdint>
#include <cstring>
#include <ostream>
@@ -26,8 +28,8 @@
#include <boost/optional/optional.hpp>
#include <glog/logging.h>
-#include "kudu/common/columnblock.h"
#include "kudu/common/column_predicate.h"
+#include "kudu/common/columnblock.h"
#include "kudu/common/common.pb.h"
#include "kudu/common/row.h"
#include "kudu/common/rowblock.h"
@@ -39,9 +41,11 @@
#include "kudu/gutil/port.h"
#include "kudu/gutil/strings/fastmem.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/walltime.h"
#include "kudu/util/bitmap.h"
#include "kudu/util/compression/compression.pb.h"
#include "kudu/util/faststring.h"
+#include "kudu/util/hash.pb.h"
#include "kudu/util/memory/arena.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/net/sockaddr.h"
@@ -948,4 +952,17 @@ void SerializeRowBlock(const RowBlock& block,
rowblock_pb->set_num_rows(rowblock_pb->num_rows() + num_rows);
}
+std::string StartTimeToString(const ServerRegistrationPB& reg) {
+ string start_time;
+ if (reg.has_start_time()) {
+ // Convert epoch time to localtime.
+ StringAppendStrftime(&start_time, "%Y-%m-%d %H:%M:%S %Z",
+ static_cast<time_t>(reg.start_time()), true);
+ } else {
+ start_time = "<unknown>";
+ }
+
+ return start_time;
+}
+
} // namespace kudu
diff --git a/src/kudu/common/wire_protocol.h b/src/kudu/common/wire_protocol.h
index cedc7d9..cf6be92 100644
--- a/src/kudu/common/wire_protocol.h
+++ b/src/kudu/common/wire_protocol.h
@@ -20,6 +20,7 @@
#define KUDU_COMMON_WIRE_PROTOCOL_H
#include <cstdint>
+#include <string>
#include <vector>
#include "kudu/util/status.h"
@@ -56,6 +57,7 @@ class HostPortPB;
class RowwiseRowBlockPB;
class SchemaPB;
class ServerEntryPB;
+class ServerRegistrationPB;
// Convert the given C++ Status object into the equivalent Protobuf.
void StatusToPB(const Status& status, AppStatusPB* pb);
@@ -195,5 +197,8 @@ Status ExtractRowsFromRowBlockPB(const Schema& schema,
Status FindLeaderHostPort(const google::protobuf::RepeatedPtrField<ServerEntryPB>& entries,
HostPort* leader_hostport);
+// Extract 'start_time' in ServerRegistrationPB, and convert it to localtime as a string
+// or '<unknown>' if lack this field.
+std::string StartTimeToString(const ServerRegistrationPB& reg);
} // namespace kudu
#endif
diff --git a/src/kudu/common/wire_protocol.proto b/src/kudu/common/wire_protocol.proto
index f592734..225ce47 100644
--- a/src/kudu/common/wire_protocol.proto
+++ b/src/kudu/common/wire_protocol.proto
@@ -93,6 +93,9 @@ message ServerRegistrationPB {
// In this case, https:// URLs should be generated for the above
// 'http_addresses' field.
optional bool https_enabled = 4;
+
+ // Seconds since the epoch.
+ optional int64 start_time = 5;
}
message ServerEntryPB {
diff --git a/src/kudu/integration-tests/registration-test.cc b/src/kudu/integration-tests/registration-test.cc
index bbd0834..6414127 100644
--- a/src/kudu/integration-tests/registration-test.cc
+++ b/src/kudu/integration-tests/registration-test.cc
@@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.
+#include <stdint.h>
+
#include <algorithm>
#include <memory>
#include <ostream>
@@ -32,6 +34,7 @@
#include "kudu/gutil/gscoped_ptr.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/walltime.h"
#include "kudu/master/catalog_manager.h"
#include "kudu/master/master-test-util.h"
#include "kudu/master/master.h"
@@ -143,6 +146,7 @@ class RegistrationTest : public KuduTest {
void SetUp() override {
// Make heartbeats faster to speed test runtime.
FLAGS_heartbeat_interval_ms = 10;
+ setup_time_ = WallTime_Now();
KuduTest::SetUp();
@@ -209,6 +213,7 @@ class RegistrationTest : public KuduTest {
protected:
gscoped_ptr<InternalMiniCluster> cluster_;
Schema schema_;
+ int64_t setup_time_;
};
TEST_F(RegistrationTest, TestTSRegisters) {
@@ -250,6 +255,21 @@ TEST_F(RegistrationTest, TestMasterSoftwareVersion) {
ASSERT_TRUE(reg.has_software_version());
ASSERT_STR_CONTAINS(reg.software_version(),
VersionInfo::GetVersionInfo());
+ ASSERT_LE(setup_time_, reg.start_time());
+ ASSERT_LE(reg.start_time(), WallTime_Now());
+ }
+}
+
+TEST_F(RegistrationTest, TestServerStartTime) {
+ ServerRegistrationPB reg;
+ cluster_->mini_master()->master()->GetMasterRegistration(®);
+ ASSERT_LE(setup_time_, reg.start_time());
+ ASSERT_LE(reg.start_time(), WallTime_Now());
+
+ for (int i = 0; i < cluster_->num_tablet_servers(); ++i) {
+ auto start_time = cluster_->mini_tablet_server(i)->server()->start_time();
+ ASSERT_LE(setup_time_, start_time);
+ ASSERT_LE(start_time, WallTime_Now());
}
}
diff --git a/src/kudu/master/master-test.cc b/src/kudu/master/master-test.cc
index 24db50d..552d1ed 100644
--- a/src/kudu/master/master-test.cc
+++ b/src/kudu/master/master-test.cc
@@ -17,6 +17,8 @@
#include "kudu/master/master.h"
+#include <time.h>
+
#include <algorithm>
#include <cstdint>
#include <map>
@@ -54,6 +56,7 @@
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/gutil/strings/util.h"
+#include "kudu/gutil/walltime.h"
#include "kudu/master/catalog_manager.h"
#include "kudu/master/master.pb.h"
#include "kudu/master/master.proxy.h"
@@ -210,6 +213,7 @@ TEST_F(MasterTest, TestRegisterAndHeartbeat) {
MakeHostPortPB("localhost", 1000, fake_reg.add_rpc_addresses());
MakeHostPortPB("localhost", 2000, fake_reg.add_http_addresses());
fake_reg.set_software_version(VersionInfo::GetVersionInfo());
+ fake_reg.set_start_time(10000);
// Information on replica management scheme.
ReplicaManagementInfoPB rmi;
@@ -378,6 +382,9 @@ TEST_F(MasterTest, TestRegisterAndHeartbeat) {
ASSERT_EQ(true, tablet_server["live"].GetBool());
ASSERT_STREQ(VersionInfo::GetVersionInfo().c_str(),
tablet_server["version"].GetString());
+ string start_time;
+ StringAppendStrftime(&start_time, "%Y-%m-%d %H:%M:%S %Z", static_cast<time_t>(10000), true);
+ ASSERT_STREQ(start_time.c_str(), tablet_server["start_time"].GetString());
}
// Ensure that trying to re-register with a different version is OK.
@@ -392,6 +399,22 @@ TEST_F(MasterTest, TestRegisterAndHeartbeat) {
// the numeric portion will match.
req.mutable_registration()->set_software_version(Substitute("kudu $0 (rev SOME_NON_GIT_HASH)",
KUDU_VERSION_STRING));
+
+ ASSERT_OK(proxy_->TSHeartbeat(req, &resp, &rpc));
+ ASSERT_FALSE(resp.has_error());
+ }
+
+ // Ensure that trying to re-register with a different start_time is OK.
+ {
+ TSHeartbeatRequestPB req;
+ TSHeartbeatResponsePB resp;
+ RpcController rpc;
+ req.mutable_common()->CopyFrom(common);
+ req.mutable_registration()->CopyFrom(fake_reg);
+ req.mutable_replica_management_info()->CopyFrom(rmi);
+ // 10 minutes later.
+ req.mutable_registration()->set_start_time(10600);
+
ASSERT_OK(proxy_->TSHeartbeat(req, &resp, &rpc));
ASSERT_FALSE(resp.has_error());
}
diff --git a/src/kudu/master/master.cc b/src/kudu/master/master.cc
index ae33cd2..bc7f9ae 100644
--- a/src/kudu/master/master.cc
+++ b/src/kudu/master/master.cc
@@ -293,6 +293,7 @@ Status Master::InitMasterRegistration() {
reg.set_https_enabled(web_server()->IsSecure());
}
reg.set_software_version(VersionInfo::GetVersionInfo());
+ reg.set_start_time(start_time_);
registration_.Swap(®);
registration_initialized_.store(true);
diff --git a/src/kudu/master/master_path_handlers.cc b/src/kudu/master/master_path_handlers.cc
index 8566966..02e6474 100644
--- a/src/kudu/master/master_path_handlers.cc
+++ b/src/kudu/master/master_path_handlers.cc
@@ -129,6 +129,8 @@ void MasterPathHandlers::HandleTabletServers(const Webserver::WebRequest& /*req*
reg.http_addresses(0).port());
}
ts_json["time_since_hb"] = StringPrintf("%.1fs", desc->TimeSinceHeartbeat().ToSeconds());
+ ts_json["start_time"] = StartTimeToString(reg);
+ reg.clear_start_time(); // Clear 'start_time' before dumping to string.
ts_json["registration"] = pb_util::SecureShortDebugString(reg);
ts_json["location"] = desc->location().get_value_or("<none>");
version_counts[reg.software_version()][desc->PresumedDead() ? 1 : 0]++;
@@ -458,7 +460,7 @@ void MasterPathHandlers::HandleMasters(const Webserver::WebRequest& /*req*/,
continue;
}
EasyJson master_json = (*output)["masters"].PushBack(EasyJson::kObject);
- const ServerRegistrationPB& reg = master.registration();
+ ServerRegistrationPB reg = master.registration();
master_json["uuid"] = master.instance_id().permanent_uuid();
if (!reg.http_addresses().empty()) {
master_json["target"] = Substitute("$0://$1:$2/",
@@ -467,7 +469,9 @@ void MasterPathHandlers::HandleMasters(const Webserver::WebRequest& /*req*/,
reg.http_addresses(0).port());
}
master_json["role"] = master.has_role() ? RaftPeerPB_Role_Name(master.role()) : "N/A";
- master_json["registration"] = pb_util::SecureShortDebugString(master.registration());
+ master_json["start_time"] = StartTimeToString(reg);
+ reg.clear_start_time(); // Clear 'start_time' before dumping to string.
+ master_json["registration"] = pb_util::SecureShortDebugString(reg);
}
}
@@ -645,6 +649,9 @@ void MasterPathHandlers::HandleDumpEntities(const Webserver::WebRequest& /*req*/
jw.String("version");
jw.String(reg.software_version());
+ jw.String("start_time");
+ jw.String(StartTimeToString(reg));
+
jw.EndObject();
}
jw.EndArray();
diff --git a/src/kudu/master/ts_descriptor-test.cc b/src/kudu/master/ts_descriptor-test.cc
index a7ec824..92e3fec 100644
--- a/src/kudu/master/ts_descriptor-test.cc
+++ b/src/kudu/master/ts_descriptor-test.cc
@@ -67,6 +67,7 @@ void SetupBasicRegistrationInfo(const string& uuid,
http_hostport->set_port(54321);
registration->set_software_version("1.0.0");
registration->set_https_enabled(false);
+ registration->set_start_time(10000);
}
TEST(TSDescriptorTest, TestRegistration) {
diff --git a/src/kudu/server/server_base.cc b/src/kudu/server/server_base.cc
index 1a742d1..8894373 100644
--- a/src/kudu/server/server_base.cc
+++ b/src/kudu/server/server_base.cc
@@ -43,6 +43,7 @@
#include "kudu/gutil/port.h"
#include "kudu/gutil/strings/strcat.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/walltime.h"
#include "kudu/rpc/messenger.h"
#include "kudu/rpc/remote_user.h"
#include "kudu/rpc/result_tracker.h"
@@ -679,6 +680,8 @@ Status ServerBase::Start() {
"Failed to dump server info to " + options_.dump_info_path);
}
+ start_time_ = WallTime_Now();
+
return Status::OK();
}
diff --git a/src/kudu/server/server_base.h b/src/kudu/server/server_base.h
index 8c0f940..203dd99 100644
--- a/src/kudu/server/server_base.h
+++ b/src/kudu/server/server_base.h
@@ -107,6 +107,10 @@ class ServerBase {
// Return a PB describing the status of the server (version info, bound ports, etc)
Status GetStatusPB(ServerStatusPB* status) const;
+ int64_t start_time() const {
+ return start_time_;
+ }
+
enum {
SUPER_USER = 1,
USER = 1 << 1,
@@ -161,6 +165,8 @@ class ServerBase {
void LogUnauthorizedAccess(rpc::RpcContext* rpc) const;
const std::string name_;
+ // Seconds since the epoch.
+ int64_t start_time_;
std::unique_ptr<MinidumpExceptionHandler> minidump_handler_;
std::shared_ptr<MemTracker> mem_tracker_;
diff --git a/src/kudu/tools/tool_action_master.cc b/src/kudu/tools/tool_action_master.cc
index 98acfb9..e74c1b7 100644
--- a/src/kudu/tools/tool_action_master.cc
+++ b/src/kudu/tools/tool_action_master.cc
@@ -15,8 +15,6 @@
// specific language governing permissions and limitations
// under the License.
-#include "kudu/tools/tool_action.h"
-
#include <algorithm>
#include <iostream>
#include <iterator>
@@ -40,6 +38,7 @@
#include "kudu/master/master.h"
#include "kudu/master/master.pb.h"
#include "kudu/master/master.proxy.h"
+#include "kudu/tools/tool_action.h"
#include "kudu/tools/tool_action_common.h"
#include "kudu/util/status.h"
@@ -144,6 +143,10 @@ Status ListMasters(const RunnerContext& context) {
for (const auto& master : masters) {
values.push_back(master.registration().software_version());
}
+ } else if (boost::iequals(column, "start_time")) {
+ for (const auto& master : masters) {
+ values.emplace_back(StartTimeToString(master.registration()));
+ }
} else {
return Status::InvalidArgument("unknown column (--columns)", column);
}
@@ -207,7 +210,8 @@ unique_ptr<Mode> BuildMasterMode() {
.AddOptionalParameter("columns", string("uuid,rpc-addresses"),
string("Comma-separated list of master info fields to "
"include in output.\nPossible values: uuid, "
- "rpc-addresses, http-addresses, version, and seqno"))
+ "rpc-addresses, http-addresses, version, seqno "
+ "and start_time"))
.AddOptionalParameter("format")
.AddOptionalParameter("timeout_ms")
.Build();
diff --git a/src/kudu/tools/tool_action_tserver.cc b/src/kudu/tools/tool_action_tserver.cc
index a0527b8..95fa07e 100644
--- a/src/kudu/tools/tool_action_tserver.cc
+++ b/src/kudu/tools/tool_action_tserver.cc
@@ -15,8 +15,6 @@
// specific language governing permissions and limitations
// under the License.
-#include "kudu/tools/tool_action.h"
-
#include <iostream>
#include <memory>
#include <string>
@@ -37,6 +35,7 @@
#include "kudu/gutil/strings/substitute.h"
#include "kudu/master/master.pb.h"
#include "kudu/master/master.proxy.h"
+#include "kudu/tools/tool_action.h"
#include "kudu/tools/tool_action_common.h"
#include "kudu/tserver/tablet_server.h"
#include "kudu/util/status.h"
@@ -143,6 +142,10 @@ Status ListTServers(const RunnerContext& context) {
string loc = server.location();
values.emplace_back(loc.empty() ? "<none>" : std::move(loc));
}
+ } else if (boost::iequals(column, "start_time")) {
+ for (const auto& server : servers) {
+ values.emplace_back(StartTimeToString(server.registration()));
+ }
} else {
return Status::InvalidArgument("unknown column (--columns)", column);
}
@@ -207,7 +210,7 @@ unique_ptr<Mode> BuildTServerMode() {
string("Comma-separated list of tserver info fields to "
"include in output.\nPossible values: uuid, "
"rpc-addresses, http-addresses, version, seqno, "
- "and heartbeat"))
+ "heartbeat and start_time"))
.AddOptionalParameter("format")
.AddOptionalParameter("timeout_ms")
.Build();
diff --git a/src/kudu/tserver/heartbeater.cc b/src/kudu/tserver/heartbeater.cc
index b9cb0a8..0b1587f 100644
--- a/src/kudu/tserver/heartbeater.cc
+++ b/src/kudu/tserver/heartbeater.cc
@@ -368,6 +368,7 @@ Status Heartbeater::Thread::SetupRegistration(ServerRegistrationPB* reg) {
reg->set_https_enabled(server_->web_server()->IsSecure());
}
reg->set_software_version(VersionInfo::GetVersionInfo());
+ reg->set_start_time(server_->start_time());
return Status::OK();
}
diff --git a/src/kudu/util/pb_util.cc b/src/kudu/util/pb_util.cc
index 35e4628..6237c80 100644
--- a/src/kudu/util/pb_util.cc
+++ b/src/kudu/util/pb_util.cc
@@ -649,7 +649,6 @@ string SecureShortDebugString(const Message& msg) {
return debug_string;
}
-
WritablePBContainerFile::WritablePBContainerFile(shared_ptr<RWFile> writer)
: state_(FileState::NOT_INITIALIZED),
offset_(0),
diff --git a/src/kudu/util/pb_util.h b/src/kudu/util/pb_util.h
index 6c132a6..13e496f 100644
--- a/src/kudu/util/pb_util.h
+++ b/src/kudu/util/pb_util.h
@@ -31,8 +31,8 @@
#include <gtest/gtest_prod.h>
#include "kudu/gutil/ref_counted.h"
-#include "kudu/util/mutex.h"
#include "kudu/util/debug/trace_event_impl.h"
+#include "kudu/util/mutex.h"
namespace google {
namespace protobuf {
@@ -47,11 +47,11 @@ class SimpleDescriptorDatabase;
namespace kudu {
class Env;
+class RWFile;
class RandomAccessFile;
class SequentialFile;
class Slice;
class Status;
-class RWFile;
class faststring;
namespace pb_util {
diff --git a/www/masters.mustache b/www/masters.mustache
index 0ce7649..268533e 100644
--- a/www/masters.mustache
+++ b/www/masters.mustache
@@ -32,6 +32,7 @@ under the License.
<thead><tr>
<th>UUID</th>
<th>Role</th>
+ <th>Start time</th>
<th>Registration</th>
</tr></thead>
<tbody>
@@ -39,6 +40,7 @@ under the License.
<tr>
<td>{{#target}}<a href="{{.}}">{{/target}}{{uuid}}{{#target}}</a>{{/target}}</td>
<td>{{role}}</td>
+ <td>{{start_time}}</td>
<td><pre><code>{{registration}}</code></pre></td>
</tr>
{{/masters}}
diff --git a/www/tablet-servers.mustache b/www/tablet-servers.mustache
index a778f72..7370232 100644
--- a/www/tablet-servers.mustache
+++ b/www/tablet-servers.mustache
@@ -47,6 +47,7 @@ under the License.
<th>UUID</th>
<th>Location</th>
<th>Time since heartbeat</th>
+ <th>Start time</th>
<th>Registration</th>
</tr></thead>
<tbody>
@@ -55,6 +56,7 @@ under the License.
<td>{{#target}}<a href="{{.}}">{{/target}}{{uuid}}{{#target}}</a>{{/target}}</td>
<td>{{location}}</td>
<td>{{time_since_hb}}</td>
+ <td>{{start_time}}</td>
<td><pre><code>{{registration}}</code></pre></td>
</tr>
{{/live_tservers}}