Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IGNITE-22776 : SQL table statistic is updated only once. #11448

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1ba83f5
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev May 23, 2024
803c190
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev May 24, 2024
4b55d31
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev Jun 5, 2024
b5077d1
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev Jun 6, 2024
7c86431
Merge remote-tracking branch 'refs/remotes/apache/master' into ignite…
NSAmelchev Jun 6, 2024
8b88ea9
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev Jun 6, 2024
e461ba4
IGNITE-22319 Node crashes if a snapshot restore cancelled due to netw…
NSAmelchev Jun 6, 2024
6dbebea
Review fixes
NSAmelchev Jun 10, 2024
4df1317
Review fixes
NSAmelchev Jun 10, 2024
b877084
Review fixes
NSAmelchev Jun 10, 2024
72678c6
Review fixes
NSAmelchev Jun 11, 2024
38b3739
Merge remote-tracking branch 'refs/remotes/apache/master' into ignite…
NSAmelchev Jul 4, 2024
1b01fae
wip
NSAmelchev Jul 11, 2024
66964b3
Merge remote-tracking branch 'refs/remotes/apache/master' into ignite…
NSAmelchev Jul 11, 2024
53bde1d
wip
NSAmelchev Jul 11, 2024
ccef631
test
Vladsz83 Jul 19, 2024
0f04df8
Merge branch 'master' into MissingStatistics
Vladsz83 Jul 19, 2024
447a15c
clients and sql cmds research
Vladsz83 Jul 19, 2024
9d0a18c
+ tests
Vladsz83 Jul 19, 2024
4a386a9
+ delete
Vladsz83 Jul 22, 2024
f63b92b
Merge branch 'master' into IGNITE-22776-stats_updating
Vladsz83 Jul 22, 2024
90b9a98
+ master. Test fix
Vladsz83 Jul 23, 2024
155223e
review fixes
NSAmelchev Jul 23, 2024
474aed9
Merge branch 'master' into ignite-22319
Vladsz83 Jul 24, 2024
4117e2e
review fixes
NSAmelchev Jul 25, 2024
39f79fc
Merge remote-tracking branch 'nikita/ignite-22319' into ignite-22319
Vladsz83 Jul 25, 2024
003558a
Merge remote-tracking branch 'refs/remotes/apache/master' into ignite…
NSAmelchev Jul 25, 2024
8b3ea4f
Merge remote-tracking branch 'nikita/ignite-22319' into ignite-22319
Vladsz83 Jul 25, 2024
4e5476d
research
Vladsz83 Jul 25, 2024
e7aff56
my
Vladsz83 Jul 25, 2024
0b0952d
Merge branch 'master' into IGNITE-22776-stats_updating
Vladsz83 Jul 25, 2024
7678c08
review fixes
Vladsz83 Jul 26, 2024
ac1daf1
minor
Vladsz83 Jul 26, 2024
75c0405
Merge branch 'master' into IGNITE-22776-stats_updating
Vladsz83 Jul 26, 2024
b0fad18
reverts
Vladsz83 Jul 26, 2024
c469341
review fix
Vladsz83 Jul 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2747,6 +2747,8 @@ public void store(GridCacheContext cctx, CacheDataRow newRow, @Nullable CacheDat

if (idx != null)
idx.store(cctx, desc, newRow, prevRow, prevRowAvailable);

statsMgr.onRowUpdated(desc.schemaName(), desc.tableName(), newRow.partition(), key.valueBytes(coctx));
}

/**
Expand Down Expand Up @@ -3614,6 +3616,8 @@ public void remove(GridCacheContext cctx, CacheDataRow row)

if (indexingEnabled())
idx.remove(cctx, desc, row);

statsMgr.onRowUpdated(desc.schemaName(), desc.tableName(), row.partition(), row.key().valueBytes(cctx.cacheObjectContext()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public class IgniteStatisticsManagerImpl implements IgniteStatisticsManager {
private volatile boolean started;

/** Schedule to process obsolescence statistics. */
private GridTimeoutProcessor.CancelableTask obsolescenceSchedule;
private volatile GridTimeoutProcessor.CancelableTask obsolescenceSchedule;

/** Exchange listener. */
private final PartitionsExchangeAware exchAwareLsnr = new PartitionsExchangeAware() {
Expand Down Expand Up @@ -236,16 +236,23 @@ else if (db == null)

tryStart();

if (serverNode) {
// Use mgmt pool to work with statistics repository in busy lock to schedule some tasks.
obsolescenceSchedule = ctx.timeout().schedule(() -> {
obsolescenceBusyExecutor.execute(() -> processObsolescence());
}, OBSOLESCENCE_INTERVAL * 1000, OBSOLESCENCE_INTERVAL * 1000);
}
if (serverNode)
scheduleObsolescence(OBSOLESCENCE_INTERVAL);

ctx.cache().context().exchange().registerExchangeAwareComponent(exchAwareLsnr);
}

/** */
void scheduleObsolescence(int seconds) {
assert seconds >= 1;

if (obsolescenceSchedule != null)
obsolescenceSchedule.close();

obsolescenceSchedule = ctx.timeout().schedule(() -> obsolescenceBusyExecutor.execute(this::processObsolescence),
seconds * 1000, seconds * 1000);
}

/**
* Check all preconditions and stop if started and have reason to stop.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,23 @@ protected List<List<?>> sql(String sql) {
}

/**
* Create SQL table with the given index.
* Creates SQL table with the given index and fills with small amount of data.
*
* @param suffix Table idx, if {@code null} - name "SMALL" without index will be used.
* @return Table name.
*/
protected String createSmallTable(String suffix) {
return createSmallTable(SMALL_SIZE, suffix);
}

/**
* Creates SQL table with the given index and fills with data of the passed amount.
*
* @param preloadCnt Records cnt to load after creation.
* @param suffix Table idx, if {@code null} - name "SMALL" without index will be used.
* @return Table name.
*/
protected String createSmallTable(int preloadCnt, String suffix) {
String tblName = "small" + ((suffix != null) ? suffix : "");

sql("DROP TABLE IF EXISTS " + tblName);
Expand All @@ -279,7 +290,7 @@ protected String createSmallTable(String suffix) {

sql(String.format("CREATE INDEX %s_c ON %s(c)", tblName, tblName));

for (int i = 0; i < SMALL_SIZE; i++)
for (int i = 0; i < preloadCnt; i++)
sql(String.format("INSERT INTO %s(a, b, c) VALUES(%d, %d, %d)", tblName, i, i, i % 10));

return tblName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,147 @@
package org.apache.ignite.internal.processors.query.stat;

import java.util.Map;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.apache.ignite.Ignite;
import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
import org.apache.ignite.cluster.ClusterState;
import org.apache.ignite.configuration.DataRegionConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.IgniteInterruptedCheckedException;
import org.apache.ignite.internal.util.collection.IntMap;
import org.apache.ignite.internal.util.typedef.G;
import org.apache.ignite.testframework.GridTestUtils;
import org.junit.Test;

import static org.apache.ignite.internal.processors.query.stat.IgniteStatisticsHelper.buildDefaultConfigurations;
import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;

/**
* Test for statistics obsolescence.
*/
public class StatisticsObsolescenceTest extends StatisticsAbstractTest {
/** */
@Test
public void testObsolescenceWithInsert() throws Exception {
doTestObsolescenceUnderLoad(false, 1,
key -> sql(String.format("insert into SMALL(A, B, C) values(%d, %d, %d)", key, key, key)));
}

/** */
@Test
public void testObsolescenceWithUpdate() throws Exception {
doTestObsolescenceUnderLoad(true, 0, key -> sql("update SMALL set B=B+1 where A=" + key));
}

/** */
@Test
public void testObsolescenceWithDelete() throws Exception {
doTestObsolescenceUnderLoad(true, -1, key -> sql("delete from SMALL where A=" + key));
}

/** */
private void doTestObsolescenceUnderLoad(boolean preload, int rowCntCmp, Consumer<Long> op) throws Exception {
// Keep enough data to touch every partition. The statistics collection is sensitive to a partition's empty rows num
// and is able to reassemble in this case. This would give false-positive result.
int workingRowsNum = RendezvousAffinityFunction.DFLT_PARTITION_COUNT * 10;
int preloadCnt = preload ? workingRowsNum : 0;

int osbInterval = 7;

CyclicBarrier barrier = new CyclicBarrier(2);

try {
startGridsMultiThreaded(2);

for (Ignite ig : G.allGrids())
((IgniteStatisticsManagerImpl)((IgniteEx)ig).context().query().statsManager()).scheduleObsolescence(osbInterval);

createSmallTable(preloadCnt, null);

statisticsMgr(0).usageState(StatisticsUsageState.ON);
statisticsMgr(0).collectStatistics(buildDefaultConfigurations(SMALL_TARGET));

// Initialized statistics.
assertTrue(waitForCondition(() -> statisticsMgr(0).getLocalStatistics(SMALL_KEY) != null, osbInterval * 1000));
assertTrue(waitForCondition(() -> statisticsMgr(1).getLocalStatistics(SMALL_KEY) != null, osbInterval * 1000));

ObjectStatisticsImpl initStat1 = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);
ObjectStatisticsImpl initStat2 = (ObjectStatisticsImpl)statisticsMgr(1).getLocalStatistics(SMALL_KEY);

assertEquals(preloadCnt, initStat1.rowCount() + initStat2.rowCount());

GridTestUtils.runAsync(() -> {
AtomicLong key = new AtomicLong(1L);

long opCnt = 0;

while (!barrier.isBroken()) {
op.accept(key.getAndIncrement());

// Enough updates to trigger the statistics.
if (++opCnt == workingRowsNum / 3) {
opCnt = 0;

barrier.await();
barrier.await();
}
}
});

barrier.await();

waitForStatsUpdates(initStat1, osbInterval * 2);

ObjectStatisticsImpl updatedStat = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);

assertTrue(rowCntCmp > 0 ? updatedStat.rowCount() > initStat1.rowCount() :
(rowCntCmp < 0 ? updatedStat.rowCount() < initStat1.rowCount() : updatedStat.rowCount() == initStat1.rowCount()));

barrier.await();
barrier.await();

// Continuing data loading, the table is being updated. Since the row count is inreasing, we must obtain a
// new statistics, greather than {@code firstNotEmpty}.
waitForStatsUpdates(updatedStat, osbInterval * 2);

ObjectStatisticsImpl finalStat = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);

assertTrue(rowCntCmp > 0 ? finalStat.rowCount() > updatedStat.rowCount() :
(rowCntCmp < 0 ? finalStat.rowCount() < updatedStat.rowCount() : finalStat.rowCount() == updatedStat.rowCount()));
}
finally {
barrier.reset();
}
}

/** */
private void waitForStatsUpdates(ObjectStatisticsImpl compareTo, long timeoutSec) throws IgniteInterruptedCheckedException {
assertTrue(waitForCondition(() -> {
ObjectStatisticsImpl updatedStat = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);

if (updatedStat == null)
return false;

AtomicBoolean passed = new AtomicBoolean(true);

updatedStat.columnsStatistics().forEach((col, stat) -> {
ColumnStatistics compared = compareTo.columnStatistics(col);

assert compared != null;

if (compared.createdAt() >= stat.createdAt())
passed.set(false);
});

return passed.get();
}, timeoutSec * 1000));
}

/**
* Test statistics refreshing after significant changes of base table:
* 1) Create and populate small table
Expand All @@ -51,7 +176,7 @@ public void testObsolescence() throws Exception {

statisticsMgr(0).collectStatistics(buildDefaultConfigurations(SMALL_TARGET));

assertTrue(GridTestUtils.waitForCondition(() -> statisticsMgr(0).getLocalStatistics(SMALL_KEY) != null, TIMEOUT));
assertTrue(waitForCondition(() -> statisticsMgr(0).getLocalStatistics(SMALL_KEY) != null, TIMEOUT));

ObjectStatisticsImpl stat1 = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);

Expand All @@ -62,7 +187,7 @@ public void testObsolescence() throws Exception {

statisticsMgr(0).processObsolescence();

assertTrue(GridTestUtils.waitForCondition(() -> {
assertTrue(waitForCondition(() -> {
ObjectStatisticsImpl stat2 = (ObjectStatisticsImpl)statisticsMgr(0).getLocalStatistics(SMALL_KEY);

return stat2 != null && stat2.rowCount() > stat1.rowCount();
Expand Down Expand Up @@ -103,7 +228,7 @@ public void testInactiveLoad() throws Exception {

ignite.cluster().state(ClusterState.ACTIVE);

assertTrue(GridTestUtils.waitForCondition(() -> statObs.get(SMALL_KEY).size() > oldSize, TIMEOUT));
assertTrue(waitForCondition(() -> statObs.get(SMALL_KEY).size() > oldSize, TIMEOUT));
}

/** {@inheritDoc} */
Expand Down
Loading