Fix paging issue where DataStatus was not updated on insert.

fork-5.53.8
Greyson Parrelli 2022-03-11 14:27:15 -05:00 zatwierdzone przez Cody Henthorne
rodzic 54eb579558
commit e7a370a549
3 zmienionych plików z 125 dodań i 31 usunięć

Wyświetl plik

@ -13,7 +13,8 @@ class DataStatus {
private static final Pools.Pool<BitSet> POOL = new Pools.SynchronizedPool<>(1);
private final BitSet state;
private final int size;
private int size;
public static DataStatus obtain(int size) {
BitSet bitset = POOL.acquire();
@ -31,6 +32,10 @@ class DataStatus {
this.state = bitset;
}
void mark(int position) {
state.set(position, true);
}
void markRange(int startInclusive, int endExclusive) {
state.set(startInclusive, endExclusive, true);
}
@ -53,6 +58,24 @@ class DataStatus {
return -1;
}
boolean get(int position) {
return state.get(position);
}
void insertState(int position, boolean value) {
if (position < 0 || position > size + 1) {
throw new IndexOutOfBoundsException();
}
for (int i = size; i > position; i--) {
state.set(i, state.get(i - 1));
}
state.set(position, value);
this.size = size + 1;
}
int size() {
return size;
}

Wyświetl plik

@ -62,38 +62,43 @@ class FixedSizePagingController<Key, Data> implements PagingController<Key> {
return;
}
if (loadState.size() == 0) {
liveData.postValue(Collections.emptyList());
return;
final int loadStart;
final int loadEnd;
synchronized (loadState) {
if (loadState.size() == 0) {
liveData.postValue(Collections.emptyList());
return;
}
int leftPageBoundary = (aroundIndex / config.pageSize()) * config.pageSize();
int rightPageBoundary = leftPageBoundary + config.pageSize();
int buffer = config.bufferPages() * config.pageSize();
int leftLoadBoundary = Math.max(0, leftPageBoundary - buffer);
int rightLoadBoundary = Math.min(loadState.size(), rightPageBoundary + buffer);
loadStart = loadState.getEarliestUnmarkedIndexInRange(leftLoadBoundary, rightLoadBoundary);
if (loadStart < 0) {
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "loadStart < 0"));
return;
}
loadEnd = loadState.getLatestUnmarkedIndexInRange(Math.max(leftLoadBoundary, loadStart), rightLoadBoundary) + 1;
if (loadEnd <= loadStart) {
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "loadEnd <= loadStart, loadEnd: " + loadEnd + ", loadStart: " + loadStart));
return;
}
int totalSize = loadState.size();
loadState.markRange(loadStart, loadEnd);
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "start: " + loadStart + ", end: " + loadEnd + ", totalSize: " + totalSize));
}
int leftPageBoundary = (aroundIndex / config.pageSize()) * config.pageSize();
int rightPageBoundary = leftPageBoundary + config.pageSize();
int buffer = config.bufferPages() * config.pageSize();
int leftLoadBoundary = Math.max(0, leftPageBoundary - buffer);
int rightLoadBoundary = Math.min(loadState.size(), rightPageBoundary + buffer);
int loadStart = loadState.getEarliestUnmarkedIndexInRange(leftLoadBoundary, rightLoadBoundary);
if (loadStart < 0) {
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "loadStart < 0"));
return;
}
int loadEnd = loadState.getLatestUnmarkedIndexInRange(Math.max(leftLoadBoundary, loadStart), rightLoadBoundary) + 1;
if (loadEnd <= loadStart) {
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "loadEnd <= loadStart, loadEnd: " + loadEnd + ", loadStart: " + loadStart));
return;
}
int totalSize = loadState.size();
loadState.markRange(loadStart, loadEnd);
if (DEBUG) Log.i(TAG, buildLog(aroundIndex, "start: " + loadStart + ", end: " + loadEnd + ", totalSize: " + totalSize));
FETCH_EXECUTOR.execute(() -> {
if (invalidated) {
Log.w(TAG, buildLog(aroundIndex, "Invalidated! At beginning of load task."));
@ -147,6 +152,10 @@ class FixedSizePagingController<Key, Data> implements PagingController<Key> {
return;
}
synchronized (loadState) {
loadState.mark(position);
}
Data item = dataSource.load(key);
if (item == null) {
@ -180,6 +189,10 @@ class FixedSizePagingController<Key, Data> implements PagingController<Key> {
return;
}
synchronized (loadState) {
loadState.insertState(position, true);
}
Data item = dataSource.load(key);
if (item == null) {

Wyświetl plik

@ -0,0 +1,58 @@
package org.signal.paging;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class DataStatusTest {
@Test
public void insertState_initiallyEmpty_InsertAtZero() {
DataStatus subject = DataStatus.obtain(0);
subject.insertState(0, true);
assertEquals(1, subject.size());
assertTrue(subject.get(0));
}
@Test
public void insertState_someData_InsertAtZero() {
DataStatus subject = DataStatus.obtain(2);
subject.mark(1);
subject.insertState(0, true);
assertEquals(3, subject.size());
assertTrue(subject.get(0));
assertFalse(subject.get(1));
assertTrue(subject.get(2));
}
@Test
public void insertState_someData_InsertAtOne() {
DataStatus subject = DataStatus.obtain(3);
subject.mark(1);
subject.insertState(1, true);
assertEquals(4, subject.size());
assertFalse(subject.get(0));
assertTrue(subject.get(1));
assertTrue(subject.get(2));
assertFalse(subject.get(3));
}
@Test(expected = IndexOutOfBoundsException.class)
public void insertState_negativeThrows() {
DataStatus subject = DataStatus.obtain(0);
subject.insertState(-1, true);
}
@Test(expected = IndexOutOfBoundsException.class)
public void insertState_largerThanSizePlusOneThrows() {
DataStatus subject = DataStatus.obtain(0);
subject.insertState(2, true);
}
}