From e6b31018541e140f2100f01ab8fc62a0013a3ffe Mon Sep 17 00:00:00 2001 From: tabbas651 <74683978+tabbas651@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:15:35 -0400 Subject: [PATCH 1/2] RDKB-65621: Propagate seek-map clearing across log-upload profiles (#414) * RDKB-65621: Propagate seek-map clearing across log-upload profiles Reason for Change: Fix a race where concurrent profile timeout threads consumed a shared retain-seek flag, causing only one profile to clear its grep seek map after log upload. Store and propagate the clear-seek decision per profile, and update related tests. This ensures all profiles clear their grep seek maps after a log upload, preventing stale seek positions from causing log markers such as Total_5G_clients_split to be missed after log files are truncated or rotated. Test Procedure: Refer the ticket descriptions Risks: Medium Priority: P0 Signed-off-by: Thamim Razith Abbas Ali * Update scheduler mocks and unit tests for the new per-profile --------- Signed-off-by: Thamim Razith Abbas Ali --- source/bulkdata/profile.c | 6 +++--- source/bulkdata/profile.h | 2 +- source/bulkdata/reportprofiles.c | 17 +++++++++++++++-- source/scheduler/scheduler.c | 16 ++++++---------- source/scheduler/scheduler.h | 3 ++- source/test/bulkdata/SchedulerMock.cpp | 4 ++-- source/test/bulkdata/SchedulerMock.h | 2 +- source/test/bulkdata/profileTest.cpp | 14 ++++++++++++-- source/test/scheduler/schedulerTest.cpp | 6 +++--- 9 files changed, 45 insertions(+), 25 deletions(-) diff --git a/source/bulkdata/profile.c b/source/bulkdata/profile.c index 342d7d57..e6de9331 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 181ae940..7bbfaa24 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 c01f1eb0..6c02b0b3 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 daeb0bd8..f6a73710 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 356cf398..a1d6c885 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 0611b642..6c4b77b2 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 ad1c6d30..d4ab47e2 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 f2b43205..f56d05f3 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 53ec7ada..4186c16a 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) From 69e45e00908743d90028bb67ddad22f78d7deb56 Mon Sep 17 00:00:00 2001 From: shibu-kv Date: Thu, 20 Aug 2026 06:42:16 -0700 Subject: [PATCH 2/2] Changelog updates for 1.10.1 release --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 788b5721..8ebdf9b2 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)