Skip to content

Commit b4810dc

Browse files
authored
Merge pull request #513 from Countly/disable-gradual-cleanup
Init flag disableGradualRequestCleaner
2 parents 7a42160 + 0d65aa4 commit b4810dc

File tree

5 files changed

+112
-2
lines changed

5 files changed

+112
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Added a new config option `setWebviewDisplayOption(WebViewDisplayOption)` to control how Content and Feedback Widgets are displayed.
55
* `IMMERSIVE` mode (default): Full-screen display (except cutouts).
66
* `SAFE_AREA` mode: Omits status bar, navigation bar and cutouts when displaying webviews.
7+
* Added a new init config option `disableGradualRequestCleaner()` to change request queue overflow behavior. When enabled, all overflowing requests (plus one slot) are removed at once instead of being cleaned gradually in limited batches.
78

89
* Immediate requests now will be run by parallel executor instead of serial by default.
910

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package ly.count.android.sdk;
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
import org.junit.runner.RunWith;
7+
8+
import static org.junit.Assert.*;
9+
import static org.mockito.Mockito.mock;
10+
11+
/**
12+
* Tests for the request queue cleaning behavior with and without the gradual cleaner disabled.
13+
*/
14+
@RunWith(AndroidJUnit4.class)
15+
public class CountlyStoreRequestCleanerTests {
16+
CountlyStore store;
17+
18+
@Before
19+
public void setUp() {
20+
store = new CountlyStore(TestUtils.getContext(), mock(ModuleLog.class));
21+
store.clear();
22+
}
23+
24+
private void fillRequests(int count) {
25+
for (int i = 0; i < count; i++) {
26+
store.addRequest("req_" + i, false);
27+
}
28+
}
29+
30+
@Test
31+
public void testDefaultGradualCleanerRemovesUpToLoopLimit() {
32+
store.maxRequestQueueSize = 1000;
33+
fillRequests(200);
34+
assertEquals(200, store.getRequests().length);
35+
36+
// Reduce max to force clean on next add
37+
store.maxRequestQueueSize = 50; // new limit
38+
store.addRequest("req_new_default", false);
39+
40+
// With gradual cleaner: removed Math.min(100, overflow(150)) + 1 = 101 before adding new
41+
// Remaining after removal: 99, after adding new: 100
42+
String[] requests = store.getRequests();
43+
assertEquals(100, requests.length);
44+
// First remaining element should be the original index 101 (req_101)
45+
assertTrue("Expected first retained request to be req_101 but was " + requests[0], requests[0].equals("req_101"));
46+
// Last element should be the newly added one
47+
assertEquals("req_new_default", requests[requests.length - 1]);
48+
}
49+
50+
@Test
51+
public void testDisableGradualRequestCleanerRemovesAllOverflow() {
52+
store.maxRequestQueueSize = 1000;
53+
fillRequests(200);
54+
assertEquals(200, store.getRequests().length);
55+
56+
// Enable new mode
57+
store.setDisableGradualRequestCleaner(true);
58+
59+
// Reduce max to force clean on next add
60+
store.maxRequestQueueSize = 50; // new limit
61+
store.addRequest("req_new_disabled", false);
62+
63+
// With disabled gradual cleaner: removed overflow (150) + 1 = 151 before add
64+
// Remaining after removal: 49, after adding new: 50
65+
String[] requests = store.getRequests();
66+
assertEquals(50, requests.length);
67+
// First remaining element should be original index 151 (req_151)
68+
assertTrue("Expected first retained request to be req_151 but was " + requests[0], requests[0].equals("req_151"));
69+
// Last element should be the newly added one
70+
assertEquals("req_new_disabled", requests[requests.length - 1]);
71+
}
72+
}

sdk/src/main/java/ly/count/android/sdk/Countly.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,11 @@ public synchronized Countly init(CountlyConfig config) {
458458
L.d("[Init] request queue size set to [" + config.maxRequestQueueSize + "]");
459459
countlyStore.setLimits(config.maxRequestQueueSize);
460460

461+
if (config.disableGradualRequestCleaner) {
462+
L.d("[Init] Disabling gradual request queue cleaning. Overflow will be removed in one pass.");
463+
countlyStore.setDisableGradualRequestCleaner(true);
464+
}
465+
461466
if (config.storageProvider == null) {
462467
// outside of tests this should be null
463468
config.storageProvider = config.countlyStore;

sdk/src/main/java/ly/count/android/sdk/CountlyConfig.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ public class CountlyConfig {
210210
boolean useSerialExecutor = false;
211211
WebViewDisplayOption webViewDisplayOption = WebViewDisplayOption.IMMERSIVE;
212212

213+
// If set to true, request queue cleaner will remove all overflow at once instead of gradually (loop limited) removing
214+
boolean disableGradualRequestCleaner = false;
215+
213216
/**
214217
* THIS VARIABLE SHOULD NOT BE USED
215218
* IT IS ONLY FOR INTERNAL TESTING
@@ -1083,6 +1086,20 @@ public synchronized CountlyConfig setUseSerialExecutor(boolean useSerial) {
10831086
return this;
10841087
}
10851088

1089+
/**
1090+
* Disable the gradual request cleaner. By default when the request queue exceeds the configured
1091+
* maximum size, only a limited number of the oldest requests are removed per cleanup cycle
1092+
* (capped by an internal loop limit of 100) to gradually shrink the queue. Calling this method changes
1093+
* the behavior so that whenever the queue exceeds the maximum size, all overflowing requests
1094+
* (plus one extra slot for the new request) are removed in a single operation.
1095+
*
1096+
* @return Returns the same config object for convenient linking
1097+
*/
1098+
public synchronized CountlyConfig disableGradualRequestCleaner() {
1099+
this.disableGradualRequestCleaner = true;
1100+
return this;
1101+
}
1102+
10861103
/**
10871104
* APM configuration interface to be used with CountlyConfig
10881105
*/

sdk/src/main/java/ly/count/android/sdk/CountlyStore.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public class CountlyStore implements StorageProvider, EventQueueProvider {
8686
int dropAgeHours = 0;
8787
private final static int requestRemovalLoopLimit = 100;
8888

89+
// If true, when cleaning request queue overflow remove all overflowing requests at once (plus one slot)
90+
// instead of gradually removing up to 'requestRemovalLoopLimit'
91+
boolean disableGradualRequestCleaner = false;
92+
8993
//explicit storage fields
9094
boolean explicitStorageModeEnabled;
9195
boolean esDirtyFlag = false;
@@ -497,15 +501,26 @@ synchronized void deleteOldestRequests(List<String> requests) {
497501
return;
498502
}
499503

500-
int requestsToRemove = Math.min(requestRemovalLoopLimit, requests.size() - maxRequestQueueSize) + 1; // +1 because it should open a new place for newcomer
501-
L.i("[CountlyStore] deleteOldestRequests, Will remove the oldest " + requestsToRemove + " request");
504+
int overflow = requests.size() - maxRequestQueueSize;
505+
int requestsToRemove;
506+
if (disableGradualRequestCleaner) {
507+
requestsToRemove = overflow + 1;
508+
L.i("[CountlyStore] deleteOldestRequests, Gradual cleaner disabled. Removing all overflow: " + requestsToRemove + " request");
509+
} else {
510+
requestsToRemove = Math.min(requestRemovalLoopLimit, overflow) + 1; // +1 because it should open a new place for newcomer
511+
L.i("[CountlyStore] deleteOldestRequests, Will remove the oldest " + requestsToRemove + " request");
512+
}
502513
requests.subList(0, requestsToRemove).clear(); // sublist reflects all changes to the main list
503514

504515
if (pcc != null) {
505516
pcc.TrackCounterTimeNs("CountlyStore_deleteOldestRequest", UtilsTime.getNanoTime() - tsStart);
506517
}
507518
}
508519

520+
void setDisableGradualRequestCleaner(boolean disable) {
521+
disableGradualRequestCleaner = disable;
522+
}
523+
509524
synchronized void deleteOldestRequest_reworked() {
510525
long tsStart = 0L;
511526
if (pcc != null) {

0 commit comments

Comments
 (0)