Skip to content

Commit 9b1a5d2

Browse files
author
Sayaan Saha
committed
Added semaphores
1 parent acd80f4 commit 9b1a5d2

File tree

4 files changed

+71
-35
lines changed

4 files changed

+71
-35
lines changed

AndroidSDKCore/src/main/java/com/leanplum/internal/Request.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import java.util.ArrayList;
4646
import java.util.Date;
4747
import java.util.HashMap;
48-
import java.util.LinkedList;
4948
import java.util.List;
5049
import java.util.Map;
5150
import java.util.Stack;
@@ -60,7 +59,7 @@ public class Request {
6059
private static final long DEVELOPMENT_MIN_DELAY_MS = 100;
6160
private static final long DEVELOPMENT_MAX_DELAY_MS = 5000;
6261
private static final long PRODUCTION_DELAY = 60000;
63-
private Waiter waiter;
62+
private RequestSequence requestSequence;
6463
static final int MAX_EVENTS_PER_API_CALL;
6564
static final String LEANPLUM = "__leanplum__";
6665
static final String UUID_KEY = "uuid";
@@ -166,7 +165,7 @@ public static void saveToken() {
166165
SharedPreferencesUtil.commitChanges(editor);
167166
}
168167

169-
private static class NoWaiter implements Waiter {
168+
private static class NoRequestSequence implements RequestSequence {
170169
@Override
171170
public void beforeRead() {
172171
// No op.
@@ -201,10 +200,10 @@ public static String userId() {
201200
}
202201

203202
public Request(String httpMethod, String apiMethod, Map<String, Object> params) {
204-
this(httpMethod, apiMethod, params, new NoWaiter());
203+
this(httpMethod, apiMethod, params, new NoRequestSequence());
205204
}
206205

207-
Request(String httpMethod, String apiMethod, Map<String, Object> params, Waiter waiter) {
206+
Request(String httpMethod, String apiMethod, Map<String, Object> params, RequestSequence requestSequence) {
208207
this.httpMethod = httpMethod;
209208
this.apiMethod = apiMethod;
210209
this.params = params != null ? params : new HashMap<String, Object>();
@@ -215,7 +214,7 @@ public Request(String httpMethod, String apiMethod, Map<String, Object> params)
215214
// Make sure the Handler is initialized on the main thread.
216215
OsHandler.getInstance();
217216
dataBaseIndex = -1;
218-
this.waiter = waiter;
217+
this.requestSequence = requestSequence;
219218
}
220219

221220
public static Request get(String apiMethod, Map<String, Object> params) {
@@ -261,7 +260,8 @@ private Map<String, Object> createArgsDictionary() {
261260

262261
private void saveRequestForLater(Map<String, Object> args) {
263262
try {
264-
waiter.beforeWrite();
263+
requestSequence.beforeWrite();
264+
265265
synchronized (Request.class) {
266266
Context context = Leanplum.getContext();
267267
SharedPreferences preferences = context.getSharedPreferences(
@@ -284,7 +284,7 @@ private void saveRequestForLater(Map<String, Object> args) {
284284
if (response != null || error != null && !Util.isConnected()) {
285285
eventCallbackManager.addCallbacks(this, response, error);
286286
}
287-
waiter.afterWrite();
287+
requestSequence.afterWrite();
288288
}
289289
} catch (Throwable t) {
290290
Util.handleException(t);
@@ -580,7 +580,7 @@ private RequestsWithEncoding getRequestsWithEncodedString() {
580580
}
581581

582582
private void sendRequests() {
583-
waiter.beforeRead();
583+
requestSequence.beforeRead();
584584
RequestsWithEncoding requestsWithEncoding = getRequestsWithEncodedString();
585585

586586
List<Map<String, Object>> unsentRequests = requestsWithEncoding.unsentRequests;
@@ -647,7 +647,7 @@ private void sendRequests() {
647647
parseResponseBody(responseBody, requestsToSend, errorException, unsentRequests.size());
648648
}
649649
}
650-
waiter.afterRead();
650+
requestSequence.afterRead();
651651
} catch (JSONException e) {
652652
Log.e("Error parsing JSON response: " + e.toString() + "\n" + Log.getStackTraceString(e));
653653
deleteSentRequests(unsentRequests.size());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.leanplum.internal;
2+
3+
/**
4+
* Public interface for during the call sequence of database
5+
* read/write operations.
6+
*
7+
* @author sayaan
8+
*/
9+
10+
public interface RequestSequence {
11+
void beforeRead();
12+
13+
void afterRead();
14+
15+
void beforeWrite();
16+
17+
void afterWrite();
18+
}

AndroidSDKCore/src/main/java/com/leanplum/internal/Waiter.java

Lines changed: 0 additions & 15 deletions
This file was deleted.

AndroidSDKTests/src/test/java/com/leanplum/internal/RequestTest.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.util.HashMap;
4343
import java.util.List;
4444
import java.util.Map;
45+
import java.util.concurrent.Semaphore;
4546

4647
import static org.mockito.AdditionalMatchers.not;
4748
import static org.mockito.Matchers.eq;
@@ -58,6 +59,7 @@
5859
)
5960
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "org.json.*", "org.powermock.*"})
6061
public class RequestTest extends TestCase {
62+
public final String POST = "POST";
6163
/**
6264
* Runs before every test case.
6365
*/
@@ -72,14 +74,22 @@ public void setUp() {
7274
* Test that read writes happened sequentially when calling sendNow().
7375
*/
7476
@Test
75-
public void testSequenceOfDatabaseOperations() {
77+
public void shouldWriteRequestAndSendInSequence() {
78+
// Given a request.
7679
Map<String, Object> params = new HashMap<>();
7780
params.put("data1", "value1");
7881
params.put("data2", "value2");
79-
ThreadWaiter waiter = new ThreadWaiter();
80-
Request request = new Request("POST", Constants.Methods.START, params, waiter);
82+
ThreadRequestSequence waiter = new ThreadRequestSequence();
83+
Request request = new Request(POST, Constants.Methods.START, params, waiter);
8184
request.setAppId("fskadfshdbfa", "wee5w4waer422323");
85+
86+
//block the write
87+
waiter.setBlockWrite(true);
88+
89+
// When the request is sent.
8290
request.sendIfConnected();
91+
92+
// When the request is sent.
8393
waiter.assertCallSequence();
8494
}
8595
/**
@@ -338,30 +348,53 @@ private List<Map<String, Object>> mockRequests(int requestSize) {
338348
return requests;
339349
}
340350

341-
private static class ThreadWaiter implements Waiter {
342-
Instant t1, t2, t3, t4;
351+
private static class ThreadRequestSequence implements RequestSequence {
352+
Instant beforeReadTime, afterReadTime, beforeWriteTime, afterWriteTime;
353+
final Semaphore semaphore = new Semaphore(1);
354+
private boolean blockWrite = false;
355+
343356
@Override
344357
public void beforeRead() {
345-
t1 = Instant.now();
358+
try {
359+
semaphore.tryAcquire();
360+
beforeReadTime = Instant.now();
361+
} finally {
362+
semaphore.release();
363+
}
346364
}
347365

348366
@Override
349367
public void afterRead() {
350-
t2 = Instant.now();
368+
afterReadTime = Instant.now();
351369
}
352370

353371
@Override
354372
public void beforeWrite() {
355-
t3 = Instant.now();
373+
// since we are blocking on main thread
374+
if (blockWrite) {
375+
try {
376+
semaphore.tryAcquire();
377+
Thread.sleep(2000);
378+
} catch (InterruptedException e) {
379+
e.printStackTrace();
380+
} finally {
381+
semaphore.release();
382+
}
383+
}
384+
beforeWriteTime = Instant.now();
356385
}
357386

358387
@Override
359388
public void afterWrite() {
360-
t4 = Instant.now();
389+
afterWriteTime = Instant.now();
390+
}
391+
392+
public void setBlockWrite(boolean value) {
393+
this.blockWrite = value;
361394
}
362395

363396
public void assertCallSequence() {
364-
assertTrue(t4.isBefore(t1));
397+
assertTrue(afterWriteTime.isBefore(beforeReadTime));
365398
}
366399
}
367400
}

0 commit comments

Comments
 (0)