Skip to content
This repository was archived by the owner on Feb 29, 2024. It is now read-only.

Commit 7a040e9

Browse files
authored
fix: Breakpoint expiry now uses create time (#71)
Updated the internal agent code and breakpoint json model to support the `createTimeUnixMsec` field which is used in the Firebase Backend version of the agent. When determining the breakpoint expiry this field will now be used. Fixes #66
1 parent 6c5d51a commit 7a040e9

7 files changed

Lines changed: 135 additions & 4 deletions

File tree

src/agent/jvm_breakpoint.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,12 @@ void JvmBreakpoint::Initialize() {
205205

206206
// Schedule breakpoint cancellation.
207207
time_t expiration_time_base;
208-
if (definition_->create_time == kUnspecifiedTimestamp) {
208+
if (model_util::GetCreateTimestamp(*definition_) == kUnspecifiedTimestamp) {
209209
// It really shouldn't happen, but if it does start computing expiration
210210
// time from this moment.
211211
expiration_time_base = scheduler_->CurrentTime();
212212
} else {
213-
expiration_time_base = definition_->create_time.seconds;
213+
expiration_time_base = model_util::GetCreateTimestamp(*definition_).seconds;
214214
}
215215

216216
int32_t expiration_seconds = absl::GetFlag(FLAGS_breakpoint_expiration_sec);

src/agent/model.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,16 @@ struct BreakpointModel {
144144
std::string log_message_format;
145145
LogLevel log_level = LogLevel::INFO;
146146
bool is_final_state = false;
147+
148+
// The Cloud Debugger GCP Backend version of the service uses a field called
149+
// 'create_time' to represent the breakpoint creation time. The OSS Snapshot
150+
// Debugger Firebase Backend version of the service uses a field called
151+
// 'create_time_unix_msec'. For simplicity when serializing we treat them
152+
// seperately and they will either get serialized or not depending on if they
153+
// have a real value or not.
147154
TimestampModel create_time;
155+
TimestampModel create_time_unix_msec;
156+
148157
std::unique_ptr<StatusMessageModel> status;
149158
std::vector<std::unique_ptr<StackFrameModel>> stack;
150159
std::vector<std::unique_ptr<VariableModel>> evaluated_expressions;

src/agent/model_json.cc

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ static void SerializeTimestamp(
270270
(*root) = Json::Value(value);
271271
}
272272

273+
static void SerializeTimestampUnixMsec(const TimestampModel& model,
274+
Json::Value* root) {
275+
int64_t total_millis = model.seconds * 1000 + model.nanos / (1000 * 1000);
276+
(*root) = Json::Value(total_millis);
277+
}
273278

274279
static void SerializeModel(
275280
const StatusMessageModel& model,
@@ -374,6 +379,23 @@ TimestampModel DeserializeTimestamp(const Json::Value& root) {
374379
return timestamp;
375380
}
376381

382+
TimestampModel DeserializeTimestampUnixMsec(const Json::Value& root) {
383+
if (!root.isInt64()) {
384+
return kUnspecifiedTimestamp;
385+
}
386+
387+
int64_t total_millis = root.asInt64();
388+
389+
if (total_millis == 0) {
390+
return kUnspecifiedTimestamp;
391+
}
392+
393+
TimestampModel timestamp;
394+
timestamp.seconds = total_millis / 1000;
395+
timestamp.nanos = (total_millis % 1000) * 1000 * 1000;
396+
397+
return timestamp;
398+
}
377399

378400
template <>
379401
std::unique_ptr<StatusMessageModel> DeserializeModel<StatusMessageModel>(
@@ -558,6 +580,11 @@ static void SerializeModel(
558580
SerializeTimestamp(model.create_time, &(*root)["createTime"]);
559581
}
560582

583+
if (model.create_time_unix_msec != kUnspecifiedTimestamp) {
584+
SerializeTimestampUnixMsec(model.create_time_unix_msec,
585+
&(*root)["createTimeUnixMsec"]);
586+
}
587+
561588
if (model.status != nullptr) {
562589
SerializeModel(*model.status, &(*root)["status"]);
563590
}
@@ -611,9 +638,16 @@ std::unique_ptr<BreakpointModel> DeserializeModel<BreakpointModel>(
611638
// Final state flag.
612639
model->is_final_state = JsonCppGetBool(root, "isFinalState", false);
613640

614-
// Breakpoint creation time.
641+
// Breakpoint creation time. This field is from the Cloud Debugger GCP Backend
642+
// version of the service, and is a string in RFC3339 format.
615643
model->create_time = DeserializeTimestamp(root["createTime"]);
616644

645+
// Breakpoint creation time. This field is from the OSS Snapshot Debugger
646+
// Firebase Backend version of the service, and is an integer representing
647+
// unix epoch time in milliseconds.
648+
model->create_time_unix_msec =
649+
DeserializeTimestampUnixMsec(root["createTimeUnixMsec"]);
650+
617651
// Breakpoint status.
618652
if (root.isMember("status")) {
619653
model->status = DeserializeModel<StatusMessageModel>(root["status"]);

src/agent/model_util.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ class BreakpointBuilder {
418418
set_is_final_state(source.is_final_state);
419419

420420
set_create_time(source.create_time);
421+
set_create_time_unix_msec(source.create_time_unix_msec);
421422

422423
if (source.status != nullptr) {
423424
set_status(StatusMessageBuilder(*source.status).build());
@@ -501,6 +502,11 @@ class BreakpointBuilder {
501502
return *this;
502503
}
503504

505+
BreakpointBuilder& set_create_time_unix_msec(TimestampModel timestamp) {
506+
data_->create_time_unix_msec = timestamp;
507+
return *this;
508+
}
509+
504510
BreakpointBuilder& clear_status() {
505511
return set_status(nullptr);
506512
}
@@ -660,7 +666,6 @@ class ErrorOr {
660666
FormatMessageModel error_message_;
661667
};
662668

663-
664669
inline bool operator== (const TimestampModel& t1, const TimestampModel& t2) {
665670
return (t1.seconds == t2.seconds) && (t1.nanos == t2.nanos);
666671
}
@@ -670,6 +675,16 @@ inline bool operator!= (const TimestampModel& t1, const TimestampModel& t2) {
670675
return !(t1 == t2);
671676
}
672677

678+
namespace model_util {
679+
680+
inline TimestampModel GetCreateTimestamp(const BreakpointModel& model) {
681+
return (model.create_time != kUnspecifiedTimestamp)
682+
? model.create_time
683+
: model.create_time_unix_msec;
684+
}
685+
686+
} // namespace model_util
687+
673688
inline bool operator== (const DurationModel& d1, const DurationModel& d2) {
674689
return (d1.seconds == d2.seconds) && (d1.nanos == d2.nanos);
675690
}

tests/agent/jvm_breakpoint_test.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,19 @@ TEST_F(JvmBreakpointTest, BreakpointExpirationWithCreatedTime) {
575575
scheduler_.Process();
576576
}
577577

578+
TEST_F(JvmBreakpointTest, BreakpointExpirationWithCreatedTimeUnixMsec) {
579+
Create(BreakpointBuilder(*breakpoint_template_)
580+
.set_create_time_unix_msec(
581+
TimestampBuilder::Build(simulated_time_sec_))
582+
.build());
583+
584+
EXPECT_CALL(breakpoints_manager_, CompleteBreakpoint("test_breakpoint_id"))
585+
.WillOnce(Return());
586+
587+
simulated_time_sec_ += absl::GetFlag(FLAGS_breakpoint_expiration_sec);
588+
scheduler_.Process();
589+
}
590+
578591
TEST_F(JvmBreakpointTest, BreakpointExpirationNoCreatedTime) {
579592
Create(BreakpointBuilder(*breakpoint_template_).build());
580593

tests/agent/model_json_test.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ static bool IsEqual(
136136
(model1.log_level == model2.log_level) &&
137137
(model1.is_final_state == model2.is_final_state) &&
138138
(model1.create_time == model2.create_time) &&
139+
(model1.create_time_unix_msec == model2.create_time_unix_msec) &&
139140
IsEqual(model1.status, model2.status) &&
140141
IsEqual(model1.stack, model2.stack) &&
141142
IsEqual(model1.evaluated_expressions, model2.evaluated_expressions) &&
@@ -388,6 +389,19 @@ TEST_F(ModelJsonTest, BreakpointCreateTime) {
388389
}
389390

390391

392+
TEST_F(ModelJsonTest, BreakpointCreateTimeUnixMsec) {
393+
std::unique_ptr<BreakpointModel> breakpoint = CreateFullBreakpoint();
394+
395+
breakpoint->create_time_unix_msec.seconds = 1444163838L;
396+
breakpoint->create_time_unix_msec.nanos = 893000000;
397+
SerializationLoop(*breakpoint);
398+
399+
breakpoint->create_time_unix_msec.seconds = 3489578;
400+
breakpoint->create_time_unix_msec.nanos = TimestampModel().nanos;
401+
SerializationLoop(*breakpoint);
402+
}
403+
404+
391405
TEST_F(ModelJsonTest, UserId_Empty) {
392406
std::unique_ptr<BreakpointModel> breakpoint = CreateFullBreakpoint();
393407
breakpoint->evaluated_user_id.reset(new UserIdModel());

tests/agent/model_util_test.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
namespace devtools {
2727
namespace cdbg {
2828

29+
using testing::Eq;
30+
2931
class ModelUtilTest : public ::testing::Test {
3032
protected:
3133
void SetUp() override {
@@ -440,6 +442,50 @@ TEST_F(ModelUtilTest, BreakpointCreateTime) {
440442
}
441443

442444

445+
TEST_F(ModelUtilTest, BreakpointCreateTimeUnixMsec) {
446+
TimestampModel test_timestamp;
447+
test_timestamp.seconds = 1444163838L;
448+
test_timestamp.nanos = 123456789; // Internal precision is milliseconds.
449+
// Will be truncated to '123'.
450+
CheckBuilder(
451+
"{"
452+
" 'id' : 'A'"
453+
"}",
454+
BreakpointBuilder().set_id("A").set_create_time_unix_msec(
455+
kUnspecifiedTimestamp));
456+
457+
CheckBuilder(
458+
"{"
459+
" 'id' : 'A',"
460+
" 'createTimeUnixMsec' : 1444163838123"
461+
"}",
462+
BreakpointBuilder().set_id("A").set_create_time_unix_msec(
463+
test_timestamp));
464+
}
465+
466+
TEST_F(ModelUtilTest, GetCreateTimestamp) {
467+
TimestampModel test_timestamp;
468+
test_timestamp.seconds = 1444163838L;
469+
test_timestamp.nanos = 123456789;
470+
471+
auto bp1 = BreakpointBuilder()
472+
.set_create_time(test_timestamp)
473+
.set_create_time_unix_msec(kUnspecifiedTimestamp)
474+
.build();
475+
auto bp2 = BreakpointBuilder()
476+
.set_create_time(kUnspecifiedTimestamp)
477+
.set_create_time_unix_msec(test_timestamp)
478+
.build();
479+
auto bp3 = BreakpointBuilder()
480+
.set_create_time(kUnspecifiedTimestamp)
481+
.set_create_time_unix_msec(kUnspecifiedTimestamp)
482+
.build();
483+
484+
EXPECT_THAT(model_util::GetCreateTimestamp(*bp1), Eq(test_timestamp));
485+
EXPECT_THAT(model_util::GetCreateTimestamp(*bp2), Eq(test_timestamp));
486+
EXPECT_THAT(model_util::GetCreateTimestamp(*bp3), Eq(kUnspecifiedTimestamp));
487+
}
488+
443489
TEST_F(ModelUtilTest, SetBreakpointLabels) {
444490
std::map<std::string, std::string> labels;
445491
labels["key1"] = "value1";

0 commit comments

Comments
 (0)