diff --git a/CHANGELOG.md b/CHANGELOG.md index 788b57211..8ebdf9b2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.10.1](https://github.com/rdkcentral/telemetry/compare/1.10.0...1.10.1) + +- RDKB-65621: Propagate seek-map clearing across log-upload profiles [`#414`](https://github.com/rdkcentral/telemetry/pull/414) + #### [1.10.0](https://github.com/rdkcentral/telemetry/compare/1.9.9...1.10.0) > 13 August 2026 @@ -22,6 +26,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Resolve build error in telemetry [`#364`](https://github.com/rdkcentral/telemetry/pull/364) - TELEMETRY-2: Dynamic telemetry markers for Dynamic Tables in Telemetry [`#161`](https://github.com/rdkcentral/telemetry/pull/161) - RDKEMW-12350: Fix uninitialized missing error checks in timeZoneDST fallback path [`9de29ae`](https://github.com/rdkcentral/telemetry/commit/9de29aec28cce9641950380c05a9e31afd64b1a0) +- Changelog updates for 1.10.0 updates [`a3b7639`](https://github.com/rdkcentral/telemetry/commit/a3b7639177a7af39a2796c2ee911bd65f6f693b5) - RDKEMW-21242: Skipping inode check for Previous Log data collection [`8b58ce8`](https://github.com/rdkcentral/telemetry/commit/8b58ce896dcdf4a7c80b7efa426aa33700efaa15) #### [1.9.9](https://github.com/rdkcentral/telemetry/compare/1.9.8...1.9.9) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 342d7d576..e6de93319 100644 --- a/source/bulkdata/profile.c +++ b/source/bulkdata/profile.c @@ -1562,7 +1562,7 @@ T2ERROR deleteProfile(const char *profileName) return T2ERROR_SUCCESS; } -void sendLogUploadInterruptToScheduler() +void sendLogUploadInterruptToScheduler(bool isClearSeekMap) { size_t profileIndex = 0; Profile *tempProfile = NULL; @@ -1574,7 +1574,7 @@ void sendLogUploadInterruptToScheduler() tempProfile = (Profile *)Vector_At(profileList, profileIndex); if (Vector_Size(tempProfile->gMarkerList) > 0) { - SendInterruptToTimeoutThread(tempProfile->name); + SendInterruptToTimeoutThread(tempProfile->name, isClearSeekMap); } } pthread_rwlock_unlock(&profileListLock); @@ -2066,7 +2066,7 @@ T2ERROR triggerReportOnCondtion(const char *referenceName, const char *reference triggerCondition->oprator, triggerCondition->threshold); if(tempProfile->isSchedulerstarted) { - SendInterruptToTimeoutThread(tempProfilename); + SendInterruptToTimeoutThread(tempProfilename, false); // triggerCondMutex will be unlocked by CollectAndReport after report generation } else diff --git a/source/bulkdata/profile.h b/source/bulkdata/profile.h index 181ae9403..7bbfaa24f 100644 --- a/source/bulkdata/profile.h +++ b/source/bulkdata/profile.h @@ -139,7 +139,7 @@ void updateMarkerComponentMap(); hash_map_t *getProfileHashMap(); -void sendLogUploadInterruptToScheduler(); +void sendLogUploadInterruptToScheduler(bool isClearSeekMap); void NotifyTimeout(const char* profileName, bool isClearSeekMap); diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index c01f1eb01..6c02b0b34 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -198,8 +198,15 @@ void ReportProfiles_Interrupt() { T2Debug("%s ++in\n", __FUNCTION__); + /* + * Capture retainseekmap state once for this LOG_UPLOAD event. + * The same value must be propagated to all interrupted profiles + * to avoid race conditions between profile timeout threads. + */ + bool isClearSeekMap = !get_retainseekmap(); + // Interrupt the multi profile first as the DCADONE Flag is added from the xconf - sendLogUploadInterruptToScheduler(); + sendLogUploadInterruptToScheduler(isClearSeekMap); char* xconfProfileName = NULL ; if (ProfileXConf_isSet()) @@ -207,11 +214,17 @@ void ReportProfiles_Interrupt() xconfProfileName = ProfileXconf_getName(); if (xconfProfileName) { - SendInterruptToTimeoutThread(xconfProfileName); + SendInterruptToTimeoutThread(xconfProfileName, isClearSeekMap); free(xconfProfileName); } } + /* + * Reset the global flag after the value has been distributed + * to all profiles. + */ + set_retainseekmap(true); + T2Debug("%s --out\n", __FUNCTION__); } diff --git a/source/scheduler/scheduler.c b/source/scheduler/scheduler.c index daeb0bd87..f6a737100 100644 --- a/source/scheduler/scheduler.c +++ b/source/scheduler/scheduler.c @@ -343,15 +343,9 @@ void* TimeoutThread(void *arg) if(minThresholdTime == 0) { - if (get_retainseekmap() == true) - { - timeoutNotificationCb(tProfile->name, false); // Passing clearseekvalue as false - } - else - { - set_retainseekmap(true); //After triggering LOG upload resetting the retainseekmap value to true so the next report generation doesn't affect - timeoutNotificationCb(tProfile->name, true); //Passing clearseek value as true - } + timeoutNotificationCb(tProfile->name, tProfile->isClearSeekMap); + tProfile->isClearSeekMap = false; + if(tProfile->terminated) { T2Warning("Profile : %s is being removed from scheduler \n", tProfile->name); @@ -421,7 +415,7 @@ void* TimeoutThread(void *arg) return NULL; } -T2ERROR SendInterruptToTimeoutThread(char* profileName) +T2ERROR SendInterruptToTimeoutThread(char* profileName, bool isClearSeekMap) { SchedulerProfile *tProfile = NULL; T2Debug("%s ++in\n", __FUNCTION__); @@ -458,6 +452,7 @@ T2ERROR SendInterruptToTimeoutThread(char* profileName) pthread_mutex_unlock(&scMutex); return T2ERROR_FAILURE; } + tProfile->isClearSeekMap = isClearSeekMap; pthread_cond_signal(&tProfile->tCond); if(pthread_mutex_unlock(&tProfile->tMutex) != 0) { @@ -610,6 +605,7 @@ T2ERROR registerProfileWithScheduler(const char* profileName, unsigned int timeI tProfile->reportonupdate = reportOnUpdate; tProfile->firstreportint = firstReportingInterval; tProfile->firstexecution = false; + tProfile->isClearSeekMap = false; tProfile->timeRef = timeRef; tProfile->timeRefinSec = 0; if(tProfile->timeOutDuration < tProfile->firstreportint) diff --git a/source/scheduler/scheduler.h b/source/scheduler/scheduler.h index 356cf398e..a1d6c885b 100644 --- a/source/scheduler/scheduler.h +++ b/source/scheduler/scheduler.h @@ -38,6 +38,7 @@ typedef struct _SchedulerProfile bool reportonupdate; unsigned int firstreportint; bool firstexecution; + bool isClearSeekMap; pthread_t tId; pthread_mutex_t tMutex; pthread_cond_t tCond; @@ -58,7 +59,7 @@ T2ERROR registerProfileWithScheduler(const char* profileName, unsigned int timeI T2ERROR unregisterProfileFromScheduler(const char* profileName); -T2ERROR SendInterruptToTimeoutThread(char* profileName); +T2ERROR SendInterruptToTimeoutThread(char* profileName, bool isClearSeekMap); bool get_retainseekmap(); diff --git a/source/test/bulkdata/SchedulerMock.cpp b/source/test/bulkdata/SchedulerMock.cpp index 0611b6424..6c4b77b24 100755 --- a/source/test/bulkdata/SchedulerMock.cpp +++ b/source/test/bulkdata/SchedulerMock.cpp @@ -73,11 +73,11 @@ T2ERROR unregisterProfileFromScheduler(const char* profileName) return T2ERROR_SUCCESS; } -T2ERROR SendInterruptToTimeoutThread(char* profileName) +T2ERROR SendInterruptToTimeoutThread(char* profileName, bool isClearSeekMap) { if (g_schedulerMock) { - return g_schedulerMock->SendInterruptToTimeoutThread(profileName); + return g_schedulerMock->SendInterruptToTimeoutThread(profileName, isClearSeekMap); } // Fallback implementation for when mock is not set diff --git a/source/test/bulkdata/SchedulerMock.h b/source/test/bulkdata/SchedulerMock.h index ad1c6d30e..d4ab47e20 100755 --- a/source/test/bulkdata/SchedulerMock.h +++ b/source/test/bulkdata/SchedulerMock.h @@ -34,7 +34,7 @@ class SchedulerMock MOCK_METHOD(void, uninitScheduler, (), ()); MOCK_METHOD(T2ERROR, registerProfileWithScheduler, (const char* profileName, unsigned int timeInterval, unsigned int activationTimeout, bool deleteonTimout, bool repeat, bool reportOnUpdate, unsigned int firstReportingInterval, char *timeRef), ()); MOCK_METHOD(T2ERROR, unregisterProfileFromScheduler, (const char* profileName), ()); - MOCK_METHOD(T2ERROR, SendInterruptToTimeoutThread, (char* profileName), ()); + MOCK_METHOD(T2ERROR, SendInterruptToTimeoutThread, (char* profileName, bool isClearSeekMap), ()); MOCK_METHOD(bool, get_retainseekmap, (), ()); MOCK_METHOD(void, set_retainseekmap, (bool value), ()); MOCK_METHOD(int, getLapsedTime, (struct timespec *result, struct timespec *x, struct timespec *y), ()); diff --git a/source/test/bulkdata/profileTest.cpp b/source/test/bulkdata/profileTest.cpp index f2b432058..f56d05f3e 100644 --- a/source/test/bulkdata/profileTest.cpp +++ b/source/test/bulkdata/profileTest.cpp @@ -656,9 +656,14 @@ TEST_F(ProfileTest, ReportProfiles_Interrupt_Coverage) { .WillRepeatedly(Return(0)); // Return 1 to indicate only one profile (no duplicates) // ReportProfiles_Interrupt calls SendInterruptToTimeoutThread for xconf profile if ProfileXConf_isSet - EXPECT_CALL(*g_schedulerMock, SendInterruptToTimeoutThread(_)) + EXPECT_CALL(*g_schedulerMock, SendInterruptToTimeoutThread(_, _)) .Times(::testing::AtMost(1)); // ProfileXConf is not set in this test, so no interrupt call + EXPECT_CALL(*g_schedulerMock, get_retainseekmap()) + .Times(::testing::AtMost(1)); + EXPECT_CALL(*g_schedulerMock, set_retainseekmap(_)) + .Times(::testing::AtMost(1)); + ReportProfiles_Interrupt(); } @@ -1030,7 +1035,12 @@ TEST_F(ProfileTest, SetAndIsSet) { test_set_reportThreadExits(true); generateDcaReport(false,true); - EXPECT_CALL(*g_schedulerMock, SendInterruptToTimeoutThread(_)) + EXPECT_CALL(*g_schedulerMock, SendInterruptToTimeoutThread(_, _)) + .Times(::testing::AtMost(1)); + + EXPECT_CALL(*g_schedulerMock, get_retainseekmap()) + .Times(::testing::AtMost(1)); + EXPECT_CALL(*g_schedulerMock, set_retainseekmap(_)) .Times(::testing::AtMost(1)); ReportProfiles_Interrupt(); diff --git a/source/test/scheduler/schedulerTest.cpp b/source/test/scheduler/schedulerTest.cpp index 53ec7ada2..4186c16a1 100644 --- a/source/test/scheduler/schedulerTest.cpp +++ b/source/test/scheduler/schedulerTest.cpp @@ -229,7 +229,7 @@ TEST(initScheduler, NULL_CALLBACK) TEST(SendInterruptToTimeoutThread, NON_NULL_CHECK) { - EXPECT_EQ(T2ERROR_SUCCESS, SendInterruptToTimeoutThread("RDKB_Profile")); + EXPECT_EQ(T2ERROR_SUCCESS, SendInterruptToTimeoutThread("RDKB_Profile", false)); } TEST(REGISTERSCHEWITHPROFILE_AFTER_INITSCHEDULER, REGISTER_PROFILE) @@ -267,7 +267,7 @@ TEST(UNREGISTERPROFILEFROMSCHEDULER, BEFORE_INIT) TEST(SENDINTERRUPTTOTIMEOUTTHREAD, NOT_INITIALIZED) { uninitScheduler(); // ensure not initialized - EXPECT_EQ(T2ERROR_FAILURE, SendInterruptToTimeoutThread("SHOULD_FAIL")); + EXPECT_EQ(T2ERROR_FAILURE, SendInterruptToTimeoutThread("SHOULD_FAIL", false)); } @@ -372,7 +372,7 @@ TEST(TIMEOUTTHREAD, WAIT_NO_REPORTING_INTERVAL) TEST(SendInterruptToTimeoutThread, NULL_CHECK) { - EXPECT_EQ(T2ERROR_INVALID_ARGS, SendInterruptToTimeoutThread(NULL)); + EXPECT_EQ(T2ERROR_INVALID_ARGS, SendInterruptToTimeoutThread(NULL, false)); } #if 0 TEST(UNREGISTERPROFILEFROMSCH_AFTER_INITSCHEDULER, UNREGISTER_PROFILE_NOT_REGISTERED)