Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb396eb7 authored by Tej Singh's avatar Tej Singh
Browse files

Fix edge case in statsd alarms

Right now, if an alarm fires exactly on time (within 1 second), or
exactly on a multiple of its period, statsd will reset the alarm for the
same time, which can result a loop of statsd setting an alarm, the alarm
firing, statsd setting an alarm at the same time, etc.

The fix is that if an alarm fires on time, we should move to the next
period.

Test: atest statsd_test (added to a test, which would fail without the
code change)
Bug: 159098080

Change-Id: I150538cb1d3d5a2b943df2a32d92f8f84bb96626
Merged-In: I150538cb1d3d5a2b943df2a32d92f8f84bb96626
parent 9dd718c5
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -61,11 +61,11 @@ void AlarmTracker::addSubscription(const Subscription& subscription) {
}
}


int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
    if (currentTimeSec <= mAlarmSec) {
    if (currentTimeSec < mAlarmSec) {
        return mAlarmSec;
        return mAlarmSec;
    }
    }
    int64_t periodsForward =
    int64_t periodsForward =
        ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1;
        ((currentTimeSec - mAlarmSec) * MS_PER_SEC) / mAlarmConfig.period_millis() + 1;
    return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
    return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
}
}


+27 −3
Original line number Original line Diff line number Diff line
@@ -40,23 +40,47 @@ TEST(AlarmTrackerTest, TestTriggerTimestamp) {
    alarm.set_offset_millis(15 * MS_PER_SEC);
    alarm.set_offset_millis(15 * MS_PER_SEC);
    alarm.set_period_millis(60 * 60 * MS_PER_SEC);  // 1hr
    alarm.set_period_millis(60 * 60 * MS_PER_SEC);  // 1hr
    int64_t startMillis = 100000000 * MS_PER_SEC;
    int64_t startMillis = 100000000 * MS_PER_SEC;
    int64_t nextAlarmTime = startMillis / MS_PER_SEC + 15;
    AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
    AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);


    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);


    uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
    uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
        subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
        subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
    EXPECT_TRUE(firedAlarmSet.empty());
    EXPECT_TRUE(firedAlarmSet.empty());
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);


    currentTimeSec = startMillis / MS_PER_SEC + 7000;
    currentTimeSec = startMillis / MS_PER_SEC + 7000;
    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
    EXPECT_EQ(firedAlarmSet.size(), 1u);
    EXPECT_EQ(firedAlarmSet.size(), 1u);
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    EXPECT_TRUE(firedAlarmSet.empty());
    EXPECT_TRUE(firedAlarmSet.empty());
    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);

    // Alarm fires exactly on time.
    currentTimeSec = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 3 * 60 * 60;
    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
    ASSERT_EQ(firedAlarmSet.size(), 1u);
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    EXPECT_TRUE(firedAlarmSet.empty());
    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);

    // Alarm fires exactly 1 period late.
    currentTimeSec = startMillis / MS_PER_SEC + 15 + 4 * 60 * 60;
    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 5 * 60 * 60;
    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
    ASSERT_EQ(firedAlarmSet.size(), 1u);
    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
    EXPECT_TRUE(firedAlarmSet.empty());
    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
}
}


}  // namespace statsd
}  // namespace statsd