Put remote boot UUID in ServerStatistics and RemoteMessage
This makes it so we can see when a remote reboots easily, and gives us a
stepping stone to putting it in the log file header.
RemoteMessage then goes to the logger, so we are ready to teach the
logger how to detect and handle reboots.
Change-Id: I943de46094b60535c92a677b430d6828933b820d
diff --git a/aos/events/BUILD b/aos/events/BUILD
index 239b324..646f597 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -83,6 +83,7 @@
"//aos:configuration_fbs",
"//aos:flatbuffers",
"//aos:ftrace",
+ "//aos/events/logging:uuid",
"//aos/ipc_lib:data_alignment",
"//aos/logging:implementations",
"//aos/time",
diff --git a/aos/events/event_loop.cc b/aos/events/event_loop.cc
index 08fa7fd..8d01549 100644
--- a/aos/events/event_loop.cc
+++ b/aos/events/event_loop.cc
@@ -79,8 +79,9 @@
PhasedLoopHandler::~PhasedLoopHandler() {}
-EventLoop::EventLoop(const Configuration *configuration)
- : timing_report_(flatbuffers::DetachedBuffer()),
+EventLoop::EventLoop(const Configuration *configuration, UUID boot_uuid)
+ : boot_uuid_(boot_uuid),
+ timing_report_(flatbuffers::DetachedBuffer()),
configuration_(configuration) {}
EventLoop::~EventLoop() {
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index bf7381c..3916ce4 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -12,6 +12,7 @@
#include "aos/events/channel_preallocated_allocator.h"
#include "aos/events/event_loop_event.h"
#include "aos/events/event_loop_generated.h"
+#include "aos/events/logging/uuid.h"
#include "aos/events/timing_statistics.h"
#include "aos/flatbuffers.h"
#include "aos/ftrace.h"
@@ -473,7 +474,7 @@
class EventLoop {
public:
- EventLoop(const Configuration *configuration);
+ EventLoop(const Configuration *configuration, UUID boot_uuid);
virtual ~EventLoop();
@@ -653,6 +654,9 @@
// range of Context::buffer_index values for this channel.
virtual int NumberBuffers(const Channel *channel) = 0;
+ // Returns the boot UUID.
+ const UUID &boot_uuid() { return boot_uuid_; }
+
protected:
// Sets the name of the event loop. This is the application name.
virtual void set_name(const std::string_view name) = 0;
@@ -732,6 +736,8 @@
// If true, don't send AOS_LOG to /aos
bool skip_logger_ = false;
+ UUID boot_uuid_;
+
private:
virtual pid_t GetTid() = 0;
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index e05f2b3..45ec394 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -26,8 +26,8 @@
visibility = ["//visibility:public"],
deps = [
":buffer_encoder",
- ":uuid",
":logger_fbs",
+ ":uuid",
"//aos:configuration",
"//aos:flatbuffer_merge",
"//aos:flatbuffers",
@@ -316,6 +316,10 @@
srcs = ["uuid.cc"],
hdrs = ["uuid.h"],
target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "@com_github_google_glog//:glog",
+ ],
)
cc_test(
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index c536711..8115400 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -686,25 +686,31 @@
UnorderedElementsAre(
std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
- std::make_tuple("/test", "aos.examples.Ping", 2001)));
+ std::make_tuple("/test", "aos.examples.Ping", 2001)))
+ << " : " << logfiles_[0];
// Timestamps for pong
EXPECT_THAT(
CountChannelsTimestamp(logfiles_[0]),
UnorderedElementsAre(
std::make_tuple("/test", "aos.examples.Pong", 2001),
- std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
+ std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
+ << " : " << logfiles_[0];
// Pong data.
- EXPECT_THAT(CountChannelsData(logfiles_[1]),
- UnorderedElementsAre(
- std::make_tuple("/test", "aos.examples.Pong", 101)));
+ EXPECT_THAT(
+ CountChannelsData(logfiles_[1]),
+ UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
+ << " : " << logfiles_[1];
EXPECT_THAT(CountChannelsData(logfiles_[2]),
UnorderedElementsAre(
- std::make_tuple("/test", "aos.examples.Pong", 1900)));
+ std::make_tuple("/test", "aos.examples.Pong", 1910)))
+ << " : " << logfiles_[1];
// No timestamps
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre())
+ << " : " << logfiles_[1];
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre())
+ << " : " << logfiles_[2];
// Timing reports and pongs.
EXPECT_THAT(
@@ -712,56 +718,74 @@
UnorderedElementsAre(
std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
- std::make_tuple("/test", "aos.examples.Pong", 2001)));
+ std::make_tuple("/test", "aos.examples.Pong", 2001)))
+ << " : " << logfiles_[3];
// And ping timestamps.
EXPECT_THAT(
CountChannelsTimestamp(logfiles_[3]),
UnorderedElementsAre(
std::make_tuple("/test", "aos.examples.Ping", 2001),
- std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
+ std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
+ << " : " << logfiles_[3];
// Timestamps from pi2 on pi1, and the other way.
- EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
+ EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre())
+ << " : " << logfiles_[4];
+ EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre())
+ << " : " << logfiles_[5];
+ EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre())
+ << " : " << logfiles_[6];
+ EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre())
+ << " : " << logfiles_[7];
EXPECT_THAT(
CountChannelsTimestamp(logfiles_[4]),
UnorderedElementsAre(
- std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
- std::make_tuple("/test", "aos.examples.Ping", 101)));
+ std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
+ std::make_tuple("/test", "aos.examples.Ping", 91)))
+ << " : " << logfiles_[4];
EXPECT_THAT(
CountChannelsTimestamp(logfiles_[5]),
UnorderedElementsAre(
- std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
- std::make_tuple("/test", "aos.examples.Ping", 1900)));
+ std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
+ std::make_tuple("/test", "aos.examples.Ping", 1910)))
+ << " : " << logfiles_[5];
EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
UnorderedElementsAre(std::make_tuple(
- "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
+ "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
+ << " : " << logfiles_[6];
EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
UnorderedElementsAre(std::make_tuple(
- "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
+ "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
+ << " : " << logfiles_[7];
// And then test that the remotely logged timestamp data files only have
// timestamps in them.
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
- EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre())
+ << " : " << logfiles_[8];
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre())
+ << " : " << logfiles_[9];
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre())
+ << " : " << logfiles_[10];
+ EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre())
+ << " : " << logfiles_[11];
EXPECT_THAT(CountChannelsData(logfiles_[8]),
UnorderedElementsAre(std::make_tuple(
- "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
+ "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
+ << " : " << logfiles_[8];
EXPECT_THAT(CountChannelsData(logfiles_[9]),
UnorderedElementsAre(std::make_tuple(
- "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
+ "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
+ << " : " << logfiles_[9];
EXPECT_THAT(CountChannelsData(logfiles_[10]),
UnorderedElementsAre(std::make_tuple(
- "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
+ "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
+ << " : " << logfiles_[10];
EXPECT_THAT(CountChannelsData(logfiles_[11]),
UnorderedElementsAre(std::make_tuple(
- "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
+ "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
+ << " : " << logfiles_[11];
}
LogReader reader(SortParts(logfiles_));
diff --git a/aos/events/logging/uuid.cc b/aos/events/logging/uuid.cc
index 376fa95..3914740 100644
--- a/aos/events/logging/uuid.cc
+++ b/aos/events/logging/uuid.cc
@@ -1,9 +1,14 @@
#include "aos/events/logging/uuid.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <array>
#include <random>
#include <string_view>
+#include "glog/logging.h"
+
namespace aos {
namespace {
char ToHex(int val) {
@@ -57,9 +62,24 @@
return result;
}
-UUID UUID::Zero() {
+UUID UUID::Zero() { return FromString("00000000-0000-0000-0000-000000000000"); }
+
+UUID UUID::FromString(std::string_view str) {
UUID result;
- result.data_.fill(0);
+ CHECK_EQ(str.size(), kSize);
+
+ std::copy(str.begin(), str.end(), result.data_.begin());
+ return result;
+}
+
+UUID UUID::BootUUID() {
+ int fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY);
+ PCHECK(fd != -1);
+
+ UUID result;
+ CHECK_EQ(static_cast<ssize_t>(kSize), read(fd, result.data_.begin(), kSize));
+ close(fd);
+
return result;
}
diff --git a/aos/events/logging/uuid.h b/aos/events/logging/uuid.h
index 0387a4b..d7ec33a 100644
--- a/aos/events/logging/uuid.h
+++ b/aos/events/logging/uuid.h
@@ -13,8 +13,16 @@
// Returns a randomly generated UUID. This is known as a UUID4.
static UUID Random();
+ // Returns a uuid with all '0' characters.
static UUID Zero();
+ static UUID FromString(std::string_view);
+
+ static UUID BootUUID();
+
+ // Size of a UUID.
+ static constexpr size_t kSize = 36;
+
std::string_view string_view() const {
return std::string_view(data_.data(), data_.size());
}
@@ -30,7 +38,7 @@
UUID() {}
// Fixed size storage for the data. Non-null terminated.
- std::array<char, 36> data_;
+ std::array<char, kSize> data_;
};
} // namespace aos
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index fed5f4c..2a0d332 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -222,7 +222,7 @@
} // namespace
ShmEventLoop::ShmEventLoop(const Configuration *configuration)
- : EventLoop(configuration),
+ : EventLoop(configuration, UUID::BootUUID()),
shm_base_(FLAGS_shm_base),
name_(FLAGS_application_name),
node_(MaybeMyNode(configuration)) {
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index 9c8bb09..80ba88c 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -455,7 +455,8 @@
std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
*raw_event_loops,
const Node *node, pid_t tid)
- : EventLoop(CHECK_NOTNULL(configuration)),
+ : EventLoop(CHECK_NOTNULL(configuration),
+ node_event_loop_factory->boot_uuid()),
scheduler_(scheduler),
node_event_loop_factory_(node_event_loop_factory),
channels_(channels),
diff --git a/aos/events/simulated_event_loop.h b/aos/events/simulated_event_loop.h
index 5ba7a8a..40deb43 100644
--- a/aos/events/simulated_event_loop.h
+++ b/aos/events/simulated_event_loop.h
@@ -13,6 +13,7 @@
#include "absl/container/btree_map.h"
#include "aos/events/event_loop.h"
#include "aos/events/event_scheduler.h"
+#include "aos/events/logging/uuid.h"
#include "aos/events/simple_channel.h"
#include "aos/flatbuffer_merge.h"
#include "aos/flatbuffers.h"
@@ -175,6 +176,15 @@
scheduler_.SetDistributedOffset(monotonic_offset, monotonic_slope);
}
+ // Returns the boot UUID for this node.
+ const UUID &boot_uuid() const { return boot_uuid_; }
+
+ // Reboots the node. This just resets the boot_uuid_, nothing else.
+ // TODO(austin): This is here for a test case or two, not for general
+ // consumption. The interactions with the rest of the system need to be
+ // worked out better. Don't use this for anything real yet.
+ void Reboot() { boot_uuid_ = UUID::Random(); }
+
private:
friend class SimulatedEventLoopFactory;
NodeEventLoopFactory(
@@ -186,6 +196,8 @@
EventScheduler scheduler_;
SimulatedEventLoopFactory *const factory_;
+ UUID boot_uuid_ = UUID::Random();
+
const Node *const node_;
std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
diff --git a/aos/events/simulated_event_loop_test.cc b/aos/events/simulated_event_loop_test.cc
index fb144c3..3768348 100644
--- a/aos/events/simulated_event_loop_test.cc
+++ b/aos/events/simulated_event_loop_test.cc
@@ -448,6 +448,7 @@
for (const message_bridge::ServerConnection *connection :
*stats.connections()) {
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
+ EXPECT_TRUE(connection->has_boot_uuid());
if (connection->node()->name()->string_view() == "pi2") {
EXPECT_GT(connection->sent_packets(), 50);
} else if (connection->node()->name()->string_view() == "pi3") {
@@ -471,6 +472,7 @@
const message_bridge::ServerConnection *connection =
stats.connections()->Get(0);
+ EXPECT_TRUE(connection->has_boot_uuid());
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
EXPECT_GT(connection->sent_packets(), 50);
EXPECT_TRUE(connection->has_monotonic_offset());
@@ -487,6 +489,7 @@
const message_bridge::ServerConnection *connection =
stats.connections()->Get(0);
+ EXPECT_TRUE(connection->has_boot_uuid());
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
EXPECT_GE(connection->sent_packets(), 5);
EXPECT_TRUE(connection->has_monotonic_offset());
@@ -577,8 +580,14 @@
"/pi1/aos/remote_timestamps/pi2",
[pi1_timestamp_channel, ping_timestamp_channel, &ping_on_pi2_fetcher,
&ping_on_pi1_fetcher, &pi1_on_pi2_timestamp_fetcher,
- &pi1_on_pi1_timestamp_fetcher](const RemoteMessage &header) {
+ &pi1_on_pi1_timestamp_fetcher, &simulated_event_loop_factory,
+ pi2](const RemoteMessage &header) {
VLOG(1) << aos::FlatbufferToJson(&header);
+ EXPECT_TRUE(header.has_boot_uuid());
+ EXPECT_EQ(header.boot_uuid()->string_view(),
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
+ ->boot_uuid()
+ .string_view());
const aos::monotonic_clock::time_point header_monotonic_sent_time(
chrono::nanoseconds(header.monotonic_sent_time()));
@@ -661,9 +670,9 @@
EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 100);
EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 100);
- EXPECT_EQ(pi1_server_statistics_count, 9);
- EXPECT_EQ(pi2_server_statistics_count, 9);
- EXPECT_EQ(pi3_server_statistics_count, 9);
+ EXPECT_EQ(pi1_server_statistics_count, 10);
+ EXPECT_EQ(pi2_server_statistics_count, 10);
+ EXPECT_EQ(pi3_server_statistics_count, 10);
EXPECT_EQ(pi1_client_statistics_count, 95);
EXPECT_EQ(pi2_client_statistics_count, 95);
@@ -721,6 +730,7 @@
for (const message_bridge::ServerConnection *connection :
*stats.connections()) {
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
+ EXPECT_TRUE(connection->has_boot_uuid());
if (connection->node()->name()->string_view() == "pi2") {
EXPECT_EQ(connection->monotonic_offset(),
chrono::nanoseconds(kOffset).count());
@@ -744,6 +754,7 @@
const message_bridge::ServerConnection *connection =
stats.connections()->Get(0);
+ EXPECT_TRUE(connection->has_boot_uuid());
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
EXPECT_TRUE(connection->has_monotonic_offset());
EXPECT_EQ(connection->monotonic_offset(),
@@ -760,6 +771,7 @@
const message_bridge::ServerConnection *connection =
stats.connections()->Get(0);
+ EXPECT_TRUE(connection->has_boot_uuid());
EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
EXPECT_TRUE(connection->has_monotonic_offset());
EXPECT_EQ(connection->monotonic_offset(), 0);
@@ -770,9 +782,9 @@
chrono::milliseconds(500) +
chrono::milliseconds(5));
- EXPECT_EQ(pi1_server_statistics_count, 9);
+ EXPECT_EQ(pi1_server_statistics_count, 10);
EXPECT_EQ(pi2_server_statistics_count, 9);
- EXPECT_EQ(pi3_server_statistics_count, 9);
+ EXPECT_EQ(pi3_server_statistics_count, 10);
}
// Test that disabling statistics actually disables them.
@@ -1024,8 +1036,13 @@
int reliable_timestamp_count = 0;
pi1_remote_timestamp->MakeWatcher(
"/pi1/aos/remote_timestamps/pi2",
- [reliable_channel_index,
- &reliable_timestamp_count](const RemoteMessage &header) {
+ [reliable_channel_index, &reliable_timestamp_count,
+ &simulated_event_loop_factory, pi2](const RemoteMessage &header) {
+ EXPECT_TRUE(header.has_boot_uuid());
+ EXPECT_EQ(header.boot_uuid()->string_view(),
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
+ ->boot_uuid()
+ .string_view());
VLOG(1) << aos::FlatbufferToJson(&header);
if (header.channel_index() == reliable_channel_index) {
++reliable_timestamp_count;
@@ -1051,5 +1068,84 @@
EXPECT_EQ(reliable_timestamp_count, 2u);
}
+// Tests that rebooting a node changes the ServerStatistics message and the
+// RemoteTimestamp message.
+TEST(SimulatedEventLoopTest, BootUUIDTest) {
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(ConfigPrefix() +
+ "events/multinode_pingpong_config.json");
+ const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
+ const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
+
+ SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
+
+ std::unique_ptr<EventLoop> ping_event_loop =
+ simulated_event_loop_factory.MakeEventLoop("ping", pi1);
+ Ping ping(ping_event_loop.get());
+
+ std::unique_ptr<EventLoop> pong_event_loop =
+ simulated_event_loop_factory.MakeEventLoop("pong", pi2);
+ Pong pong(pong_event_loop.get());
+
+ std::unique_ptr<EventLoop> pi1_remote_timestamp =
+ simulated_event_loop_factory.MakeEventLoop("pi1_remote_timestamp", pi1);
+ std::string expected_boot_uuid(
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
+ ->boot_uuid()
+ .string_view());
+
+ int timestamp_count = 0;
+ pi1_remote_timestamp->MakeWatcher(
+ "/pi1/aos/remote_timestamps/pi2",
+ [×tamp_count, &expected_boot_uuid](const RemoteMessage &header) {
+ EXPECT_TRUE(header.has_boot_uuid());
+ EXPECT_EQ(header.boot_uuid()->string_view(), expected_boot_uuid);
+ VLOG(1) << aos::FlatbufferToJson(&header);
+ ++timestamp_count;
+ });
+
+ int pi1_server_statistics_count = 0;
+ pi1_remote_timestamp->MakeWatcher(
+ "/pi1/aos", [&pi1_server_statistics_count, &expected_boot_uuid](
+ const message_bridge::ServerStatistics &stats) {
+ VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
+ for (const message_bridge::ServerConnection *connection :
+ *stats.connections()) {
+ EXPECT_TRUE(connection->has_boot_uuid());
+ if (connection->node()->name()->string_view() == "pi2") {
+ EXPECT_EQ(expected_boot_uuid,
+ connection->boot_uuid()->string_view())
+ << " : Got " << aos::FlatbufferToJson(&stats);
+ ++pi1_server_statistics_count;
+ }
+ }
+ });
+
+ // Let a couple of ServerStatistics messages show up before rebooting.
+ simulated_event_loop_factory.RunFor(chrono::milliseconds(2001));
+
+ EXPECT_GT(timestamp_count, 100);
+ EXPECT_GE(pi1_server_statistics_count, 1u);
+
+ // Confirm that reboot changes the UUID.
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)->Reboot();
+
+ EXPECT_NE(expected_boot_uuid,
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
+ ->boot_uuid()
+ .string_view());
+
+ expected_boot_uuid =
+ simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
+ ->boot_uuid()
+ .string_view();
+ timestamp_count = 0;
+ pi1_server_statistics_count = 0;
+
+ simulated_event_loop_factory.RunFor(chrono::milliseconds(2000));
+ EXPECT_GT(timestamp_count, 100);
+ EXPECT_GE(pi1_server_statistics_count, 1u);
+}
+
} // namespace testing
} // namespace aos
diff --git a/aos/events/simulated_network_bridge.cc b/aos/events/simulated_network_bridge.cc
index 1ba1408..45bc6e7 100644
--- a/aos/events/simulated_network_bridge.cc
+++ b/aos/events/simulated_network_bridge.cc
@@ -21,6 +21,8 @@
aos::EventLoop *send_event_loop,
std::unique_ptr<aos::RawFetcher> fetcher,
std::unique_ptr<aos::RawSender> sender,
+ MessageBridgeServerStatus *server_status,
+ size_t destination_node_index,
ServerConnection *server_connection, int client_index,
MessageBridgeClientStatus *client_status,
size_t channel_index,
@@ -30,6 +32,8 @@
send_event_loop_(send_event_loop),
fetcher_(std::move(fetcher)),
sender_(std::move(sender)),
+ server_status_(server_status),
+ destination_node_index_(destination_node_index),
server_connection_(server_connection),
client_status_(client_status),
client_index_(client_index),
@@ -123,6 +127,20 @@
aos::Sender<RemoteMessage>::Builder builder =
timestamp_logger_->MakeBuilder();
+ // Reset the filter every time the UUID changes. There's probably a more
+ // clever way to do this, but that means a better concept of rebooting.
+ if (server_status_->BootUUID(destination_node_index_) !=
+ send_node_factory_->boot_uuid().string_view()) {
+ server_status_->ResetFilter(destination_node_index_);
+ server_status_->SetBootUUID(
+ destination_node_index_,
+ send_node_factory_->boot_uuid().string_view());
+ }
+
+ flatbuffers::Offset<flatbuffers::String> boot_uuid_offset =
+ builder.fbb()->CreateString(
+ send_node_factory_->boot_uuid().string_view());
+
RemoteMessage::Builder message_header_builder =
builder.MakeBuilder<RemoteMessage>();
@@ -142,6 +160,7 @@
message_header_builder.add_realtime_sent_time(
sender_->realtime_sent_time().time_since_epoch().count());
message_header_builder.add_queue_index(sender_->sent_queue_index());
+ message_header_builder.add_boot_uuid(boot_uuid_offset);
builder.Send(message_header_builder.Finish());
}
@@ -172,6 +191,9 @@
std::unique_ptr<aos::RawFetcher> fetcher_;
// Sender to send them back out.
std::unique_ptr<aos::RawSender> sender_;
+
+ MessageBridgeServerStatus *server_status_;
+ const size_t destination_node_index_;
// True if we have sent the message in the fetcher.
bool sent_ = false;
@@ -222,6 +244,28 @@
}
}
+ for (const Node *node : simulated_event_loop_factory->nodes()) {
+ auto it = event_loop_map_.find(node);
+
+ CHECK(it != event_loop_map_.end());
+
+ size_t node_index = 0;
+ for (ServerConnection *connection :
+ it->second.server_status.server_connection()) {
+ if (connection != nullptr) {
+ const Node *client_node =
+ simulated_event_loop_factory->configuration()->nodes()->Get(
+ node_index);
+ auto client_event_loop = event_loop_map_.find(client_node);
+ it->second.server_status.ResetFilter(node_index);
+ it->second.server_status.SetBootUUID(
+ node_index,
+ client_event_loop->second.event_loop->boot_uuid().string_view());
+ }
+ ++node_index;
+ }
+ }
+
for (const Channel *channel :
*simulated_event_loop_factory->configuration()->channels()) {
if (!channel->has_destination_nodes()) {
@@ -268,6 +312,7 @@
destination_event_loop->second.event_loop.get(),
source_event_loop->second.event_loop->MakeRawFetcher(channel),
destination_event_loop->second.event_loop->MakeRawSender(channel),
+ &source_event_loop->second.server_status, destination_node_index,
server_connection, client_index,
&destination_event_loop->second.client_status,
configuration::ChannelIndex(
diff --git a/aos/network/connect.fbs b/aos/network/connect.fbs
index b593472..7ff2fbe 100644
--- a/aos/network/connect.fbs
+++ b/aos/network/connect.fbs
@@ -10,4 +10,9 @@
// The channels that we want transfered to this client.
channels_to_transfer:[Channel] (id: 1);
+
+ // The UUID that this node booted with.
+ boot_uuid: string (id: 2);
}
+
+root_type Connect;
diff --git a/aos/network/message_bridge_client_lib.cc b/aos/network/message_bridge_client_lib.cc
index 99b2ac1..38c3831 100644
--- a/aos/network/message_bridge_client_lib.cc
+++ b/aos/network/message_bridge_client_lib.cc
@@ -11,6 +11,7 @@
#include "aos/network/sctp_client.h"
#include "aos/network/timestamp_generated.h"
#include "aos/unique_malloc_ptr.h"
+#include "aos/util/file.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
@@ -97,8 +98,9 @@
std::vector<SctpClientChannelState> *channels, int client_index,
MessageBridgeClientStatus *client_status)
: event_loop_(event_loop),
- connect_message_(MakeConnectMessage(event_loop->configuration(), my_node,
- remote_name)),
+ connect_message_(
+ MakeConnectMessage(event_loop->configuration(), my_node, remote_name,
+ event_loop->boot_uuid().string_view())),
message_reception_reply_(MakeMessageHeaderReply()),
remote_node_(CHECK_NOTNULL(
configuration::GetNode(event_loop->configuration(), remote_name))),
diff --git a/aos/network/message_bridge_protocol.cc b/aos/network/message_bridge_protocol.cc
index 8936da8..53102c2 100644
--- a/aos/network/message_bridge_protocol.cc
+++ b/aos/network/message_bridge_protocol.cc
@@ -13,12 +13,15 @@
aos::FlatbufferDetachedBuffer<aos::message_bridge::Connect> MakeConnectMessage(
const Configuration *config, const Node *my_node,
- std::string_view remote_name) {
+ std::string_view remote_name, std::string_view boot_uuid) {
CHECK(config->has_nodes()) << ": Config must have nodes to transfer.";
flatbuffers::FlatBufferBuilder fbb;
fbb.ForceDefaults(true);
+ flatbuffers::Offset<flatbuffers::String> boot_uuid_offset =
+ fbb.CreateString(boot_uuid);
+
flatbuffers::Offset<Node> node_offset =
RecursiveCopyFlatBuffer<Node>(my_node, &fbb);
const std::string_view node_name = my_node->name()->string_view();
@@ -46,6 +49,7 @@
Connect::Builder connect_builder(fbb);
connect_builder.add_channels_to_transfer(channels_offset);
connect_builder.add_node(node_offset);
+ connect_builder.add_boot_uuid(boot_uuid_offset);
fbb.Finish(connect_builder.Finish());
return fbb.Release();
diff --git a/aos/network/message_bridge_protocol.h b/aos/network/message_bridge_protocol.h
index 7b6a248..5759a29 100644
--- a/aos/network/message_bridge_protocol.h
+++ b/aos/network/message_bridge_protocol.h
@@ -33,7 +33,7 @@
// Builds up a subscription request for my_node to remote_name.
aos::FlatbufferDetachedBuffer<aos::message_bridge::Connect> MakeConnectMessage(
const Configuration *config, const Node *my_node,
- std::string_view remote_name);
+ std::string_view remote_name, std::string_view boot_uuid);
} // namespace message_bridge
} // namespace aos
diff --git a/aos/network/message_bridge_server.fbs b/aos/network/message_bridge_server.fbs
index 1be0796..fa73ba5 100644
--- a/aos/network/message_bridge_server.fbs
+++ b/aos/network/message_bridge_server.fbs
@@ -27,6 +27,9 @@
// monotonic time.
monotonic_offset:int64 (id: 4);
+ // Boot UUID of the client.
+ boot_uuid:string (id: 5);
+
// TODO(austin): Per channel counts?
}
diff --git a/aos/network/message_bridge_server_lib.cc b/aos/network/message_bridge_server_lib.cc
index d8a632e..1ac6cb5 100644
--- a/aos/network/message_bridge_server_lib.cc
+++ b/aos/network/message_bridge_server_lib.cc
@@ -94,8 +94,9 @@
// and flushes. Whee.
}
-void ChannelState::HandleDelivery(sctp_assoc_t rcv_assoc_id, uint16_t /*ssn*/,
- absl::Span<const uint8_t> data) {
+void ChannelState::HandleDelivery(
+ sctp_assoc_t rcv_assoc_id, uint16_t /*ssn*/, absl::Span<const uint8_t> data,
+ const MessageBridgeServerStatus &server_status) {
const logger::MessageHeader *message_header =
flatbuffers::GetRoot<logger::MessageHeader>(data.data());
for (Peer &peer : peers_) {
@@ -110,6 +111,10 @@
aos::Sender<RemoteMessage>::Builder builder =
peer.timestamp_logger->MakeBuilder();
+ flatbuffers::Offset<flatbuffers::String> boot_uuid_offset =
+ builder.fbb()->CreateString(
+ server_status.BootUUID(peer.node_index));
+
RemoteMessage::Builder message_header_builder =
builder.MakeBuilder<RemoteMessage>();
@@ -131,6 +136,7 @@
message_header->realtime_sent_time());
message_header_builder.add_remote_queue_index(
message_header->queue_index());
+ message_header_builder.add_boot_uuid(boot_uuid_offset);
builder.Send(message_header_builder.Finish());
}
@@ -271,7 +277,8 @@
MakeConnectMessage(event_loop->configuration(),
configuration::GetNode(event_loop->configuration(),
destination_node_name),
- event_loop->node()->name()->string_view())
+ event_loop->node()->name()->string_view(),
+ UUID::Zero().string_view())
.span()
.size());
VLOG(1) << "Connection to " << destination_node_name << " has size "
@@ -410,6 +417,7 @@
->name()
->string_view();
server_status_.ResetFilter(node_index);
+ server_status_.SetBootUUID(node_index, "");
}
}
@@ -484,6 +492,7 @@
}
}
server_status_.ResetFilter(node_index);
+ server_status_.SetBootUUID(node_index, connect->boot_uuid()->string_view());
VLOG(1) << "Resetting filters for " << node_index << " "
<< event_loop_->configuration()
->nodes()
@@ -500,7 +509,8 @@
->HandleDelivery(
message->header.rcvinfo.rcv_assoc_id,
message->header.rcvinfo.rcv_ssn,
- absl::Span<const uint8_t>(message->data(), message->size));
+ absl::Span<const uint8_t>(message->data(), message->size),
+ server_status_);
}
if (VLOG_IS_ON(1)) {
diff --git a/aos/network/message_bridge_server_lib.h b/aos/network/message_bridge_server_lib.h
index 04b0e16..55f3fea 100644
--- a/aos/network/message_bridge_server_lib.h
+++ b/aos/network/message_bridge_server_lib.h
@@ -82,7 +82,8 @@
// Handles reception of delivery times.
void HandleDelivery(sctp_assoc_t rcv_assoc_id, uint16_t ssn,
- absl::Span<const uint8_t> data);
+ absl::Span<const uint8_t> data,
+ const MessageBridgeServerStatus &server_status);
// Handles (by consuming) failure to deliver a message.
void HandleFailure(
diff --git a/aos/network/message_bridge_server_status.cc b/aos/network/message_bridge_server_status.cc
index 1f2de0b..c5c30d7 100644
--- a/aos/network/message_bridge_server_status.cc
+++ b/aos/network/message_bridge_server_status.cc
@@ -85,6 +85,11 @@
statistics_.message().connections()->size());
filters_.resize(event_loop->configuration()->nodes()->size());
+ boot_uuids_.resize(event_loop->configuration()->nodes()->size());
+ for (std::string &boot_uuid : boot_uuids_) {
+ // Make sure the memory gets allocated.
+ boot_uuid.reserve(UUID::kSize);
+ }
timestamp_fetchers_.resize(event_loop->configuration()->nodes()->size());
server_connection_.resize(event_loop->configuration()->nodes()->size());
@@ -129,6 +134,13 @@
node_name);
}
+void MessageBridgeServerStatus::SetBootUUID(int node_index,
+ std::string_view boot_uuid) {
+ boot_uuids_[node_index] = boot_uuid;
+ SendStatistics();
+ last_statistics_send_time_ = event_loop_->monotonic_now();
+}
+
void MessageBridgeServerStatus::ResetFilter(int node_index) {
filters_[node_index].Reset();
server_connection_[node_index]->mutate_monotonic_offset(0);
@@ -153,6 +165,12 @@
node_builder.add_name(node_name_offset);
flatbuffers::Offset<Node> node_offset = node_builder.Finish();
+ flatbuffers::Offset<flatbuffers::String> boot_uuid_offset;
+ if (!boot_uuids_[node_index].empty() &&
+ connection->state() == State::CONNECTED) {
+ boot_uuid_offset = builder.fbb()->CreateString(boot_uuids_[node_index]);
+ }
+
ServerConnection::Builder server_connection_builder =
builder.MakeBuilder<ServerConnection>();
server_connection_builder.add_node(node_offset);
@@ -167,6 +185,10 @@
connection->monotonic_offset());
}
+ if (!boot_uuid_offset.IsNull()) {
+ server_connection_builder.add_boot_uuid(boot_uuid_offset);
+ }
+
server_connection_offsets_.emplace_back(server_connection_builder.Finish());
}
diff --git a/aos/network/message_bridge_server_status.h b/aos/network/message_bridge_server_status.h
index 814fccb..0e70e24 100644
--- a/aos/network/message_bridge_server_status.h
+++ b/aos/network/message_bridge_server_status.h
@@ -40,6 +40,14 @@
// Resets the filter and clears the entry from the server statistics.
void ResetFilter(int node_index);
+ // Sets the boot UUID for the provided node.
+ void SetBootUUID(int node_index, std::string_view boot_uuid);
+
+ // Returns the boot UUID for a node, or an empty string_view if there isn't
+ // one.
+ std::string_view BootUUID(int node_index) const {
+ return boot_uuids_[node_index];
+ }
// Returns the ServerConnection message which is updated by the server.
ServerConnection *FindServerConnection(std::string_view node_name);
@@ -83,6 +91,9 @@
// Bidirectional filters for each connection.
std::vector<ClippedAverageFilter> filters_;
+ // List of UUIDs for each node.
+ std::vector<std::string> boot_uuids_;
+
// Sender for the timestamps that we are forwarding over the network.
aos::Sender<Timestamp> timestamp_sender_;
diff --git a/aos/network/message_bridge_test.cc b/aos/network/message_bridge_test.cc
index ed192b7..8588423 100644
--- a/aos/network/message_bridge_test.cc
+++ b/aos/network/message_bridge_test.cc
@@ -152,7 +152,7 @@
"/pi1/aos",
[&ping_count, &pi2_client_event_loop, &ping_sender,
&pi1_server_statistics_count](const ServerStatistics &stats) {
- LOG(INFO) << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ServerStatistics " << FlatbufferToJson(&stats);
ASSERT_TRUE(stats.has_connections());
EXPECT_EQ(stats.connections()->size(), 1);
@@ -172,6 +172,7 @@
if (connection->node()->name()->string_view() ==
pi2_client_event_loop.node()->name()->string_view()) {
if (connection->state() == State::CONNECTED) {
+ EXPECT_TRUE(connection->has_boot_uuid());
connected = true;
}
}
@@ -193,7 +194,7 @@
int pi2_server_statistics_count = 0;
pong_event_loop.MakeWatcher("/pi2/aos", [&pi2_server_statistics_count](
const ServerStatistics &stats) {
- LOG(INFO) << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ServerStatistics " << FlatbufferToJson(&stats);
for (const ServerConnection *connection : *stats.connections()) {
if (connection->has_monotonic_offset()) {
++pi2_server_statistics_count;
@@ -203,6 +204,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(connection->has_boot_uuid());
}
}
});
@@ -210,7 +212,7 @@
int pi1_client_statistics_count = 0;
ping_event_loop.MakeWatcher("/pi1/aos", [&pi1_client_statistics_count](
const ClientStatistics &stats) {
- LOG(INFO) << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ClientStatistics " << FlatbufferToJson(&stats);
for (const ClientConnection *connection : *stats.connections()) {
if (connection->has_monotonic_offset()) {
@@ -230,7 +232,7 @@
int pi2_client_statistics_count = 0;
pong_event_loop.MakeWatcher("/pi2/aos", [&pi2_client_statistics_count](
const ClientStatistics &stats) {
- LOG(INFO) << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ClientStatistics " << FlatbufferToJson(&stats);
for (const ClientConnection *connection : *stats.connections()) {
if (connection->has_monotonic_offset()) {
@@ -286,6 +288,8 @@
VLOG(1) << "/pi1/aos/remote_timestamps/pi2 RemoteMessage "
<< aos::FlatbufferToJson(&header);
+ EXPECT_TRUE(header.has_boot_uuid());
+
const aos::monotonic_clock::time_point header_monotonic_sent_time(
chrono::nanoseconds(header.monotonic_sent_time()));
const aos::realtime_clock::time_point header_realtime_sent_time(
@@ -462,29 +466,29 @@
// Wait until we are connected, then send.
pi1_test_event_loop.MakeWatcher(
"/pi1/aos", [](const ServerStatistics &stats) {
- LOG(INFO) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ServerStatistics " << FlatbufferToJson(&stats);
});
pi2_test_event_loop.MakeWatcher(
"/pi2/aos", [](const ServerStatistics &stats) {
- LOG(INFO) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ServerStatistics " << FlatbufferToJson(&stats);
});
pi1_test_event_loop.MakeWatcher(
"/pi1/aos", [](const ClientStatistics &stats) {
- LOG(INFO) << "pi1 ClientStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ClientStatistics " << FlatbufferToJson(&stats);
});
pi2_test_event_loop.MakeWatcher(
"/pi2/aos", [](const ClientStatistics &stats) {
- LOG(INFO) << "pi2 ClientStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ClientStatistics " << FlatbufferToJson(&stats);
});
pi1_test_event_loop.MakeWatcher("/pi1/aos", [](const Timestamp ×tamp) {
- LOG(INFO) << "pi1 Timestamp " << FlatbufferToJson(×tamp);
+ LOG(INFO) << "/pi1/aos Timestamp " << FlatbufferToJson(×tamp);
});
pi2_test_event_loop.MakeWatcher("/pi2/aos", [](const Timestamp ×tamp) {
- LOG(INFO) << "pi2 Timestamp " << FlatbufferToJson(×tamp);
+ LOG(INFO) << "/pi2/aos Timestamp " << FlatbufferToJson(×tamp);
});
// Start everything up. Pong is the only thing we don't know how to wait on,
@@ -533,6 +537,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi1_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi1_connection->has_boot_uuid());
EXPECT_EQ(pi2_connection->state(), State::CONNECTED);
EXPECT_TRUE(pi2_connection->has_monotonic_offset());
@@ -540,6 +545,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi2_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi2_connection->has_boot_uuid());
}
std::this_thread::sleep_for(std::chrono::seconds(2));
@@ -555,8 +561,10 @@
EXPECT_EQ(pi1_connection->state(), State::DISCONNECTED);
EXPECT_FALSE(pi1_connection->has_monotonic_offset());
+ EXPECT_FALSE(pi1_connection->has_boot_uuid());
EXPECT_EQ(pi2_connection->state(), State::CONNECTED);
EXPECT_FALSE(pi2_connection->has_monotonic_offset());
+ EXPECT_TRUE(pi2_connection->has_boot_uuid());
}
{
@@ -591,6 +599,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi1_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi1_connection->has_boot_uuid());
EXPECT_EQ(pi2_connection->state(), State::CONNECTED);
EXPECT_TRUE(pi2_connection->has_monotonic_offset());
@@ -598,6 +607,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi2_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi2_connection->has_boot_uuid());
}
// Shut everyone else down
@@ -665,31 +675,31 @@
// Wait until we are connected, then send.
pi1_test_event_loop.MakeWatcher(
"/pi1/aos", [](const ServerStatistics &stats) {
- LOG(INFO) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ServerStatistics " << FlatbufferToJson(&stats);
});
// Confirm both client and server statistics messages have decent offsets in
// them.
pi2_test_event_loop.MakeWatcher(
"/pi2/aos", [](const ServerStatistics &stats) {
- LOG(INFO) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ServerStatistics " << FlatbufferToJson(&stats);
});
pi1_test_event_loop.MakeWatcher(
"/pi1/aos", [](const ClientStatistics &stats) {
- LOG(INFO) << "pi1 ClientStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi1/aos ClientStatistics " << FlatbufferToJson(&stats);
});
pi2_test_event_loop.MakeWatcher(
"/pi2/aos", [](const ClientStatistics &stats) {
- LOG(INFO) << "pi2 ClientStatistics " << FlatbufferToJson(&stats);
+ LOG(INFO) << "/pi2/aos ClientStatistics " << FlatbufferToJson(&stats);
});
pi1_test_event_loop.MakeWatcher("/pi1/aos", [](const Timestamp ×tamp) {
- LOG(INFO) << "pi1 Timestamp " << FlatbufferToJson(×tamp);
+ LOG(INFO) << "/pi1/aos Timestamp " << FlatbufferToJson(×tamp);
});
pi2_test_event_loop.MakeWatcher("/pi2/aos", [](const Timestamp ×tamp) {
- LOG(INFO) << "pi2 Timestamp " << FlatbufferToJson(×tamp);
+ LOG(INFO) << "/pi2/aos Timestamp " << FlatbufferToJson(×tamp);
});
// Start everything up. Pong is the only thing we don't know how to wait on,
@@ -738,6 +748,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi1_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi1_connection->has_boot_uuid());
EXPECT_EQ(pi2_connection->state(), State::CONNECTED);
EXPECT_TRUE(pi2_connection->has_monotonic_offset());
@@ -745,6 +756,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi2_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi2_connection->has_boot_uuid());
}
std::this_thread::sleep_for(std::chrono::seconds(2));
@@ -761,6 +773,7 @@
EXPECT_EQ(pi1_server_connection->state(), State::CONNECTED);
EXPECT_FALSE(pi1_server_connection->has_monotonic_offset());
+ EXPECT_TRUE(pi1_server_connection->has_boot_uuid());
EXPECT_EQ(pi1_client_connection->state(), State::DISCONNECTED);
EXPECT_FALSE(pi1_client_connection->has_monotonic_offset());
}
@@ -797,6 +810,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi1_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi1_connection->has_boot_uuid());
EXPECT_EQ(pi2_connection->state(), State::CONNECTED);
EXPECT_TRUE(pi2_connection->has_monotonic_offset());
@@ -804,6 +818,7 @@
chrono::milliseconds(1));
EXPECT_GT(chrono::nanoseconds(pi2_connection->monotonic_offset()),
chrono::milliseconds(-1));
+ EXPECT_TRUE(pi2_connection->has_boot_uuid());
}
// Shut everyone else down
@@ -883,6 +898,7 @@
[ping_channel_index, &ping_timestamp_count](const RemoteMessage &header) {
VLOG(1) << "/pi1/aos/remote_timestamps/pi2 RemoteMessage "
<< aos::FlatbufferToJson(&header);
+ EXPECT_TRUE(header.has_boot_uuid());
if (header.channel_index() == ping_channel_index) {
++ping_timestamp_count;
}
@@ -1038,6 +1054,7 @@
[ping_channel_index, &ping_timestamp_count](const RemoteMessage &header) {
VLOG(1) << "/pi1/aos/remote_timestamps/pi2 RemoteMessage "
<< aos::FlatbufferToJson(&header);
+ EXPECT_TRUE(header.has_boot_uuid());
if (header.channel_index() == ping_channel_index) {
++ping_timestamp_count;
}
diff --git a/aos/network/remote_message.fbs b/aos/network/remote_message.fbs
index 5659704..b43f055 100644
--- a/aos/network/remote_message.fbs
+++ b/aos/network/remote_message.fbs
@@ -26,6 +26,9 @@
realtime_remote_time:int64 = -9223372036854775808 (id: 6);
// Queue index of this message on the remote node.
remote_queue_index:uint32 = 4294967295 (id: 7);
+
+ // UUID for this boot.
+ boot_uuid:string (id: 8);
}
root_type RemoteMessage;