| /*=============================================================================# |
| # 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); |
| } |
| } |
| |
| } |