Skip to content

Commit 561eef6

Browse files
Merge pull request #201 from backtrace-labs/backtrace-db-context-batch-fix
Fix Backtrace Database Context retry mechanism
2 parents ddf396f + a4edc98 commit 561eef6

3 files changed

Lines changed: 76 additions & 29 deletions

File tree

backtrace-library/src/androidTest/java/backtraceio/library/database/BacktraceDatabaseContextTest.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ public class BacktraceDatabaseContextTest {
3333
private BacktraceDatabaseSettings databaseSettings;
3434
private final String testMessage = "Example test string";
3535

36+
private final int RETRY_LIMIT = 5;
37+
3638
@Before
3739
public void setUp() {
3840
this.context = InstrumentationRegistry.getInstrumentation().getContext();
3941
this.dbPath = this.context.getFilesDir().getAbsolutePath();
4042
this.databaseSettings = new BacktraceDatabaseSettings(this.dbPath, RetryOrder.Queue);
43+
this.databaseSettings.setRetryLimit(RETRY_LIMIT);
4144
this.databaseContext = new BacktraceDatabaseContext(this.databaseSettings);
4245
}
4346
@After
@@ -254,17 +257,40 @@ public void tryAddNullBacktraceDbRecord() {
254257
databaseContext.add((BacktraceDatabaseRecord) null);
255258
}
256259

260+
@Test
261+
public void testIncrementBatchRetry() {
262+
// GIVEN
263+
int numberOfRetries = 0;
264+
fillDatabase(10);
265+
266+
// WHEN
267+
268+
for (int i = 0; i < 10; i++) {
269+
BacktraceDatabaseRecord first = databaseContext.first(); // QUEUE
270+
if (first == null) {
271+
break;
272+
}
273+
first.close();
274+
this.databaseContext.incrementBatchRetry();
275+
numberOfRetries++;
276+
}
277+
278+
// THEN
279+
assertEquals(0, databaseContext.count());
280+
assertEquals(RETRY_LIMIT, numberOfRetries);
281+
}
282+
257283
private List<BacktraceDatabaseRecord> fillDatabase() {
284+
return this.fillDatabase(3);
285+
}
286+
private List<BacktraceDatabaseRecord> fillDatabase(int numberOfReports) {
258287
List<BacktraceDatabaseRecord> result = new ArrayList<>();
259-
BacktraceReport report = new BacktraceReport(this.testMessage);
260-
BacktraceReport report2 = new BacktraceReport(this.testMessage);
261-
BacktraceReport report3 = new BacktraceReport(this.testMessage);
262-
BacktraceData data = new BacktraceData.Builder(report).setAttributes(this.context, null).build();
263-
BacktraceData data2 = new BacktraceData.Builder(report2).setAttributes(this.context, null).build();
264-
BacktraceData data3 = new BacktraceData.Builder(report3).setAttributes(this.context, null).build();
265-
result.add(databaseContext.add(data));
266-
result.add(databaseContext.add(data2));
267-
result.add(databaseContext.add(data3));
288+
289+
for (int i = 0; i < numberOfReports; i++) {
290+
BacktraceReport report = new BacktraceReport(testMessage);
291+
BacktraceData data = new BacktraceData.Builder(report).setAttributes(this.context, null).build();
292+
result.add(databaseContext.add(data));
293+
}
268294

269295
// Dispose all records
270296
for (BacktraceDatabaseRecord record : result) {
@@ -273,4 +299,4 @@ private List<BacktraceDatabaseRecord> fillDatabase() {
273299

274300
return result;
275301
}
276-
}
302+
}

backtrace-library/src/main/java/backtraceio/library/BacktraceDatabase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public void onEvent(BacktraceResult backtraceResult) {
316316
} else {
317317
BacktraceLogger.d(LOG_TAG, "Backtrace DB Timer - closing record");
318318
currentRecord.close();
319-
// backtraceDatabaseContext.incrementBatchRetry(); TODO: consider another way to remove some records after few retries
319+
backtraceDatabaseContext.incrementBatchRetry(); // If we are not able to send single record we are moving all reports to next batch
320320
}
321321
threadWaiter.countDown();
322322
}

backtrace-library/src/main/java/backtraceio/library/services/BacktraceDatabaseContext.java

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,15 @@ public class BacktraceDatabaseContext implements DatabaseContext {
5656

5757
/**
5858
* @deprecated This constructor will be removed in future versions.
59-
* The {@code context} parameter is no longer used.
60-
* Please use the constructor without the {@code context} parameter.
59+
* The {@code context} parameter is no longer used.
60+
* Please use the constructor without the {@code context} parameter.
6161
*
62-
* <p>Use {@link #BacktraceDatabaseContext(BacktraceDatabaseSettings)} instead.</p>
62+
* <p>
63+
* Use {@link #BacktraceDatabaseContext(BacktraceDatabaseSettings)}
64+
* instead.
65+
* </p>
6366
*
64-
* @param context The unused Android context parameter.
67+
* @param context The unused Android context parameter.
6568
* @param settings The database settings.
6669
*/
6770
@Deprecated
@@ -145,7 +148,8 @@ public BacktraceDatabaseRecord add(BacktraceDatabaseRecord backtraceDatabaseReco
145148
}
146149

147150
/**
148-
* Get first existing database record. Method returns record based on order in database
151+
* Get first existing database record. Method returns record based on order in
152+
* database
149153
*
150154
* @return first Backtrace database record
151155
*/
@@ -156,15 +160,15 @@ public BacktraceDatabaseRecord first() {
156160
}
157161

158162
/**
159-
* Get last existing database record. Method returns record based on order in database
163+
* Get last existing database record. Method returns record based on order in
164+
* database
160165
*
161166
* @return last Backtrace database record
162167
*/
163168
public BacktraceDatabaseRecord last() {
164169
return this.retryOrder == RetryOrder.Queue ? getLastRecord() : getFirstRecord();
165170
}
166171

167-
168172
/**
169173
* Get all database records
170174
*
@@ -187,7 +191,6 @@ public long getDatabaseSize() {
187191
return this.totalSize.get();
188192
}
189193

190-
191194
/**
192195
* Delete existing record from database
193196
*
@@ -241,7 +244,7 @@ public boolean contains(BacktraceDatabaseRecord record) {
241244
Queue<BacktraceDatabaseRecord> records = entry.getValue();
242245

243246
for (BacktraceDatabaseRecord databaseRecord : records) {
244-
if (databaseRecord != null && databaseRecord.id == record.id) {
247+
if (databaseRecord != null && databaseRecord.id.equals(record.id)) {
245248
return true;
246249
}
247250
}
@@ -288,7 +291,7 @@ public void clear() {
288291
}
289292
}
290293

291-
/**
294+
/**
292295
* Delete the oldest file
293296
*
294297
* @return is deletion was successful
@@ -308,26 +311,44 @@ public boolean removeOldestRecord() {
308311
* Increment each batch
309312
*/
310313
private void incrementBatches() {
314+
// Move batches forward: batch i -> batch i+1
315+
// Iterate in reverse to avoid overwriting data before moving it
311316
for (int i = this._retryNumber - 2; i >= 0; i--) {
312317
Queue<BacktraceDatabaseRecord> currentBatch = this.batchRetry.get(i);
313-
batchRetry.put(i, new ConcurrentLinkedQueue<>());
314-
batchRetry.put(i + 1, currentBatch);
318+
319+
// Ensure we have a valid queue (shouldn't be null, but handle it safely)
320+
if (currentBatch == null) {
321+
currentBatch = new ConcurrentLinkedQueue<>();
322+
}
323+
324+
// Store reference to the batch we're moving
325+
Queue<BacktraceDatabaseRecord> batchToMove = currentBatch;
326+
327+
// Clear batch at position i and replace with new empty queue
328+
this.batchRetry.put(i, new ConcurrentLinkedQueue<>());
329+
330+
// Move the batch to the next position (overwriting whatever was there)
331+
this.batchRetry.put(i + 1, batchToMove);
315332
}
316333
}
317334

318335
/**
319336
* Remove last batch
320337
*/
321338
private void removeMaxRetries() {
322-
Queue<BacktraceDatabaseRecord> currentBatch = this.batchRetry.get(_retryNumber - 1);
339+
Queue<BacktraceDatabaseRecord> currentBatch = this.batchRetry.put(_retryNumber - 1, new ConcurrentLinkedQueue<>());
340+
341+
if (currentBatch == null) {
342+
this.batchRetry.put(_retryNumber - 1, new ConcurrentLinkedQueue<>());
343+
return;
344+
}
323345

324346
for (BacktraceDatabaseRecord record : currentBatch) {
325-
if (!record.valid()) {
326-
continue;
347+
if (record.valid()) {
348+
record.delete();
349+
this.totalRecords.decrementAndGet();
350+
totalSize.addAndGet(-record.getSize());
327351
}
328-
record.delete();
329-
this.totalRecords.decrementAndGet();
330-
totalSize.addAndGet(-record.getSize());
331352
}
332353
}
333354

0 commit comments

Comments
 (0)