Fix race conditions on SQLiteScoreList

pull/309/head
Alinson S. Xavier 8 years ago
parent e06ace9ea8
commit fe1513bb64

@ -67,6 +67,8 @@ public class BaseAndroidTest
protected ModelFactory modelFactory; protected ModelFactory modelFactory;
private boolean isDone = false;
@Before @Before
public void setUp() public void setUp()
{ {
@ -117,6 +119,25 @@ public class BaseAndroidTest
assertTrue(latch.await(60, TimeUnit.SECONDS)); assertTrue(latch.await(60, TimeUnit.SECONDS));
} }
protected void runConcurrently(Runnable... runnableList) throws Exception
{
isDone = false;
ExecutorService executor = Executors.newFixedThreadPool(100);
List<Future> futures = new LinkedList<>();
for (Runnable r : runnableList)
futures.add(executor.submit(() ->
{
while (!isDone) r.run();
return null;
}));
Thread.sleep(3000);
isDone = true;
executor.shutdown();
for(Future f : futures) f.get();
while (!executor.isTerminated()) Thread.sleep(50);
}
protected void setTheme(@StyleRes int themeId) protected void setTheme(@StyleRes int themeId)
{ {
targetContext.setTheme(themeId); targetContext.setTheme(themeId);

@ -61,29 +61,6 @@ public class SQLiteScoreListTest extends BaseAndroidTest
day = DateUtils.millisecondsInOneDay; day = DateUtils.millisecondsInOneDay;
} }
@Test
public void testGetAll()
{
List<Score> list = scores.toList();
assertThat(list.size(), equalTo(121));
assertThat(list.get(0).getTimestamp(), equalTo(today));
assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day));
}
@Test
public void testInvalidateNewerThan()
{
scores.getTodayValue(); // force recompute
List<ScoreRecord> records = getAllRecords();
assertThat(records.size(), equalTo(121));
scores.invalidateNewerThan(today - 10 * day);
records = getAllRecords();
assertThat(records.size(), equalTo(110));
assertThat(records.get(0).timestamp, equalTo(today - 11 * day));
}
@Test @Test
public void testAdd() public void testAdd()
{ {
@ -101,6 +78,15 @@ public class SQLiteScoreListTest extends BaseAndroidTest
assertThat(records.get(0).timestamp, equalTo(today)); assertThat(records.get(0).timestamp, equalTo(today));
} }
@Test
public void testGetAll()
{
List<Score> list = scores.toList();
assertThat(list.size(), equalTo(121));
assertThat(list.get(0).getTimestamp(), equalTo(today));
assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day));
}
@Test @Test
public void testGetByInterval() public void testGetByInterval()
{ {
@ -115,6 +101,16 @@ public class SQLiteScoreListTest extends BaseAndroidTest
assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day)); assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day));
} }
@Test
public void testGetByInterval_concurrent() throws Exception
{
Runnable block1 = () -> scores.invalidateNewerThan(0);
Runnable block2 =
() -> assertThat(scores.getByInterval(today, today).size(),
equalTo(1));
runConcurrently(block1, block2);
}
@Test @Test
public void testGetByInterval_withLongInterval() public void testGetByInterval_withLongInterval()
{ {
@ -125,6 +121,30 @@ public class SQLiteScoreListTest extends BaseAndroidTest
assertThat(list.size(), equalTo(201)); assertThat(list.size(), equalTo(201));
} }
@Test
public void testGetTodayValue_concurrent() throws Exception
{
Runnable block1 = () -> scores.invalidateNewerThan(0);
Runnable block2 =
() -> assertThat(scores.getTodayValue(), equalTo(18407827));
runConcurrently(block1, block2);
}
@Test
public void testInvalidateNewerThan()
{
scores.getTodayValue(); // force recompute
List<ScoreRecord> records = getAllRecords();
assertThat(records.size(), equalTo(121));
scores.invalidateNewerThan(today - 10 * day);
records = getAllRecords();
assertThat(records.size(), equalTo(110));
assertThat(records.get(0).timestamp, equalTo(today - 11 * day));
}
private List<ScoreRecord> getAllRecords() private List<ScoreRecord> getAllRecords()
{ {
return new Select() return new Select()

@ -81,7 +81,7 @@ public abstract class ScoreList implements Iterable<Score>
* @param timestamp the timestamp of a day * @param timestamp the timestamp of a day
* @return score value for that day * @return score value for that day
*/ */
public final synchronized int getValue(long timestamp) public synchronized final int getValue(long timestamp)
{ {
compute(timestamp, timestamp); compute(timestamp, timestamp);
Score s = getComputedByTimestamp(timestamp); Score s = getComputedByTimestamp(timestamp);

@ -100,7 +100,8 @@ public class SQLiteScoreList extends ScoreList
@NonNull @NonNull
@Override @Override
public List<Score> getByInterval(long fromTimestamp, long toTimestamp) public synchronized List<Score> getByInterval(long fromTimestamp,
long toTimestamp)
{ {
check(habit.getId()); check(habit.getId());
compute(fromTimestamp, toTimestamp); compute(fromTimestamp, toTimestamp);
@ -137,7 +138,7 @@ public class SQLiteScoreList extends ScoreList
} }
@Override @Override
public int getTodayValue() public synchronized int getTodayValue()
{ {
if (cache == null || cache.expired()) if (cache == null || cache.expired())
cache = new CachedData(super.getTodayValue()); cache = new CachedData(super.getTodayValue());
@ -146,7 +147,7 @@ public class SQLiteScoreList extends ScoreList
} }
@Override @Override
public void invalidateNewerThan(long timestamp) public synchronized void invalidateNewerThan(long timestamp)
{ {
cache = null; cache = null;
invalidateStatement.bindLong(1, habit.getId()); invalidateStatement.bindLong(1, habit.getId());

Loading…
Cancel
Save