You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ignite.apache.org by "Pavel Pereslegin (Jira)" <ji...@apache.org> on 2023/10/20 08:56:00 UTC
[jira] [Updated] (IGNITE-20498) Prevent potential catalog version order violations.
[ https://issues.apache.org/jira/browse/IGNITE-20498?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Pavel Pereslegin updated IGNITE-20498:
--------------------------------------
Description:
Currently, catalog versions are stored in an ordered structure. The activation timestamp is used as a key, which depends on the configuration property "schemaSync.delayDuration".
Changes to "delayDuration" parameter in runtime may lead to a violation of the order in which catalog versions are stored. That is, the old version may be saved with a bigger timestamp than the newer one.
As a result, the manager can return incorrect (older) version of the catalog using a timestamp.
reproducer:
{code:java}
public class CatalogDelayDurationChangeTest extends BaseIgniteAbstractTest {
private static final String NODE_NAME = "node1";
private static final String TABLE_NAME = "test1";
private final HybridClock clock = new HybridClockImpl();
private final AtomicLong delayFromConfig = new AtomicLong();
@Test
public void testChangeDelayDuration() {
CatalogManager catalogMgr = createManager();
// Prepare schema changes.
ColumnParams column = ColumnParams.builder().name("ID").type(ColumnType.INT32).build();
CatalogCommand cmd1 = BaseCatalogManagerTest.createTableCommand(TABLE_NAME, List.of(column), List.of("ID"), null);
CatalogCommand cmd2 = BaseCatalogManagerTest.createTableCommand("test2", List.of(column), List.of("ID"), null);
// Make first schema change with delay = 1000.
delayFromConfig.set(1_000);
CompletableFuture<Void> schemaChangeFuture0 = catalogMgr.execute(cmd1);
// Make second schema change with delay = 1.
delayFromConfig.set(1);
CompletableFuture<Void> schemaChangeFuture1 = catalogMgr.execute(cmd2);
assertThat(schemaChangeFuture0, willCompleteSuccessfully());
assertThat(schemaChangeFuture1, willCompleteSuccessfully());
// Make sure that we are getting the latest version of the schema using current timestamp.
int latestVer = catalogMgr.latestCatalogVersion();
int currentTsVer = catalogMgr.activeCatalogVersion(clock.now().longValue());
assertThat(currentTsVer, equalTo(latestVer));
}
private CatalogManager createManager() {
VaultManager vault = new VaultManager(new InMemoryVaultService());
MetaStorageManager metastore = StandaloneMetaStorageManager.create(vault, new SimpleInMemoryKeyValueStorage(NODE_NAME));
UpdateLog updateLog = spy(new UpdateLogImpl(metastore));
ClockWaiter clockWaiter = spy(new ClockWaiter(NODE_NAME, clock));
CatalogManager manager = new CatalogManagerImpl(updateLog, clockWaiter, delayFromConfig::get);
vault.start();
metastore.start();
clockWaiter.start();
manager.start();
metastore.deployWatches().join();
return manager;
}
}
{code}
was:
Currently, catalog versions are stored in an ordered structure. The activation timestamp is used as a key, which depends on the configuration property "schemaSync.delayDuration".
Changes to "delayDuration" parameter in runtime may lead to a violation of the order in which catalog versions are stored. That is, the old version may be saved with a larger timestamp than the newer one.
As a result, the manager can return incorrect (older) version of the catalog using a timestamp.
reproducer:
{code:java}
public class CatalogDelayDurationChangeTest extends BaseIgniteAbstractTest {
private static final String NODE_NAME = "node1";
private static final String TABLE_NAME = "test1";
private final HybridClock clock = new HybridClockImpl();
private final AtomicLong delayFromConfig = new AtomicLong();
@Test
public void testChangeDelayDuration() {
CatalogManager catalogMgr = createManager();
// Prepare schema changes.
ColumnParams column = ColumnParams.builder().name("ID").type(ColumnType.INT32).build();
CatalogCommand cmd1 = BaseCatalogManagerTest.createTableCommand(TABLE_NAME, List.of(column), List.of("ID"), null);
CatalogCommand cmd2 = BaseCatalogManagerTest.createTableCommand("test2", List.of(column), List.of("ID"), null);
// Make first schema change with delay = 1000.
delayFromConfig.set(1_000);
CompletableFuture<Void> schemaChangeFuture0 = catalogMgr.execute(cmd1);
// Make second schema change with delay = 1.
delayFromConfig.set(1);
CompletableFuture<Void> schemaChangeFuture1 = catalogMgr.execute(cmd2);
assertThat(schemaChangeFuture0, willCompleteSuccessfully());
assertThat(schemaChangeFuture1, willCompleteSuccessfully());
// Make sure that we are getting the latest version of the schema using current timestamp.
int latestVer = catalogMgr.latestCatalogVersion();
int currentTsVer = catalogMgr.activeCatalogVersion(clock.now().longValue());
assertThat(currentTsVer, equalTo(latestVer));
}
private CatalogManager createManager() {
VaultManager vault = new VaultManager(new InMemoryVaultService());
MetaStorageManager metastore = StandaloneMetaStorageManager.create(vault, new SimpleInMemoryKeyValueStorage(NODE_NAME));
UpdateLog updateLog = spy(new UpdateLogImpl(metastore));
ClockWaiter clockWaiter = spy(new ClockWaiter(NODE_NAME, clock));
CatalogManager manager = new CatalogManagerImpl(updateLog, clockWaiter, delayFromConfig::get);
vault.start();
metastore.start();
clockWaiter.start();
manager.start();
metastore.deployWatches().join();
return manager;
}
}
{code}
> Prevent potential catalog version order violations.
> ---------------------------------------------------
>
> Key: IGNITE-20498
> URL: https://issues.apache.org/jira/browse/IGNITE-20498
> Project: Ignite
> Issue Type: Bug
> Reporter: Pavel Pereslegin
> Priority: Major
> Labels: ignite-3
>
> Currently, catalog versions are stored in an ordered structure. The activation timestamp is used as a key, which depends on the configuration property "schemaSync.delayDuration".
> Changes to "delayDuration" parameter in runtime may lead to a violation of the order in which catalog versions are stored. That is, the old version may be saved with a bigger timestamp than the newer one.
> As a result, the manager can return incorrect (older) version of the catalog using a timestamp.
> reproducer:
> {code:java}
> public class CatalogDelayDurationChangeTest extends BaseIgniteAbstractTest {
> private static final String NODE_NAME = "node1";
> private static final String TABLE_NAME = "test1";
> private final HybridClock clock = new HybridClockImpl();
> private final AtomicLong delayFromConfig = new AtomicLong();
> @Test
> public void testChangeDelayDuration() {
> CatalogManager catalogMgr = createManager();
> // Prepare schema changes.
> ColumnParams column = ColumnParams.builder().name("ID").type(ColumnType.INT32).build();
> CatalogCommand cmd1 = BaseCatalogManagerTest.createTableCommand(TABLE_NAME, List.of(column), List.of("ID"), null);
> CatalogCommand cmd2 = BaseCatalogManagerTest.createTableCommand("test2", List.of(column), List.of("ID"), null);
> // Make first schema change with delay = 1000.
> delayFromConfig.set(1_000);
> CompletableFuture<Void> schemaChangeFuture0 = catalogMgr.execute(cmd1);
> // Make second schema change with delay = 1.
> delayFromConfig.set(1);
> CompletableFuture<Void> schemaChangeFuture1 = catalogMgr.execute(cmd2);
> assertThat(schemaChangeFuture0, willCompleteSuccessfully());
> assertThat(schemaChangeFuture1, willCompleteSuccessfully());
> // Make sure that we are getting the latest version of the schema using current timestamp.
> int latestVer = catalogMgr.latestCatalogVersion();
> int currentTsVer = catalogMgr.activeCatalogVersion(clock.now().longValue());
> assertThat(currentTsVer, equalTo(latestVer));
> }
> private CatalogManager createManager() {
> VaultManager vault = new VaultManager(new InMemoryVaultService());
> MetaStorageManager metastore = StandaloneMetaStorageManager.create(vault, new SimpleInMemoryKeyValueStorage(NODE_NAME));
> UpdateLog updateLog = spy(new UpdateLogImpl(metastore));
> ClockWaiter clockWaiter = spy(new ClockWaiter(NODE_NAME, clock));
> CatalogManager manager = new CatalogManagerImpl(updateLog, clockWaiter, delayFromConfig::get);
> vault.start();
> metastore.start();
> clockWaiter.start();
> manager.start();
> metastore.deployWatches().join();
> return manager;
> }
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)