blob: 8ae881a4f1ef8171e76c1a0bb8d18f441814e5db [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2019, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.services.util.dataaccess;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import java.util.PrimitiveIterator.OfLong;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.status.NullProgressMonitor;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Updater;
@NonNullByDefault
public class LazyRStoreTest {
private static final int RANDOM_SEED= 68432;
private static String toKey(final String prefix, final long rowIdx, final long colIdx) {
return prefix + '-' + rowIdx + ',' + colIdx;
}
private static class TestElement {
private final String prefix;
private final Fragment<?> fragment;
public TestElement(final String prefix, final Fragment<?> fragment) {
this.prefix= prefix;
this.fragment= fragment;
}
public String get(final long row, final long col) {
if (row < 0 || row > this.fragment.getRowCount()
|| col < 0 || col > this.fragment.getColumnCount() ) {
throw new IllegalArgumentException();
}
return toKey(this.prefix,
(this.fragment.getRowBeginIdx() + row),
(this.fragment.getColumnBeginIdx() + col) );
}
}
private LazyRStore<TestElement> store;
@SuppressWarnings("null")
public LazyRStoreTest() {
}
@Test
public void get_directUpdate_scrollRows() {
final long rowCount= 2000000;
final long colCount= 100000;
final AtomicReference<@Nullable String> prefix= new AtomicReference<>();
this.store= new LazyRStore<>(rowCount, colCount, 10, directUpdater(prefix));
final ProgressMonitor m= new NullProgressMonitor();
prefix.set("A");
for (long colIdx= 0; colIdx < colCount; colIdx+= 33333) {
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 20) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long rowIdx= rowCount - 1; rowIdx >= 0; rowIdx-= 20) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long rowIdx= rowCount - 1; rowIdx >= 0; rowIdx-= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
}
}
@Test
public void get_directUpdate_scrollCols() {
final long rowCount= 100000;
final long colCount= 2000000;
final AtomicReference<@Nullable String> prefix= new AtomicReference<>();
this.store= new LazyRStore<>(rowCount, colCount, 10, directUpdater(prefix));
final ProgressMonitor m= new NullProgressMonitor();
prefix.set("A");
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 33333) {
for (long colIdx= 0; colIdx < colCount; colIdx+= 20) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long colIdx= 0; colIdx < colCount; colIdx+= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long colIdx= colCount - 1; colIdx >= 0; colIdx-= 20) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long colIdx= colCount - 1; colIdx >= 0; colIdx-= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
for (long colIdx= 0; colIdx < colCount; colIdx+= 1000) {
assertFragment(rowIdx, colIdx, "A", m);
}
}
}
@Test
public void get_directUpdate_random() {
final int rowCount= 2000000;
final int colCount= 2000000;
final AtomicReference<@Nullable String> prefix= new AtomicReference<>();
this.store= new LazyRStore<>(rowCount, colCount, 10, directUpdater(prefix));
final ProgressMonitor m= new NullProgressMonitor();
final Random rand= new Random(RANDOM_SEED);
prefix.set("A");
for (int i= 0; i < 100000; i++) {
assertFragment(rand.nextInt(rowCount), rand.nextInt(colCount), "A", m);
}
}
@Test
public void get_directUpdate_randomLong() {
final long rowCount= 200000000000L;
final long colCount= 20000000000L;
final AtomicReference<@Nullable String> prefix= new AtomicReference<>();
this.store= new LazyRStore<>(rowCount, colCount, 10, directUpdater(prefix));
final ProgressMonitor m= new NullProgressMonitor();
final Random rand= new Random(RANDOM_SEED);
final OfLong rows= rand.longs(0, rowCount).iterator();
final OfLong cols= rand.longs(0, colCount).iterator();
prefix.set("A");
for (int i= 0; i < 100000; i++) {
assertFragment(rows.nextLong(), cols.nextLong(), "A", m);
}
}
@Test
public void get_noUpdate_scrollRows() {
final long rowCount= 2000000;
final long colCount= 100000;
this.store= new LazyRStore<>(rowCount, colCount, 10, noUpdater());
final ProgressMonitor m= new NullProgressMonitor();
for (long colIdx= 0; colIdx < colCount; colIdx+= 33333) {
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 20) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long rowIdx= rowCount - 1; rowIdx >= 0; rowIdx-= 20) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long rowIdx= rowCount - 1; rowIdx >= 0; rowIdx-= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
}
}
@Test
public void get_noUpdate_scrollCols() {
final long rowCount= 100000;
final long colCount= 2000000;
this.store= new LazyRStore<>(rowCount, colCount, 10, noUpdater());
final ProgressMonitor m= new NullProgressMonitor();
for (long rowIdx= 0; rowIdx < rowCount; rowIdx+= 33333) {
for (long colIdx= 0; colIdx < colCount; colIdx+= 20) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long colIdx= 0; colIdx < colCount; colIdx+= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long colIdx= colCount - 1; colIdx >= 0; colIdx-= 20) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long colIdx= colCount - 1; colIdx >= 0; colIdx-= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
for (long colIdx= 0; colIdx < colCount; colIdx+= 1000) {
assertFragment(rowIdx, colIdx, null, m);
}
}
}
@Test
public void get_noUpdate_random() {
final int rowCount= 2000000;
final int colCount= 2000000;
this.store= new LazyRStore<>(rowCount, colCount, 10, noUpdater());
final ProgressMonitor m= new NullProgressMonitor();
final Random rand= new Random(RANDOM_SEED);
for (int i= 0; i < 100000; i++) {
assertFragment(rand.nextInt(rowCount), rand.nextInt(colCount), null, m);
}
}
@Test
public void get_noUpdate_randomLong() {
final long rowCount= 200000000000L;
final long colCount= 20000000000L;
this.store= new LazyRStore<>(rowCount, colCount, 10, noUpdater());
final ProgressMonitor m= new NullProgressMonitor();
final Random rand= new Random(RANDOM_SEED);
final OfLong rows= rand.longs(0, rowCount).iterator();
final OfLong cols= rand.longs(0, colCount).iterator();
for (int i= 0; i < 100000; i++) {
assertFragment(rows.nextLong(), cols.nextLong(), null, m);
}
}
@Test
public void get_ensureCached() {
final long rowCount= 100000;
final long colCount= 2000000;
final AtomicReference<@Nullable String> prefix= new AtomicReference<>();
this.store= new LazyRStore<>(rowCount, colCount, 10, directUpdater(prefix));
final ProgressMonitor m= new NullProgressMonitor();
prefix.set("A");
assertFragment(10, 200, "A", m);
prefix.set("B");
for (int i= 0; i < 9; i++) {
assertFragment(10000, i * 10000, "B", m);
}
assertFragment(10, 200, "A", m);
}
private Updater<TestElement> directUpdater(final AtomicReference<@Nullable String> prefix) {
return new LazyRStore.Updater<LazyRStoreTest.TestElement>() {
@Override
public void scheduleUpdate(final LazyRStore<TestElement> store,
final @Nullable RDataAssignment assignment, final @Nullable Fragment<TestElement> fragment,
final int flags, final ProgressMonitor m) {
if (fragment != null) {
store.updateFragment(fragment,
new TestElement(nonNullAssert(prefix.get()), fragment) );
}
}
};
}
private Updater<TestElement> noUpdater() {
return new LazyRStore.Updater<LazyRStoreTest.TestElement>() {
@Override
public void scheduleUpdate(final LazyRStore<TestElement> store,
final @Nullable RDataAssignment assignment, final @Nullable Fragment<TestElement> fragment,
final int flags, final ProgressMonitor m) {
}
};
}
private void assertFragment(final long rowIdx, final long colIdx,
final @Nullable String expectedPrefix,
final ProgressMonitor m) {
final String id= String.format("[%1$s,%2$s]", rowIdx, colIdx);
try {
final Fragment<TestElement> fragment= this.store.getFragment(rowIdx, colIdx, 0, m);
if (expectedPrefix != null) {
assertNotNull(id, fragment);
final TestElement rObject= fragment.getRObject();
assertNotNull(id, rObject);
assertEquals(toKey(expectedPrefix, rowIdx, colIdx),
rObject.get(fragment.toLocalRowIdx(rowIdx), fragment.toLocalColumnIdx(colIdx)) );
}
else {
assertNull(id, fragment);
}
}
catch (final RuntimeException e) {
throw new RuntimeException(id, e);
}
}
}