This is an automated email from the ASF dual-hosted git repository.
jt2594838 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new ec473f7fd1d [Subscription] Isolate tree and table topics (#18397)
ec473f7fd1d is described below
commit ec473f7fd1d64d690bc770d034ace348fb016e3f
Author: Caideyipi <[email protected]>
AuthorDate: Thu Aug 6 18:47:10 2026 +0800
[Subscription] Isolate tree and table topics (#18397)
* [Subscription] Isolate tree and table topics
* [Subscription] Fix retry test topic lookup mocks
---
.../tablemodel/IoTDBSubscriptionIsolationIT.java | 161 ++++++++++-----------
.../write/subscription/topic/DropTopicPlan.java | 31 +++-
.../iotdb/confignode/manager/ProcedureManager.java | 23 ++-
.../subscription/SubscriptionCoordinator.java | 76 +++++++---
.../persistence/subscription/SubscriptionInfo.java | 93 +++++++++---
.../procedure/env/ConfigNodeProcedureEnv.java | 12 ++
.../subscription/CreateSubscriptionProcedure.java | 3 +-
.../subscription/DropSubscriptionProcedure.java | 3 +-
.../subscription/topic/AlterTopicProcedure.java | 6 +-
.../subscription/topic/CreateTopicProcedure.java | 6 +-
.../subscription/topic/DropTopicProcedure.java | 41 +++++-
.../request/ConfigPhysicalPlanSerDeTest.java | 8 +-
.../subscription/SubscriptionCoordinatorTest.java | 19 ++-
.../subscription/SubscriptionInfoTest.java | 66 +++++++++
.../CreateSubscriptionProcedureTest.java | 2 +-
.../DropSubscriptionProcedureTest.java | 2 +-
.../subscription/topic/DropTopicProcedureTest.java | 19 +++
.../impl/DataNodeInternalRPCServiceImpl.java | 6 +-
.../agent/SubscriptionBrokerAgent.java | 47 ++++--
.../agent/SubscriptionConsumerAgent.java | 22 ++-
.../subscription/agent/SubscriptionTopicAgent.java | 83 ++++++++---
.../db/subscription/broker/SubscriptionBroker.java | 14 +-
.../broker/SubscriptionPrefetchingQueue.java | 9 +-
.../consensus/ConsensusLogToTabletConverter.java | 2 +-
.../consensus/ConsensusPrefetchingQueue.java | 9 +-
.../ConsensusSubscriptionSetupHandler.java | 32 +++-
.../batch/SubscriptionPipeTabletEventBatch.java | 9 +-
.../batch/SubscriptionPipeTsFileEventBatch.java | 5 +-
.../response/SubscriptionEventTabletResponse.java | 5 +-
.../response/SubscriptionEventTsFileResponse.java | 5 +-
.../receiver/SubscriptionReceiverV1.java | 18 ++-
.../task/subtask/SubscriptionSinkSubtask.java | 3 +-
.../subtask/SubscriptionSinkSubtaskLifeCycle.java | 7 +-
.../apache/iotdb/commons/i18n/PipeMessages.java | 1 +
.../apache/iotdb/commons/i18n/PipeMessages.java | 1 +
.../meta/consumer/ConsumerGroupMeta.java | 28 ++++
.../meta/consumer/ConsumerGroupMetaKeeper.java | 20 +++
.../subscription/meta/consumer/ConsumerMeta.java | 4 +
.../subscription/meta/topic/TopicMetaKeeper.java | 42 ++++--
.../consumer/ConsumerGroupDeSerTest.java | 25 ++++
.../subscription/topic/TopicMetaKeeperTest.java | 120 +++++++++++++++
.../src/main/thrift/datanode.thrift | 2 +
42 files changed, 865 insertions(+), 225 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/tablemodel/IoTDBSubscriptionIsolationIT.java
b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/tablemodel/IoTDBSubscriptionIsolationIT.java
index 99b674d1079..2d15cff252b 100644
---
a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/tablemodel/IoTDBSubscriptionIsolationIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/tablemodel/IoTDBSubscriptionIsolationIT.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.subscription.it.local.tablemodel;
import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.framework.IoTDBTestRunner;
import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.rpc.subscription.config.TopicConstant;
import org.apache.iotdb.session.subscription.ISubscriptionTableSession;
import org.apache.iotdb.session.subscription.ISubscriptionTreeSession;
import org.apache.iotdb.session.subscription.SubscriptionTableSessionBuilder;
@@ -34,12 +35,11 @@ import
org.apache.iotdb.subscription.it.local.AbstractSubscriptionLocalIT;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
-import static org.junit.Assert.fail;
+import java.util.Properties;
@RunWith(IoTDBTestRunner.class)
@Category({LocalStandaloneIT.class})
@@ -51,26 +51,35 @@ public class IoTDBSubscriptionIsolationIT extends
AbstractSubscriptionLocalIT {
super.setUp();
}
- @Ignore
@Test
public void testTopicIsolation() throws Exception {
- final String treeTopicName = "treeTopic";
- final String tableTopicName = "tableTopic";
+ final String topicName = "topic";
final String host = EnvFactory.getEnv().getIP();
final int port = Integer.parseInt(EnvFactory.getEnv().getPort());
- // create tree topic
+ final Properties treeTopicProperties = new Properties();
+ treeTopicProperties.setProperty(TopicConstant.PATH_KEY, "root.tree.**");
try (final ISubscriptionTreeSession session =
new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
session.open();
- session.createTopic(treeTopicName);
+ session.createTopic(topicName, treeTopicProperties);
+
+ final Properties alteredProperties = new Properties();
+ alteredProperties.setProperty(TopicConstant.PATH_KEY,
"root.tree_altered.**");
+ session.alterTopic(topicName, alteredProperties);
}
- // create table topic
+ final Properties tableTopicProperties = new Properties();
+ tableTopicProperties.setProperty(TopicConstant.DATABASE_KEY, "table_db");
+ tableTopicProperties.setProperty(TopicConstant.TABLE_KEY, "table_name");
try (final ISubscriptionTableSession session =
new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
- session.createTopic(tableTopicName);
+ session.createTopic(topicName, tableTopicProperties);
+
+ final Properties alteredProperties = new Properties();
+ alteredProperties.setProperty(TopicConstant.DATABASE_KEY,
"table_db_altered");
+ session.alterTopic(topicName, alteredProperties);
}
// show topic on tree session
@@ -78,58 +87,43 @@ public class IoTDBSubscriptionIsolationIT extends
AbstractSubscriptionLocalIT {
new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
session.open();
Assert.assertEquals(1, session.getTopics().size());
- Assert.assertTrue(session.getTopic(treeTopicName).isPresent());
- Assert.assertFalse(session.getTopic(tableTopicName).isPresent());
+ Assert.assertTrue(session.getTopic(topicName).isPresent());
+ Assert.assertTrue(
+
session.getTopic(topicName).get().getTopicAttributes().contains("root.tree_altered.**"));
+ Assert.assertFalse(
+
session.getTopic(topicName).get().getTopicAttributes().contains("table_db_altered"));
}
// show topic on table session
try (final ISubscriptionTableSession session =
new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
Assert.assertEquals(1, session.getTopics().size());
- Assert.assertTrue(session.getTopic(tableTopicName).isPresent());
- Assert.assertFalse(session.getTopic(treeTopicName).isPresent());
- }
-
- // drop table topic on tree session
- try (final ISubscriptionTreeSession session =
- new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
- session.open();
- try {
- session.dropTopic(tableTopicName);
- fail();
- } catch (final Exception ignored) {
- }
+ Assert.assertTrue(session.getTopic(topicName).isPresent());
+ Assert.assertTrue(
+
session.getTopic(topicName).get().getTopicAttributes().contains("table_db_altered"));
+ Assert.assertFalse(
+
session.getTopic(topicName).get().getTopicAttributes().contains("root.tree_altered.**"));
}
- // drop tree topic on table session
- try (final ISubscriptionTableSession session =
- new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
- try {
- session.dropTopic(treeTopicName);
- fail();
- } catch (final Exception ignored) {
- }
- }
-
- // drop tree topic on tree session
+ // Dropping the tree-model topic must not affect the same-named
table-model topic.
try (final ISubscriptionTreeSession session =
new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
session.open();
- session.dropTopic(treeTopicName);
+ session.dropTopic(topicName);
+ Assert.assertFalse(session.getTopic(topicName).isPresent());
}
- // drop table topic on table session
try (final ISubscriptionTableSession session =
new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
- session.dropTopic(tableTopicName);
+ Assert.assertTrue(session.getTopic(topicName).isPresent());
+ session.dropTopic(topicName);
+ Assert.assertFalse(session.getTopic(topicName).isPresent());
}
}
- @Ignore
@Test
public void testSubscriptionIsolation() throws Exception {
- final String treeTopicName = "treeTopic";
- final String tableTopicName = "tableTopic";
+ final String topicName = "topic";
final String host = EnvFactory.getEnv().getIP();
final int port = Integer.parseInt(EnvFactory.getEnv().getPort());
@@ -138,83 +132,74 @@ public class IoTDBSubscriptionIsolationIT extends
AbstractSubscriptionLocalIT {
try (final ISubscriptionTreeSession session =
new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
session.open();
- session.createTopic(treeTopicName);
+ session.createTopic(topicName);
}
// create table topic
try (final ISubscriptionTableSession session =
new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
- session.createTopic(tableTopicName);
+ session.createTopic(topicName);
}
- // subscribe table topic on tree consumer
- try (final ISubscriptionTreePullConsumer consumer =
- new
SubscriptionTreePullConsumerBuilder().host(host).port(port).build()) {
- consumer.open();
- try {
- consumer.subscribe(tableTopicName);
- fail();
- } catch (final Exception ignored) {
- }
- }
-
- // subscribe tree topic on table consumer
- try (final ISubscriptionTablePullConsumer consumer =
- new
SubscriptionTablePullConsumerBuilder().host(host).port(port).build()) {
- consumer.open();
- try {
- consumer.subscribe(treeTopicName);
- fail();
- } catch (final Exception ignored) {
- }
- }
-
- // subscribe tree topic on tree consumer
final ISubscriptionTreePullConsumer treeConsumer =
- new
SubscriptionTreePullConsumerBuilder().host(host).port(port).build();
+ new SubscriptionTreePullConsumerBuilder()
+ .host(host)
+ .port(port)
+ .consumerId("tree_consumer")
+ .consumerGroupId("tree_consumer_group")
+ .build();
treeConsumer.open();
- treeConsumer.subscribe(treeTopicName);
+ treeConsumer.subscribe(topicName);
- // subscribe table topic on table consumer
final ISubscriptionTablePullConsumer tableConsumer =
- new
SubscriptionTablePullConsumerBuilder().host(host).port(port).build();
+ new SubscriptionTablePullConsumerBuilder()
+ .host(host)
+ .port(port)
+ .consumerId("table_consumer")
+ .consumerGroupId("table_consumer_group")
+ .build();
tableConsumer.open();
- tableConsumer.subscribe(tableTopicName);
+ tableConsumer.subscribe(topicName);
// show subscription on tree session
try (final ISubscriptionTreeSession session =
new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
session.open();
Assert.assertEquals(1, session.getSubscriptions().size());
- Assert.assertEquals(1, session.getSubscriptions(treeTopicName).size());
- Assert.assertEquals(0, session.getSubscriptions(tableTopicName).size());
+ Assert.assertEquals(1, session.getSubscriptions(topicName).size());
+ Assert.assertEquals(
+ "tree_consumer_group",
+
session.getSubscriptions(topicName).iterator().next().getConsumerGroupId());
}
// show subscription on table session
try (final ISubscriptionTableSession session =
new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
Assert.assertEquals(1, session.getSubscriptions().size());
- Assert.assertEquals(1, session.getSubscriptions(tableTopicName).size());
- Assert.assertEquals(0, session.getSubscriptions(treeTopicName).size());
+ Assert.assertEquals(1, session.getSubscriptions(topicName).size());
+ Assert.assertEquals(
+ "table_consumer_group",
+
session.getSubscriptions(topicName).iterator().next().getConsumerGroupId());
}
- // unsubscribe table topic on tree consumer
- try {
- treeConsumer.unsubscribe(tableTopicName);
- fail();
- } catch (final Exception ignored) {
-
+ // Unsubscribing the tree-model topic must not affect the same-named
table-model subscription.
+ treeConsumer.unsubscribe(topicName);
+ try (final ISubscriptionTreeSession session =
+ new SubscriptionTreeSessionBuilder().host(host).port(port).build()) {
+ session.open();
+ Assert.assertEquals(0, session.getSubscriptions(topicName).size());
+ }
+ try (final ISubscriptionTableSession session =
+ new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
+ Assert.assertEquals(1, session.getSubscriptions(topicName).size());
}
- // unsubscribe tree topic on table consumer
- try {
- tableConsumer.unsubscribe(treeTopicName);
- fail();
- } catch (final Exception ignored) {
-
+ tableConsumer.unsubscribe(topicName);
+ try (final ISubscriptionTableSession session =
+ new SubscriptionTableSessionBuilder().host(host).port(port).build()) {
+ Assert.assertEquals(0, session.getSubscriptions(topicName).size());
}
- // close consumers
treeConsumer.close();
tableConsumer.close();
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/subscription/topic/DropTopicPlan.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/subscription/topic/DropTopicPlan.java
index 75642f92f11..5604fc311bd 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/subscription/topic/DropTopicPlan.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/subscription/topic/DropTopicPlan.java
@@ -32,6 +32,8 @@ import java.util.Objects;
public class DropTopicPlan extends ConfigPhysicalPlan {
private String topicName;
+ private boolean isTableModel;
+ private boolean isTableModelSet;
public DropTopicPlan() {
super(ConfigPhysicalPlanType.DropTopic);
@@ -42,19 +44,40 @@ public class DropTopicPlan extends ConfigPhysicalPlan {
this.topicName = topicName;
}
+ public DropTopicPlan(String topicName, boolean isTableModel) {
+ this(topicName);
+ this.isTableModel = isTableModel;
+ this.isTableModelSet = true;
+ }
+
public String getTopicName() {
return topicName;
}
+ public boolean isTableModel() {
+ return isTableModel;
+ }
+
+ public boolean isTableModelSet() {
+ return isTableModelSet;
+ }
+
@Override
protected void serializeImpl(DataOutputStream stream) throws IOException {
stream.writeShort(getType().getPlanType());
ReadWriteIOUtils.write(topicName, stream);
+ if (isTableModelSet) {
+ ReadWriteIOUtils.write(isTableModel, stream);
+ }
}
@Override
protected void deserializeImpl(ByteBuffer buffer) throws IOException {
topicName = ReadWriteIOUtils.readString(buffer);
+ isTableModelSet = buffer.hasRemaining();
+ if (isTableModelSet) {
+ isTableModel = ReadWriteIOUtils.readBool(buffer);
+ }
}
@Override
@@ -66,16 +89,18 @@ public class DropTopicPlan extends ConfigPhysicalPlan {
return false;
}
DropTopicPlan that = (DropTopicPlan) obj;
- return Objects.equals(topicName, that.topicName);
+ return isTableModel == that.isTableModel
+ && isTableModelSet == that.isTableModelSet
+ && Objects.equals(topicName, that.topicName);
}
@Override
public int hashCode() {
- return Objects.hash(topicName);
+ return Objects.hash(topicName, isTableModel, isTableModelSet);
}
@Override
public String toString() {
- return "DropTopicPlan{" + "topicName='" + topicName + "'}";
+ return "DropTopicPlan{" + "topicName='" + topicName + "', isTableModel=" +
isTableModel + '}';
}
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
index 45cea0a31e3..50b003d0494 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
@@ -1922,7 +1922,8 @@ public class ProcedureManager {
public TSStatus alterTopic(TAlterTopicReq req) {
final SubscriptionCoordinator subscriptionCoordinator =
configManager.getSubscriptionManager().getSubscriptionCoordinator();
- subscriptionCoordinator.lockTopicAlteration(req.getTopicName());
+ final boolean isTableModel = new
TopicConfig(req.getTopicAttributes()).isTableTopic();
+ subscriptionCoordinator.lockTopicAlteration(req.getTopicName(),
isTableModel);
boolean isOwnerLeaseRenewalBlocked = false;
try {
isOwnerLeaseRenewalBlocked =
@@ -1973,9 +1974,9 @@ public class ProcedureManager {
.setMessage(e.getMessage());
} finally {
if (isOwnerLeaseRenewalBlocked) {
- subscriptionCoordinator.unblockOwnerLeaseRenewal(req.getTopicName());
+ subscriptionCoordinator.unblockOwnerLeaseRenewal(req.getTopicName(),
isTableModel);
}
- subscriptionCoordinator.unlockTopicAlteration(req.getTopicName());
+ subscriptionCoordinator.unlockTopicAlteration(req.getTopicName(),
isTableModel);
}
}
@@ -2068,6 +2069,22 @@ public class ProcedureManager {
}
}
+ public TSStatus dropTopic(String topicName, boolean isTableModel) {
+ try {
+ DropTopicProcedure procedure = new DropTopicProcedure(topicName,
isTableModel);
+ executor.submitProcedure(procedure);
+ TSStatus status = waitingProcedureFinished(procedure);
+ if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ return status;
+ } else {
+ return new TSStatus(TSStatusCode.DROP_TOPIC_ERROR.getStatusCode())
+ .setMessage(wrapTimeoutMessageForPipeProcedure(status));
+ }
+ } catch (Exception e) {
+ return new
TSStatus(TSStatusCode.DROP_TOPIC_ERROR.getStatusCode()).setMessage(e.getMessage());
+ }
+ }
+
public TSStatus topicMetaSync() {
try {
TopicMetaSyncProcedure procedure = new TopicMetaSyncProcedure();
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinator.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinator.java
index 1d988eabc93..72db41afe8e 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinator.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinator.java
@@ -51,6 +51,7 @@ import
org.apache.iotdb.mpp.rpc.thrift.TPushTopicOwnerLeaseReq;
import org.apache.iotdb.mpp.rpc.thrift.TTopicOwnerLeaseEntry;
import org.apache.iotdb.rpc.RpcUtils;
import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.rpc.subscription.config.TopicConfig;
import org.apache.tsfile.utils.Pair;
import org.slf4j.Logger;
@@ -82,16 +83,18 @@ public class SubscriptionCoordinator {
private final SubscriptionMetaSyncer subscriptionMetaSyncer;
private final SubscriptionOwnerLeaseSyncer subscriptionOwnerLeaseSyncer;
- // Serialize client ALTER TOPIC requests per topic. Besides preventing
ordinary partial updates
- // from being built from the same snapshot, this also ensures that only one
owner-transfer
- // request can own the renewal-block entry for a topic at a time.
- private final Map<String, TopicAlterationLock> topicAlterationLocks = new
HashMap<>();
+ // Serialize client ALTER TOPIC requests per model-qualified topic. Besides
preventing ordinary
+ // partial updates from being built from the same snapshot, this also
ensures that only one
+ // owner-transfer request can own the renewal-block entry for a topic at a
time.
+ private final Map<TopicModelKey, TopicAlterationLock> topicAlterationLocks =
new HashMap<>();
- // topicName -> blockSinceMs (ConfigNode local clock when owner-lease
renewal was stopped for an
- // in-flight owner transfer). Used to skip renewal and to bound the
admission wait.
- private final Map<String, Long> blockedOwnerLeaseRenewalTopics =
+ // model-qualified topic -> blockSinceMs (ConfigNode local clock when
owner-lease renewal was
+ // stopped for an in-flight owner transfer). Used to skip renewal and to
bound the admission wait.
+ private final Map<TopicModelKey, Long> blockedOwnerLeaseRenewalTopics =
Collections.synchronizedMap(new HashMap<>());
+ private record TopicModelKey(String topicName, boolean isTableModel) {}
+
private static class TopicAlterationLock {
private final ReentrantLock lock = new ReentrantLock(true);
@@ -148,25 +151,35 @@ public class SubscriptionCoordinator {
}
public void lockTopicAlteration(final String topicName) {
+ lockTopicAlteration(topicName, false);
+ }
+
+ public void lockTopicAlteration(final String topicName, final boolean
isTableModel) {
+ final TopicModelKey topicModelKey = new TopicModelKey(topicName,
isTableModel);
final TopicAlterationLock topicAlterationLock;
synchronized (topicAlterationLocks) {
topicAlterationLock =
- topicAlterationLocks.computeIfAbsent(topicName, ignored -> new
TopicAlterationLock());
+ topicAlterationLocks.computeIfAbsent(topicModelKey, ignored -> new
TopicAlterationLock());
topicAlterationLock.referenceCount++;
}
topicAlterationLock.lock.lock();
}
public void unlockTopicAlteration(final String topicName) {
+ unlockTopicAlteration(topicName, false);
+ }
+
+ public void unlockTopicAlteration(final String topicName, final boolean
isTableModel) {
+ final TopicModelKey topicModelKey = new TopicModelKey(topicName,
isTableModel);
final TopicAlterationLock topicAlterationLock;
synchronized (topicAlterationLocks) {
- topicAlterationLock = topicAlterationLocks.get(topicName);
+ topicAlterationLock = topicAlterationLocks.get(topicModelKey);
}
topicAlterationLock.lock.unlock();
synchronized (topicAlterationLocks) {
if (--topicAlterationLock.referenceCount == 0) {
- topicAlterationLocks.remove(topicName, topicAlterationLock);
+ topicAlterationLocks.remove(topicModelKey, topicAlterationLock);
}
}
}
@@ -221,7 +234,9 @@ public class SubscriptionCoordinator {
}
public boolean blockOwnerLeaseRenewalIfOwnerTransfer(TAlterTopicReq req) {
- final TopicMeta currentTopicMeta =
subscriptionInfo.deepCopyTopicMeta(req.getTopicName());
+ final TopicMeta currentTopicMeta =
+ subscriptionInfo.deepCopyTopicMeta(
+ req.getTopicName(), new
TopicConfig(req.getTopicAttributes()).isTableTopic());
final TopicMeta updatedTopicMeta =
Objects.isNull(currentTopicMeta)
? null
@@ -232,12 +247,18 @@ public class SubscriptionCoordinator {
return false;
}
- blockedOwnerLeaseRenewalTopics.put(req.getTopicName(),
System.currentTimeMillis());
+ blockedOwnerLeaseRenewalTopics.put(
+ new TopicModelKey(req.getTopicName(),
currentTopicMeta.visibleUnderTableModel()),
+ System.currentTimeMillis());
return true;
}
public void unblockOwnerLeaseRenewal(String topicName) {
- blockedOwnerLeaseRenewalTopics.remove(topicName);
+ unblockOwnerLeaseRenewal(topicName, false);
+ }
+
+ public void unblockOwnerLeaseRenewal(final String topicName, final boolean
isTableModel) {
+ blockedOwnerLeaseRenewalTopics.remove(new TopicModelKey(topicName,
isTableModel));
}
/**
@@ -250,7 +271,9 @@ public class SubscriptionCoordinator {
*/
public TopicMeta buildAlteredTopicMetaAfterOwnerLeaseExpired(TAlterTopicReq
req)
throws InterruptedException {
- final TopicMeta currentTopicMeta =
subscriptionInfo.deepCopyTopicMeta(req.getTopicName());
+ final TopicMeta currentTopicMeta =
+ subscriptionInfo.deepCopyTopicMeta(
+ req.getTopicName(), new
TopicConfig(req.getTopicAttributes()).isTableTopic());
final TopicMeta updatedTopicMeta =
Objects.isNull(currentTopicMeta)
? null
@@ -268,7 +291,8 @@ public class SubscriptionCoordinator {
return updatedTopicMeta;
}
- waitForOwnerLeaseExpiration(req.getTopicName(), leaseDurationMs);
+ waitForOwnerLeaseExpiration(
+ req.getTopicName(), currentTopicMeta.visibleUnderTableModel(),
leaseDurationMs);
// Another alteration may have completed while this owner transfer was
waiting for the old
// lease to drain. Rebuild from the latest TopicMeta so that this request
only applies its own
@@ -278,7 +302,14 @@ public class SubscriptionCoordinator {
void waitForOwnerLeaseExpiration(final String topicName, final long
leaseDurationMs)
throws InterruptedException {
- final Long blockSinceMs = blockedOwnerLeaseRenewalTopics.get(topicName);
+ waitForOwnerLeaseExpiration(topicName, false, leaseDurationMs);
+ }
+
+ void waitForOwnerLeaseExpiration(
+ final String topicName, final boolean isTableModel, final long
leaseDurationMs)
+ throws InterruptedException {
+ final Long blockSinceMs =
+ blockedOwnerLeaseRenewalTopics.get(new TopicModelKey(topicName,
isTableModel));
if (Objects.isNull(blockSinceMs)) {
return;
}
@@ -303,13 +334,18 @@ public class SubscriptionCoordinator {
* let its local lease expire and fence the owner (fail-closed).
*/
public void pushTopicOwnerLeasesToDataNodes() {
- final Set<String> blockedTopicNames;
+ final Set<String> blockedTreeTopicNames = new HashSet<>();
+ final Set<String> blockedTableTopicNames = new HashSet<>();
synchronized (blockedOwnerLeaseRenewalTopics) {
- blockedTopicNames = new
HashSet<>(blockedOwnerLeaseRenewalTopics.keySet());
+ for (final TopicModelKey topicModelKey :
blockedOwnerLeaseRenewalTopics.keySet()) {
+ (topicModelKey.isTableModel() ? blockedTableTopicNames :
blockedTreeTopicNames)
+ .add(topicModelKey.topicName());
+ }
}
final List<TTopicOwnerLeaseEntry> ownerLeases =
- subscriptionInfo.collectTopicOwnerLeaseEntries(blockedTopicNames);
+ subscriptionInfo.collectTopicOwnerLeaseEntries(
+ blockedTreeTopicNames, blockedTableTopicNames);
if (ownerLeases.isEmpty()) {
return;
}
@@ -339,7 +375,7 @@ public class SubscriptionCoordinator {
String.format(
"Failed to drop topic %s. Failures: %s does not exist.",
topicName, topicName));
}
- return configManager.getProcedureManager().dropTopic(topicName);
+ return configManager.getProcedureManager().dropTopic(topicName,
req.isTableModel);
}
public TShowTopicResp showTopic(TShowTopicReq req) {
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfo.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfo.java
index 12b25159fa9..6e26f20c0d8 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfo.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfo.java
@@ -218,9 +218,11 @@ public class SubscriptionInfo implements SnapshotProcessor
{
private boolean checkBeforeCreateTopicInternal(TCreateTopicReq
createTopicReq)
throws SubscriptionException {
- validateTopicConfig(new
TopicConfig(safeTopicAttributes(createTopicReq.getTopicAttributes())));
+ final TopicConfig topicConfig =
+ new
TopicConfig(safeTopicAttributes(createTopicReq.getTopicAttributes()));
+ validateTopicConfig(topicConfig);
- if (!isTopicExisted(createTopicReq.getTopicName())) {
+ if (!isTopicExisted(createTopicReq.getTopicName(),
topicConfig.isTableTopic())) {
return true;
}
@@ -237,30 +239,36 @@ public class SubscriptionInfo implements
SnapshotProcessor {
}
public void validateBeforeDroppingTopic(String topicName) throws
SubscriptionException {
+ validateBeforeDroppingTopic(topicName, false);
+ }
+
+ public void validateBeforeDroppingTopic(String topicName, boolean
isTableModel)
+ throws SubscriptionException {
acquireReadLock();
try {
- checkBeforeDropTopicInternal(topicName);
+ checkBeforeDropTopicInternal(topicName, isTableModel);
} finally {
releaseReadLock();
}
}
- private void checkBeforeDropTopicInternal(String topicName) throws
SubscriptionException {
+ private void checkBeforeDropTopicInternal(String topicName, boolean
isTableModel)
+ throws SubscriptionException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
ConfigNodeMessages.CHECK_BEFORE_DROPPING_TOPIC_TOPIC_EXISTS,
topicName,
- isTopicExisted(topicName));
+ isTopicExisted(topicName, isTableModel));
}
- TopicMeta topicMeta = topicMetaKeeper.getTopicMeta(topicName);
+ TopicMeta topicMeta = topicMetaKeeper.getTopicMeta(topicName,
isTableModel);
if (Objects.isNull(topicMeta)) {
// DO NOTHING HERE!
// No matter whether the topic exists, we allow the drop operation
// executed on all nodes to ensure the consistency.
return;
} else {
- if
(!consumerGroupMetaKeeper.isTopicSubscribedByConsumerGroup(topicName)) {
+ if (!consumerGroupMetaKeeper.isTopicSubscribedByConsumerGroup(topicName,
isTableModel)) {
return;
}
}
@@ -311,8 +319,10 @@ public class SubscriptionInfo implements SnapshotProcessor
{
private void checkBeforeAlteringTopicInternal(TopicMeta topicMeta) throws
SubscriptionException {
validateTopicConfig(topicMeta.getConfig());
- if (isTopicExisted(topicMeta.getTopicName())) {
- final TopicMeta existedTopicMeta =
topicMetaKeeper.getTopicMeta(topicMeta.getTopicName());
+ final boolean isTableModel = topicMeta.visibleUnderTableModel();
+ if (isTopicExisted(topicMeta.getTopicName(), isTableModel)) {
+ final TopicMeta existedTopicMeta =
+ topicMetaKeeper.getTopicMeta(topicMeta.getTopicName(), isTableModel);
validateUnsupportedHotUpdatedTopicConfig(
topicMeta.getTopicName(), existedTopicMeta.getConfig(),
topicMeta.getConfig());
return;
@@ -616,6 +626,15 @@ public class SubscriptionInfo implements SnapshotProcessor
{
}
}
+ public TopicMeta getTopicMeta(String topicName, boolean isTableModel) {
+ acquireReadLock();
+ try {
+ return topicMetaKeeper.getTopicMeta(topicName, isTableModel);
+ } finally {
+ releaseReadLock();
+ }
+ }
+
public Iterable<TopicMeta> getAllTopicMeta() {
acquireReadLock();
try {
@@ -636,12 +655,32 @@ public class SubscriptionInfo implements
SnapshotProcessor {
}
}
+ public TopicMeta deepCopyTopicMeta(String topicName, boolean isTableModel) {
+ acquireReadLock();
+ try {
+ return topicMetaKeeper.containsTopicMeta(topicName, isTableModel)
+ ? topicMetaKeeper.getTopicMeta(topicName, isTableModel).deepCopy()
+ : null;
+ } finally {
+ releaseReadLock();
+ }
+ }
+
public TopicMeta deepCopyTopicMetaWithUpdatedAttributes(
String topicName, Map<String, String> updatedAttributes) {
+ final boolean isTableModel =
+ new TopicConfig(safeTopicAttributes(updatedAttributes)).isTableTopic();
+ return deepCopyTopicMetaWithUpdatedAttributes(topicName,
updatedAttributes, isTableModel);
+ }
+
+ public TopicMeta deepCopyTopicMetaWithUpdatedAttributes(
+ String topicName, Map<String, String> updatedAttributes, boolean
isTableModel) {
acquireReadLock();
try {
- return topicMetaKeeper.containsTopicMeta(topicName)
- ?
topicMetaKeeper.getTopicMeta(topicName).deepCopyWithUpdatedAttributes(updatedAttributes)
+ return topicMetaKeeper.containsTopicMeta(topicName, isTableModel)
+ ? topicMetaKeeper
+ .getTopicMeta(topicName, isTableModel)
+ .deepCopyWithUpdatedAttributes(updatedAttributes)
: null;
} finally {
releaseReadLock();
@@ -657,21 +696,28 @@ public class SubscriptionInfo implements
SnapshotProcessor {
*/
public List<TTopicOwnerLeaseEntry> collectTopicOwnerLeaseEntries(
final Set<String> blockedTopicNames) {
+ return collectTopicOwnerLeaseEntries(blockedTopicNames, blockedTopicNames);
+ }
+
+ public List<TTopicOwnerLeaseEntry> collectTopicOwnerLeaseEntries(
+ final Set<String> blockedTreeTopicNames, final Set<String>
blockedTableTopicNames) {
acquireReadLock();
try {
final List<TTopicOwnerLeaseEntry> entries = new ArrayList<>();
for (final TopicMeta topicMeta : topicMetaKeeper.getAllTopicMeta()) {
if (!topicMeta.isOwnerFencingEnabled()
|| Objects.isNull(topicMeta.getOwnerLeaseDurationMs())
- || blockedTopicNames.contains(topicMeta.getTopicName())) {
+ || (topicMeta.visibleUnderTableModel() ? blockedTableTopicNames :
blockedTreeTopicNames)
+ .contains(topicMeta.getTopicName())) {
continue;
}
entries.add(
new TTopicOwnerLeaseEntry(
- topicMeta.getTopicName(),
- topicMeta.getOwnerId(),
- topicMeta.getOwnerEpoch(),
- topicMeta.getOwnerLeaseDurationMs()));
+ topicMeta.getTopicName(),
+ topicMeta.getOwnerId(),
+ topicMeta.getOwnerEpoch(),
+ topicMeta.getOwnerLeaseDurationMs())
+ .setIsTableModel(topicMeta.visibleUnderTableModel()));
}
return entries;
} finally {
@@ -711,15 +757,17 @@ public class SubscriptionInfo implements
SnapshotProcessor {
}
private TSStatus alterTopicInternal(final AlterTopicPlan plan) {
+ final boolean isTableModel = plan.getTopicMeta().visibleUnderTableModel();
try {
TopicMeta.validateOwnerProgression(
- topicMetaKeeper.getTopicMeta(plan.getTopicMeta().getTopicName()),
plan.getTopicMeta());
+ topicMetaKeeper.getTopicMeta(plan.getTopicMeta().getTopicName(),
isTableModel),
+ plan.getTopicMeta());
} catch (final IllegalArgumentException e) {
return new
TSStatus(TSStatusCode.SUBSCRIPTION_OWNER_EPOCH_CONFLICT.getStatusCode())
.setMessage(e.getMessage());
}
- topicMetaKeeper.removeTopicMeta(plan.getTopicMeta().getTopicName());
+ topicMetaKeeper.removeTopicMeta(plan.getTopicMeta().getTopicName(),
isTableModel);
topicMetaKeeper.addTopicMeta(plan.getTopicMeta().getTopicName(),
plan.getTopicMeta());
return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
}
@@ -752,7 +800,11 @@ public class SubscriptionInfo implements SnapshotProcessor
{
public TSStatus dropTopic(DropTopicPlan plan) {
acquireWriteLock();
try {
- topicMetaKeeper.removeTopicMeta(plan.getTopicName());
+ if (plan.isTableModelSet()) {
+ topicMetaKeeper.removeTopicMeta(plan.getTopicName(),
plan.isTableModel());
+ } else {
+ topicMetaKeeper.removeTopicMeta(plan.getTopicName());
+ }
return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
} finally {
releaseWriteLock();
@@ -1087,7 +1139,8 @@ public class SubscriptionInfo implements
SnapshotProcessor {
continue;
}
for (String consumerGroupId :
-
consumerGroupMetaKeeper.getSubscribedConsumerGroupIds(topicMeta.getTopicName()))
{
+ consumerGroupMetaKeeper.getSubscribedConsumerGroupIds(
+ topicMeta.getTopicName(), topicMeta.visibleUnderTableModel())) {
Set<String> subscribedConsumerIDs =
consumerGroupMetaKeeper.getConsumersSubscribingTopic(
consumerGroupId, topicMeta.getTopicName());
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
index 5c020ebf2ec..cf1883b447f 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
@@ -102,6 +102,7 @@ import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -768,10 +769,21 @@ public class ConfigNodeProcedureEnv {
}
public List<TSStatus> dropSingleTopicOnDataNode(String topicNameToDrop) {
+ return dropSingleTopicOnDataNode(topicNameToDrop, null);
+ }
+
+ public List<TSStatus> dropSingleTopicOnDataNode(String topicNameToDrop,
boolean isTableModel) {
+ return dropSingleTopicOnDataNode(topicNameToDrop,
Boolean.valueOf(isTableModel));
+ }
+
+ private List<TSStatus> dropSingleTopicOnDataNode(String topicNameToDrop,
Boolean isTableModel) {
final Map<Integer, TDataNodeLocation> dataNodeLocationMap =
configManager.getNodeManager().getRegisteredDataNodeLocations();
final TPushSingleTopicMetaReq request =
new TPushSingleTopicMetaReq().setTopicNameToDrop(topicNameToDrop);
+ if (Objects.nonNull(isTableModel)) {
+ request.setIsTableModel(isTableModel);
+ }
final DataNodeAsyncRequestContext<TPushSingleTopicMetaReq,
TPushTopicMetaResp> clientHandler =
new DataNodeAsyncRequestContext<>(
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java
index a81661bff2f..04e29edbb94 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java
@@ -115,7 +115,8 @@ public class CreateSubscriptionProcedure extends
AbstractOperateSubscriptionAndP
// Construct CreatePipeProcedureV2s (for non-consensus topics)
for (final String topicName : subscribeReq.getTopicNames()) {
- final TopicMeta topicMeta =
subscriptionInfo.get().deepCopyTopicMeta(topicName);
+ final TopicMeta topicMeta =
+ subscriptionInfo.get().deepCopyTopicMeta(topicName,
subscribeReq.isTableModel);
final String topicMode = topicMeta.getConfig().getMode();
final boolean isConsensusBasedTopic =
topicMeta.getConfig().isIncrementalMode();
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java
index 321ebc9bb96..b4c16985aef 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java
@@ -106,7 +106,8 @@ public class DropSubscriptionProcedure extends
AbstractOperateSubscriptionAndPip
for (final String topic : unsubscribeReq.getTopicNames()) {
if (topicsUnsubByGroup.contains(topic)) {
- final TopicMeta topicMeta =
subscriptionInfo.get().deepCopyTopicMeta(topic);
+ final TopicMeta topicMeta =
+ subscriptionInfo.get().deepCopyTopicMeta(topic,
unsubscribeReq.isTableModel);
final String topicMode = topicMeta.getConfig().getMode();
final boolean isConsensusBasedTopic =
topicMeta.getConfig().isIncrementalMode();
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/AlterTopicProcedure.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/AlterTopicProcedure.java
index 6e9c94dcca4..1f6cc40cb09 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/AlterTopicProcedure.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/AlterTopicProcedure.java
@@ -124,7 +124,11 @@ public class AlterTopicProcedure extends
AbstractOperateSubscriptionProcedure {
public boolean executeFromValidate(ConfigNodeProcedureEnv env) throws
SubscriptionException {
LOGGER.info(ProcedureMessages.ALTERTOPICPROCEDURE_EXECUTEFROMVALIDATE);
- existedTopicMeta =
subscriptionInfo.get().deepCopyTopicMeta(updatedTopicMeta.getTopicName());
+ existedTopicMeta =
+ subscriptionInfo
+ .get()
+ .deepCopyTopicMeta(
+ updatedTopicMeta.getTopicName(),
updatedTopicMeta.visibleUnderTableModel());
if (Objects.nonNull(updatedTopicAttributes) &&
Objects.nonNull(existedTopicMeta)) {
updatedTopicMeta =
existedTopicMeta.deepCopyWithUpdatedAttributes(updatedTopicAttributes);
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/CreateTopicProcedure.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/CreateTopicProcedure.java
index 08ae98a5780..e525ce97479 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/CreateTopicProcedure.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/CreateTopicProcedure.java
@@ -137,7 +137,8 @@ public class CreateTopicProcedure extends
AbstractOperateSubscriptionProcedure {
response =
env.getConfigManager()
.getConsensusManager()
- .write(new DropTopicPlan(topicMeta.getTopicName()));
+ .write(
+ new DropTopicPlan(topicMeta.getTopicName(),
topicMeta.visibleUnderTableModel()));
} catch (ConsensusException e) {
LOGGER.warn(ConfigNodeMessages.FAILED_IN_THE_WRITE_API_EXECUTING_THE_CONSENSUS_LAYER_DUE,
e);
response =
@@ -157,7 +158,8 @@ public class CreateTopicProcedure extends
AbstractOperateSubscriptionProcedure {
throws SubscriptionException {
LOGGER.info(ProcedureMessages.CREATETOPICPROCEDURE_ROLLBACKFROMCREATEONDATANODES,
topicMeta);
- final List<TSStatus> statuses =
env.dropSingleTopicOnDataNode(topicMeta.getTopicName());
+ final List<TSStatus> statuses =
+ env.dropSingleTopicOnDataNode(topicMeta.getTopicName(),
topicMeta.visibleUnderTableModel());
if (RpcUtils.squashResponseStatusList(statuses).getCode()
!= TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
// throw exception instead of logging warn, do not rely on metadata
synchronization
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedure.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedure.java
index 8a17f99045a..8a95811fce5 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedure.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedure.java
@@ -47,6 +47,8 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
private static final Logger LOGGER =
LoggerFactory.getLogger(DropTopicProcedure.class);
private String topicName;
+ private boolean isTableModel;
+ private boolean isTableModelSet;
public DropTopicProcedure() {
super();
@@ -57,6 +59,12 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
this.topicName = topicName;
}
+ public DropTopicProcedure(String topicName, boolean isTableModel) {
+ this(topicName);
+ this.isTableModel = isTableModel;
+ this.isTableModelSet = true;
+ }
+
@Override
protected SubscriptionOperation getOperation() {
return SubscriptionOperation.DROP_TOPIC;
@@ -66,7 +74,11 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
protected boolean executeFromValidate(ConfigNodeProcedureEnv env) throws
SubscriptionException {
LOGGER.info(ProcedureMessages.DROPTOPICPROCEDURE_EXECUTEFROMVALIDATE,
topicName);
- subscriptionInfo.get().validateBeforeDroppingTopic(topicName);
+ if (isTableModelSet) {
+ subscriptionInfo.get().validateBeforeDroppingTopic(topicName,
isTableModel);
+ } else {
+ subscriptionInfo.get().validateBeforeDroppingTopic(topicName);
+ }
return true;
}
@@ -77,7 +89,13 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
TSStatus response;
try {
- response = env.getConfigManager().getConsensusManager().write(new
DropTopicPlan(topicName));
+ response =
+ env.getConfigManager()
+ .getConsensusManager()
+ .write(
+ isTableModelSet
+ ? new DropTopicPlan(topicName, isTableModel)
+ : new DropTopicPlan(topicName));
} catch (ConsensusException e) {
LOGGER.warn(ConfigNodeMessages.FAILED_IN_THE_WRITE_API_EXECUTING_THE_CONSENSUS_LAYER_DUE,
e);
response =
@@ -94,7 +112,10 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
protected void executeFromOperateOnDataNodes(ConfigNodeProcedureEnv env) {
LOGGER.info(ProcedureMessages.DROPTOPICPROCEDURE_EXECUTEFROMOPERATEONDATANODES,
topicName);
- final List<TSStatus> statuses = env.dropSingleTopicOnDataNode(topicName);
+ final List<TSStatus> statuses =
+ isTableModelSet
+ ? env.dropSingleTopicOnDataNode(topicName, isTableModel)
+ : env.dropSingleTopicOnDataNode(topicName);
if (RpcUtils.squashResponseStatusList(statuses).getCode()
!= TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
// throw exception instead of logging warn, do not rely on metadata
synchronization
@@ -125,6 +146,9 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
super.serialize(stream);
ReadWriteIOUtils.write(topicName, stream);
+ if (isTableModelSet) {
+ ReadWriteIOUtils.write(isTableModel, stream);
+ }
}
@Override
@@ -132,6 +156,10 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
super.deserialize(byteBuffer);
topicName = ReadWriteIOUtils.readString(byteBuffer);
+ isTableModelSet = byteBuffer.hasRemaining();
+ if (isTableModelSet) {
+ isTableModel = ReadWriteIOUtils.readBool(byteBuffer);
+ }
}
@Override
@@ -146,11 +174,14 @@ public class DropTopicProcedure extends
AbstractOperateSubscriptionProcedure {
return Objects.equals(getProcId(), that.getProcId())
&& Objects.equals(getCurrentState(), that.getCurrentState())
&& getCycles() == that.getCycles()
- && Objects.equals(topicName, that.topicName);
+ && Objects.equals(topicName, that.topicName)
+ && isTableModel == that.isTableModel
+ && isTableModelSet == that.isTableModelSet;
}
@Override
public int hashCode() {
- return Objects.hash(getProcId(), getCurrentState(), getCycles(),
topicName);
+ return Objects.hash(
+ getProcId(), getCurrentState(), getCycles(), topicName, isTableModel,
isTableModelSet);
}
}
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
index 35537a2cea2..0e858589803 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
@@ -1294,7 +1294,13 @@ public class ConfigPhysicalPlanSerDeTest {
final DropTopicPlan dropTopicPlan = new DropTopicPlan("test_topic");
final DropTopicPlan dropTopicPlan1 =
(DropTopicPlan)
ConfigPhysicalPlan.Factory.create(dropTopicPlan.serializeToByteBuffer());
- Assert.assertEquals(dropTopicPlan.getTopicName(),
dropTopicPlan1.getTopicName());
+ Assert.assertEquals(dropTopicPlan, dropTopicPlan1);
+
+ final DropTopicPlan tableDropTopicPlan = new DropTopicPlan("test_topic",
true);
+ final DropTopicPlan tableDropTopicPlan1 =
+ (DropTopicPlan)
+
ConfigPhysicalPlan.Factory.create(tableDropTopicPlan.serializeToByteBuffer());
+ Assert.assertEquals(tableDropTopicPlan, tableDropTopicPlan1);
}
@Test
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinatorTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinatorTest.java
index 12b1b3dd2ae..6bd896fd2f6 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinatorTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/subscription/SubscriptionCoordinatorTest.java
@@ -52,33 +52,33 @@ public class SubscriptionCoordinatorTest {
final CountDownLatch sameTopicLockAcquired = new CountDownLatch(1);
boolean topic1LockHeld = true;
- coordinator.lockTopicAlteration("topic1");
+ coordinator.lockTopicAlteration("topic1", false);
try {
final Future<?> sameTopicAlteration =
executor.submit(
() -> {
sameTopicAttemptStarted.countDown();
- coordinator.lockTopicAlteration("topic1");
+ coordinator.lockTopicAlteration("topic1", false);
try {
sameTopicLockAcquired.countDown();
} finally {
- coordinator.unlockTopicAlteration("topic1");
+ coordinator.unlockTopicAlteration("topic1", false);
}
});
Assert.assertTrue(sameTopicAttemptStarted.await(5, TimeUnit.SECONDS));
Assert.assertFalse(sameTopicLockAcquired.await(100,
TimeUnit.MILLISECONDS));
- coordinator.lockTopicAlteration("topic2");
- coordinator.unlockTopicAlteration("topic2");
+ coordinator.lockTopicAlteration("topic1", true);
+ coordinator.unlockTopicAlteration("topic1", true);
- coordinator.unlockTopicAlteration("topic1");
+ coordinator.unlockTopicAlteration("topic1", false);
topic1LockHeld = false;
Assert.assertTrue(sameTopicLockAcquired.await(5, TimeUnit.SECONDS));
sameTopicAlteration.get(5, TimeUnit.SECONDS);
} finally {
if (topic1LockHeld) {
- coordinator.unlockTopicAlteration("topic1");
+ coordinator.unlockTopicAlteration("topic1", false);
}
executor.shutdownNow();
}
@@ -108,8 +108,11 @@ public class SubscriptionCoordinatorTest {
new SubscriptionCoordinator(Mockito.mock(ConfigManager.class),
subscriptionInfo) {
@Override
void waitForOwnerLeaseExpiration(
- final String waitingTopicName, final long
waitingLeaseDurationMs) {
+ final String waitingTopicName,
+ final boolean isTableModel,
+ final long waitingLeaseDurationMs) {
Assert.assertEquals(topicName, waitingTopicName);
+ Assert.assertFalse(isTableModel);
Assert.assertEquals(ownerLeaseDurationMs, waitingLeaseDurationMs);
final Map<String, String> updatedAttributes = new HashMap<>();
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfoTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfoTest.java
index f87afe129e5..170bbe2d3e1 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfoTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/subscription/SubscriptionInfoTest.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.confignode.persistence.subscription;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
import
org.apache.iotdb.commons.subscription.meta.consumer.CommitProgressKeeper;
import org.apache.iotdb.commons.subscription.meta.consumer.ConsumerGroupMeta;
import org.apache.iotdb.commons.subscription.meta.consumer.ConsumerMeta;
@@ -27,6 +28,7 @@ import
org.apache.iotdb.commons.subscription.meta.topic.TopicMeta;
import
org.apache.iotdb.confignode.consensus.request.write.subscription.consumer.AlterConsumerGroupPlan;
import
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.AlterTopicPlan;
import
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.CreateTopicPlan;
+import
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.DropTopicPlan;
import
org.apache.iotdb.confignode.consensus.response.subscription.TopicTableResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowTopicInfo;
import org.apache.iotdb.confignode.rpc.thrift.TShowTopicResp;
@@ -47,6 +49,39 @@ import java.util.UUID;
public class SubscriptionInfoTest {
+ @Test
+ public void testSameNameTreeAndTableTopicsCanBeManagedIndependently() {
+ final String topicName = "same-name-topic";
+ final SubscriptionInfo subscriptionInfo = new SubscriptionInfo();
+ final TopicMeta treeTopicMeta =
+ new TopicMeta(
+ topicName,
+ 1L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TREE_VALUE));
+ final TopicMeta tableTopicMeta =
+ new TopicMeta(
+ topicName,
+ 2L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TABLE_VALUE));
+
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ subscriptionInfo.createTopic(new
CreateTopicPlan(treeTopicMeta)).getCode());
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ subscriptionInfo.createTopic(new
CreateTopicPlan(tableTopicMeta)).getCode());
+ Assert.assertSame(treeTopicMeta, subscriptionInfo.getTopicMeta(topicName,
false));
+ Assert.assertSame(tableTopicMeta, subscriptionInfo.getTopicMeta(topicName,
true));
+
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ subscriptionInfo.dropTopic(new DropTopicPlan(topicName,
false)).getCode());
+ Assert.assertFalse(subscriptionInfo.isTopicExisted(topicName, false));
+ Assert.assertTrue(subscriptionInfo.isTopicExisted(topicName, true));
+ }
+
@Test
public void testAlterTopicRejectsOwnerEpochRollback() {
final String topicName = "topic-" + UUID.randomUUID();
@@ -131,6 +166,37 @@ public class SubscriptionInfoTest {
Assert.assertEquals(ownerLeaseDurationMs, entry.getLeaseRemainingMs());
}
+ @Test
+ public void testCollectTopicOwnerLeaseEntriesIsolatedByModel() {
+ final String topicName = "topic-" + UUID.randomUUID();
+ final long ownerLeaseDurationMs = 60000;
+ final SubscriptionInfo subscriptionInfo = new SubscriptionInfo();
+
+ final TopicMeta treeTopicMeta =
+ createTopicMeta(topicName, "tree-owner", 5L, ownerLeaseDurationMs);
+ final TopicMeta tableTopicMeta =
+ createTopicMeta(topicName, "table-owner", 6L, ownerLeaseDurationMs);
+ tableTopicMeta
+ .getConfig()
+ .getAttribute()
+ .put(SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TABLE_VALUE);
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ subscriptionInfo.createTopic(new
CreateTopicPlan(treeTopicMeta)).getCode());
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ subscriptionInfo.createTopic(new
CreateTopicPlan(tableTopicMeta)).getCode());
+
+ final List<TTopicOwnerLeaseEntry> entries =
+ subscriptionInfo.collectTopicOwnerLeaseEntries(
+ Collections.singleton(topicName), Collections.emptySet());
+
+ Assert.assertEquals(1, entries.size());
+ Assert.assertEquals(topicName, entries.get(0).getTopicName());
+ Assert.assertEquals("table-owner", entries.get(0).getOwnerId());
+ Assert.assertTrue(entries.get(0).isIsTableModel());
+ }
+
@Test
public void testAlterTopicOwnerAndShowTopicOwner() {
final String topicName = "topic-" + UUID.randomUUID();
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedureTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedureTest.java
index fc4352a7a00..741e3e344be 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedureTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedureTest.java
@@ -165,7 +165,7 @@ public class CreateSubscriptionProcedureTest {
Mockito.when(
subscriptionInfo.isTopicSubscribedByConsumerGroup("test_topic",
"test_consumer_group"))
.thenReturn(false);
-
Mockito.when(subscriptionInfo.deepCopyTopicMeta("test_topic")).thenReturn(topicMeta);
+ Mockito.when(subscriptionInfo.deepCopyTopicMeta("test_topic",
false)).thenReturn(topicMeta);
final PipeTaskInfo pipeTaskInfo = Mockito.mock(PipeTaskInfo.class);
Mockito.when(pipeTaskInfo.checkBeforeCreatePipe(Mockito.any(TCreatePipeReq.class)))
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedureTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedureTest.java
index 6536c040f10..1bf74f8db24 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedureTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedureTest.java
@@ -145,7 +145,7 @@ public class DropSubscriptionProcedureTest {
.thenReturn(consumerGroupMeta);
Mockito.when(subscriptionInfo.deepCopyConsumerGroupMeta("test_consumer_group"))
.thenAnswer(invocation -> consumerGroupMeta.deepCopy());
- Mockito.when(subscriptionInfo.deepCopyTopicMeta("test_topic"))
+ Mockito.when(subscriptionInfo.deepCopyTopicMeta("test_topic", false))
.thenReturn(new TopicMeta("test_topic", 1, Collections.emptyMap()));
final PipeTaskInfo pipeTaskInfo = Mockito.mock(PipeTaskInfo.class);
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedureTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedureTest.java
index 9b9e2fc9538..0ad614408a3 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedureTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/subscription/topic/DropTopicProcedureTest.java
@@ -49,4 +49,23 @@ public class DropTopicProcedureTest {
fail();
}
}
+
+ @Test
+ public void serializeDeserializeTableModelTest() {
+ PublicBAOS byteArrayOutputStream = new PublicBAOS();
+ DataOutputStream outputStream = new
DataOutputStream(byteArrayOutputStream);
+
+ DropTopicProcedure proc = new DropTopicProcedure("test_topic", true);
+
+ try {
+ proc.serialize(outputStream);
+ ByteBuffer buffer =
+ ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0,
byteArrayOutputStream.size());
+ DropTopicProcedure proc2 = (DropTopicProcedure)
ProcedureFactory.getInstance().create(buffer);
+
+ assertEquals(proc, proc2);
+ } catch (Exception e) {
+ fail();
+ }
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
index 28d75ba4f49..a06d10413fd 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
@@ -1449,7 +1449,11 @@ public class DataNodeInternalRPCServiceImpl implements
IDataNodeRPCService.Iface
try {
final TPushTopicMetaRespExceptionMessage exceptionMessage;
if (req.isSetTopicNameToDrop()) {
- exceptionMessage =
SubscriptionAgent.topic().handleDropTopic(req.getTopicNameToDrop());
+ exceptionMessage =
+ req.isSetIsTableModel()
+ ? SubscriptionAgent.topic()
+ .handleDropTopic(req.getTopicNameToDrop(),
req.isIsTableModel())
+ :
SubscriptionAgent.topic().handleDropTopic(req.getTopicNameToDrop());
} else if (req.isSetTopicMeta()) {
exceptionMessage =
SubscriptionAgent.topic()
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java
index 019253774d5..da649e75b63 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java
@@ -105,7 +105,8 @@ public class SubscriptionBrokerAgent {
final Map<String, TopicProgress> progressByTopic) {
final String consumerGroupId = consumerConfig.getConsumerGroupId();
final String consumerId = consumerConfig.getConsumerId();
- final List<String> unsupportedConsensusTopics =
getUnsupportedConsensusTopics(topicNames);
+ final List<String> unsupportedConsensusTopics =
+ getUnsupportedConsensusTopics(consumerGroupId, topicNames);
if (!unsupportedConsensusTopics.isEmpty()) {
final String errorMessage =
buildUnsupportedConsensusRuntimeMessage(
@@ -238,7 +239,8 @@ public class SubscriptionBrokerAgent {
continue;
}
final String topicName = commitContext.getTopicName();
- if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName))
{
+ if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName, isTableModel(consumerConfig))) {
continue;
}
final String regionId = commitContext.getRegionId();
@@ -347,7 +349,8 @@ public class SubscriptionBrokerAgent {
private ConsensusSubscriptionBroker getConsensusBrokerForSeekOrNoOp(
final String consumerGroupId, final String topicName, final String
operation) {
- if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName)) {
+ if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName,
SubscriptionAgent.consumer().isTableModel(consumerGroupId))) {
final String errorMessage =
String.format(
"Subscription: %s is only supported for consensus-based
subscriptions, "
@@ -394,20 +397,26 @@ public class SubscriptionBrokerAgent {
}
}
- private List<String> getUnsupportedConsensusTopics(final Set<String>
topicNames) {
+ private List<String> getUnsupportedConsensusTopics(
+ final String consumerGroupId, final Set<String> topicNames) {
if (DataRegionConsensusImpl.getInstance() instanceof IoTConsensus) {
return Collections.emptyList();
}
final List<String> unsupportedConsensusTopics = new ArrayList<>();
for (final String topicName : topicNames) {
- if (ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName)) {
+ if (ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName,
SubscriptionAgent.consumer().isTableModel(consumerGroupId))) {
unsupportedConsensusTopics.add(topicName);
}
}
return unsupportedConsensusTopics;
}
+ private static boolean isTableModel(final ConsumerConfig consumerConfig) {
+ return
SubscriptionAgent.consumer().isTableModel(consumerConfig.getConsumerGroupId());
+ }
+
private String buildUnsupportedConsensusRuntimeMessage(
final String consumerGroupId, final String topicName, final String
operation) {
return buildUnsupportedConsensusRuntimeMessage(
@@ -656,14 +665,23 @@ public class SubscriptionBrokerAgent {
return queue;
}
- public void refreshConsensusQueueOrderMode(final String topicName, final
String orderMode) {
+ public void refreshConsensusQueueOrderMode(
+ final String topicName, final boolean isTableModel, final String
orderMode) {
LOGGER.info(
DataNodePipeMessages
.PIPE_LOG_SUBSCRIPTIONBROKERAGENT_REFRESHING_CONSENSUS_QUEUE_ORDER_1886704D,
topicName,
orderMode);
- for (final ConsensusSubscriptionBroker broker :
getBrokers(ConsensusSubscriptionBroker.class)) {
- broker.refreshConsensusQueueOrderMode(topicName, orderMode);
+ for (final Map.Entry<String, List<ISubscriptionBroker>> entry :
+ consumerGroupIdToBrokers.entrySet()) {
+ if (SubscriptionAgent.consumer().isTableModel(entry.getKey()) !=
isTableModel) {
+ continue;
+ }
+ final ConsensusSubscriptionBroker broker =
+ getBroker(entry.getValue(), ConsensusSubscriptionBroker.class);
+ if (Objects.nonNull(broker)) {
+ broker.refreshConsensusQueueOrderMode(topicName, orderMode);
+ }
}
}
@@ -691,13 +709,24 @@ public class SubscriptionBrokerAgent {
}
public ColumnFilterMatcher getColumnFilterMatcher(final String topicName) {
+ return getColumnFilterMatcher(topicName, true);
+ }
+
+ public ColumnFilterMatcher getColumnFilterMatcher(
+ final String topicName, final boolean isTableModel) {
+ if (!isTableModel) {
+ return ColumnFilterMatcher.matchAll();
+ }
+
final ColumnFilterMatcher matcher =
topicNameToColumnFilterMatcher.get(topicName);
if (Objects.nonNull(matcher)) {
return matcher;
}
final TopicConfig topicConfig =
-
SubscriptionAgent.topic().getTopicConfigs(Collections.singleton(topicName)).get(topicName);
+ SubscriptionAgent.topic()
+ .getTopicConfigs(Collections.singleton(topicName), true)
+ .get(topicName);
if (Objects.isNull(topicConfig)) {
return ColumnFilterMatcher.matchAll();
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java
index 22da7a6336b..a268f515a6a 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java
@@ -103,7 +103,9 @@ public class SubscriptionConsumerAgent {
if (Objects.isNull(metaInAgent)) {
SubscriptionAgent.broker().createPipeBrokerIfNotExist(consumerGroupId);
ConsensusSubscriptionSetupHandler.setupConsensusSubscriptions(
- consumerGroupId, metaFromCoordinator.getSubscribedTopicNames());
+ consumerGroupId,
+ metaFromCoordinator.getSubscribedTopicNames(),
+ metaFromCoordinator.visibleUnder(true));
consumerGroupMetaKeeper.addConsumerGroupMeta(consumerGroupId,
metaFromCoordinator);
return;
}
@@ -128,7 +130,9 @@ public class SubscriptionConsumerAgent {
}
ConsensusSubscriptionSetupHandler.setupConsensusSubscriptions(
- consumerGroupId, metaFromCoordinator.getSubscribedTopicNames());
+ consumerGroupId,
+ metaFromCoordinator.getSubscribedTopicNames(),
+ metaFromCoordinator.visibleUnder(true));
consumerGroupMetaKeeper.removeConsumerGroupMeta(consumerGroupId);
consumerGroupMetaKeeper.addConsumerGroupMeta(consumerGroupId,
metaFromCoordinator);
// no need to create broker manually
@@ -141,7 +145,8 @@ public class SubscriptionConsumerAgent {
final Set<String> pipeTopicsUnsubByGroup = new LinkedHashSet<>();
final Set<String> consensusTopicsUnsubByGroup = new LinkedHashSet<>();
for (final String topicName : topicsUnsubByGroup) {
- if (ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName)) {
+ if (ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName, metaFromCoordinator.visibleUnder(true))) {
consensusTopicsUnsubByGroup.add(topicName);
continue;
}
@@ -277,6 +282,17 @@ public class SubscriptionConsumerAgent {
}
}
+ public boolean isTableModel(final String consumerGroupId) {
+ acquireReadLock();
+ try {
+ final ConsumerGroupMeta consumerGroupMeta =
+ consumerGroupMetaKeeper.getConsumerGroupMeta(consumerGroupId);
+ return Objects.nonNull(consumerGroupMeta) &&
consumerGroupMeta.visibleUnder(true);
+ } finally {
+ releaseReadLock();
+ }
+ }
+
/**
* Get all active subscriptions: consumerGroupId → set of subscribed topic
names. Used by
* consensus subscription auto-binding when a new DataRegion is created.
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java
index 43475e79afe..3f69633f499 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.db.subscription.agent;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
import org.apache.iotdb.commons.subscription.meta.topic.TopicMeta;
import org.apache.iotdb.commons.subscription.meta.topic.TopicMetaKeeper;
import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
@@ -98,19 +99,22 @@ public class SubscriptionTopicAgent {
private void handleSingleTopicMetaChangesInternal(final TopicMeta
metaFromCoordinator) {
final String topicName = metaFromCoordinator.getTopicName();
- final TopicMeta oldMeta = topicMetaKeeper.getTopicMeta(topicName);
+ final boolean isTableModel = metaFromCoordinator.visibleUnderTableModel();
+ final TopicMeta oldMeta = topicMetaKeeper.getTopicMeta(topicName,
isTableModel);
TopicMeta.validateOwnerProgression(oldMeta, metaFromCoordinator);
- topicMetaKeeper.removeTopicMeta(topicName);
+ topicMetaKeeper.removeTopicMeta(topicName, isTableModel);
topicMetaKeeper.addTopicMeta(topicName, metaFromCoordinator);
if (shouldRefreshColumnFilter(oldMeta, metaFromCoordinator)) {
SubscriptionAgent.broker().refreshColumnFilter(topicName,
metaFromCoordinator.getConfig());
- } else if (!metaFromCoordinator.getConfig().isTableTopic()) {
+ } else if (!metaFromCoordinator.getConfig().isTableTopic()
+ && !topicMetaKeeper.containsTopicMeta(topicName, true)) {
// ConfigNode rejects column-filter on tree topics. Drop defensively in
case stale or replayed
// topic metadata reaches this DataNode after a table-topic to
tree-topic transition.
SubscriptionAgent.broker().dropColumnFilter(topicName);
}
SubscriptionAgent.broker()
- .refreshConsensusQueueOrderMode(topicName,
metaFromCoordinator.getConfig().getOrderMode());
+ .refreshConsensusQueueOrderMode(
+ topicName, isTableModel,
metaFromCoordinator.getConfig().getOrderMode());
}
static boolean shouldRefreshColumnFilter(final TopicMeta oldMeta, final
TopicMeta newMeta) {
@@ -185,9 +189,19 @@ public class SubscriptionTopicAgent {
}
public TPushTopicMetaRespExceptionMessage handleDropTopic(final String
topicName) {
+ return handleDropTopic(topicName, null);
+ }
+
+ public TPushTopicMetaRespExceptionMessage handleDropTopic(
+ final String topicName, final boolean isTableModel) {
+ return handleDropTopic(topicName, Boolean.valueOf(isTableModel));
+ }
+
+ private TPushTopicMetaRespExceptionMessage handleDropTopic(
+ final String topicName, final Boolean isTableModel) {
acquireWriteLock();
try {
- handleDropTopicInternal(topicName);
+ handleDropTopicInternal(topicName, isTableModel);
return null;
} catch (final Exception e) {
LOGGER.warn(DataNodeMiscMessages.EXCEPTION_DROPPING_TOPIC, topicName, e);
@@ -200,9 +214,19 @@ public class SubscriptionTopicAgent {
}
}
- private void handleDropTopicInternal(final String topicName) {
- topicMetaKeeper.removeTopicMeta(topicName);
- SubscriptionAgent.broker().dropColumnFilter(topicName);
+ private void handleDropTopicInternal(final String topicName, final Boolean
isTableModel) {
+ final TopicMeta topicMeta =
+ Objects.isNull(isTableModel)
+ ? topicMetaKeeper.getTopicMeta(topicName)
+ : topicMetaKeeper.getTopicMeta(topicName, isTableModel);
+ if (Objects.isNull(isTableModel)) {
+ topicMetaKeeper.removeTopicMeta(topicName);
+ } else {
+ topicMetaKeeper.removeTopicMeta(topicName, isTableModel);
+ }
+ if (Objects.nonNull(topicMeta) && topicMeta.visibleUnderTableModel()) {
+ SubscriptionAgent.broker().dropColumnFilter(topicName);
+ }
}
public boolean isTopicExisted(final String topicName) {
@@ -215,11 +239,15 @@ public class SubscriptionTopicAgent {
}
public String getTopicFormat(final String topicName) {
+ return getTopicFormat(topicName, false);
+ }
+
+ public String getTopicFormat(final String topicName, final boolean
isTableModel) {
acquireReadLock();
try {
- return topicMetaKeeper.containsTopicMeta(topicName)
+ return topicMetaKeeper.containsTopicMeta(topicName, isTableModel)
? topicMetaKeeper
- .getTopicMeta(topicName)
+ .getTopicMeta(topicName, isTableModel)
.getConfig()
.getStringOrDefault(TopicConstant.FORMAT_KEY,
TopicConstant.FORMAT_DEFAULT_VALUE)
: null;
@@ -229,10 +257,14 @@ public class SubscriptionTopicAgent {
}
public String getTopicMode(final String topicName) {
+ return getTopicMode(topicName, false);
+ }
+
+ public String getTopicMode(final String topicName, final boolean
isTableModel) {
acquireReadLock();
try {
- return topicMetaKeeper.containsTopicMeta(topicName)
- ? topicMetaKeeper.getTopicMeta(topicName).getConfig().getMode()
+ return topicMetaKeeper.containsTopicMeta(topicName, isTableModel)
+ ? topicMetaKeeper.getTopicMeta(topicName,
isTableModel).getConfig().getMode()
: null;
} finally {
releaseReadLock();
@@ -240,23 +272,32 @@ public class SubscriptionTopicAgent {
}
public String getTopicOrderMode(final String topicName) {
+ return getTopicOrderMode(topicName, false);
+ }
+
+ public String getTopicOrderMode(final String topicName, final boolean
isTableModel) {
acquireReadLock();
try {
- return
topicMetaKeeper.getTopicMeta(topicName).getConfig().getOrderMode();
+ return topicMetaKeeper.getTopicMeta(topicName,
isTableModel).getConfig().getOrderMode();
} finally {
releaseReadLock();
}
}
public Map<String, TopicConfig> getTopicConfigs(final Set<String>
topicNames) {
+ return getTopicConfigs(topicNames, false);
+ }
+
+ public Map<String, TopicConfig> getTopicConfigs(
+ final Set<String> topicNames, final boolean isTableModel) {
acquireReadLock();
try {
return topicNames.stream()
- .filter(topicMetaKeeper::containsTopicMeta)
+ .filter(topicName -> topicMetaKeeper.containsTopicMeta(topicName,
isTableModel))
.collect(
Collectors.toMap(
topicName -> topicName,
- topicName ->
topicMetaKeeper.getTopicMeta(topicName).getConfig()));
+ topicName -> topicMetaKeeper.getTopicMeta(topicName,
isTableModel).getConfig()));
} finally {
releaseReadLock();
}
@@ -265,7 +306,8 @@ public class SubscriptionTopicAgent {
public TSStatus checkTopicOwner(final ConsumerConfig consumerConfig, final
String topicName) {
acquireReadLock();
try {
- final TopicMeta topicMeta = topicMetaKeeper.getTopicMeta(topicName);
+ final TopicMeta topicMeta =
+ topicMetaKeeper.getTopicMeta(topicName,
isTableModel(consumerConfig));
if (Objects.isNull(topicMeta) || !topicMeta.isOwnerFencingEnabled()) {
return RpcUtils.SUCCESS_STATUS;
}
@@ -340,7 +382,10 @@ public class SubscriptionTopicAgent {
acquireWriteLock();
try {
for (final TTopicOwnerLeaseEntry lease : ownerLeases) {
- final TopicMeta topicMeta =
topicMetaKeeper.getTopicMeta(lease.getTopicName());
+ final TopicMeta topicMeta =
+ lease.isSetIsTableModel()
+ ? topicMetaKeeper.getTopicMeta(lease.getTopicName(),
lease.isIsTableModel())
+ : topicMetaKeeper.getTopicMeta(lease.getTopicName());
if (Objects.isNull(topicMeta)) {
continue;
}
@@ -351,4 +396,8 @@ public class SubscriptionTopicAgent {
releaseWriteLock();
}
}
+
+ private static boolean isTableModel(final ConsumerConfig consumerConfig) {
+ return
SystemConstant.SQL_DIALECT_TABLE_VALUE.equalsIgnoreCase(consumerConfig.getSqlDialect());
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java
index dac6bc5261c..1115c465c15 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java
@@ -102,7 +102,7 @@ public class SubscriptionBroker implements
ISubscriptionBroker {
@Override
public boolean acceptsTopic(final String topicName) {
return Objects.nonNull(topicName)
- && !ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName);
+ && !ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName,
isTableModel());
}
//////////////////////////// provided for SubscriptionBrokerAgent
////////////////////////////
@@ -436,7 +436,7 @@ public class SubscriptionBroker implements
ISubscriptionBroker {
brokerId);
return;
}
- final String topicFormat =
SubscriptionAgent.topic().getTopicFormat(topicName);
+ final String topicFormat =
SubscriptionAgent.topic().getTopicFormat(topicName, isTableModel());
final SubscriptionPrefetchingQueue prefetchingQueue;
if (TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE.equals(topicFormat)) {
prefetchingQueue =
@@ -465,7 +465,7 @@ public class SubscriptionBroker implements
ISubscriptionBroker {
public void updateCompletedTopicNames(final String topicName) {
// mark topic name completed only for topic of snapshot mode
if (SubscriptionAgent.topic()
- .getTopicMode(topicName)
+ .getTopicMode(topicName, isTableModel())
.equals(TopicConstant.MODE_SNAPSHOT_VALUE)) {
completedTopicNames.put(topicName, topicName);
}
@@ -487,7 +487,9 @@ public class SubscriptionBroker implements
ISubscriptionBroker {
prefetchingQueue.markClosed();
// mark topic name completed only for topic of snapshot mode
- if
(SubscriptionAgent.topic().getTopicMode(topicName).equals(TopicConstant.MODE_SNAPSHOT_VALUE)
+ if (SubscriptionAgent.topic()
+ .getTopicMode(topicName, isTableModel())
+ .equals(TopicConstant.MODE_SNAPSHOT_VALUE)
&& prefetchingQueue.isCompleted()) {
completedTopicNames.put(topicName, topicName);
}
@@ -508,6 +510,10 @@ public class SubscriptionBroker implements
ISubscriptionBroker {
brokerId);
}
+ private boolean isTableModel() {
+ return SubscriptionAgent.consumer().isTableModel(brokerId);
+ }
+
@Override
public void unbind(final String topicName) {
unbindPrefetchingQueue(topicName);
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java
index e069b6a51cb..0bfccd3a78b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java
@@ -153,6 +153,10 @@ public abstract class SubscriptionPrefetchingQueue {
return topicName;
}
+ public String getConsumerGroupId() {
+ return brokerId;
+ }
+
protected void cleanUpInternal() {
// clean up events in batches
batches.cleanUp();
@@ -675,7 +679,10 @@ public abstract class SubscriptionPrefetchingQueue {
private boolean canPassThroughTsFile(final PipeTsFileInsertionEvent event) {
return PipeEventCollector.canSkipParsing4TsFileEvent(event)
&& (!event.isTableModelEvent()
- ||
SubscriptionAgent.broker().getColumnFilterMatcher(topicName).isMatchAll());
+ || SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ topicName,
SubscriptionAgent.consumer().isTableModel(brokerId))
+ .isMatchAll());
}
private RetryableState onRetryableTabletInsertionEvent(
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusLogToTabletConverter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusLogToTabletConverter.java
index 317f1f61ee9..0b27de77b12 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusLogToTabletConverter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusLogToTabletConverter.java
@@ -677,7 +677,7 @@ public class ConsensusLogToTabletConverter {
private ColumnFilterMatcher getColumnFilterMatcher() {
return Objects.nonNull(topicName)
- ? SubscriptionAgent.broker().getColumnFilterMatcher(topicName)
+ ? SubscriptionAgent.broker().getColumnFilterMatcher(topicName, true)
: fallbackColumnFilterMatcher;
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusPrefetchingQueue.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusPrefetchingQueue.java
index 879346dad65..f535328cdca 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusPrefetchingQueue.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusPrefetchingQueue.java
@@ -2078,7 +2078,10 @@ public class ConsensusPrefetchingQueue {
SubscriptionPollResponseType.TABLETS.getType(),
payload,
commitContext,
-
SubscriptionAgent.broker().getColumnFilterMatcher(topicName).isTimeSelected(),
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ topicName,
SubscriptionAgent.consumer().isTableModel(consumerGroupId))
+ .isTimeSelected(),
getTimeSelectedByTable(converter.getDatabaseName(), tablets));
// Install the ownership record before exposing the event to concurrent
poll/ack threads.
@@ -2104,7 +2107,9 @@ public class ConsensusPrefetchingQueue {
return Collections.emptyMap();
}
final ColumnFilterMatcher matcher =
- SubscriptionAgent.broker().getColumnFilterMatcher(topicName);
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ topicName,
SubscriptionAgent.consumer().isTableModel(consumerGroupId));
final Map<String, Boolean> tableMap = new HashMap<>();
for (final Tablet tablet : tablets) {
if (Objects.nonNull(tablet) && Objects.nonNull(tablet.getTableName())) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusSubscriptionSetupHandler.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusSubscriptionSetupHandler.java
index 21fbd317241..bb512922248 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusSubscriptionSetupHandler.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/consensus/ConsensusSubscriptionSetupHandler.java
@@ -159,13 +159,15 @@ public class ConsensusSubscriptionSetupHandler {
for (final Map.Entry<String, java.util.Set<String>> groupEntry :
allSubscriptions.entrySet()) {
final String consumerGroupId = groupEntry.getKey();
+ final boolean isTableModel =
SubscriptionAgent.consumer().isTableModel(consumerGroupId);
for (final String topicName : groupEntry.getValue()) {
- if (!isConsensusBasedTopic(topicName)) {
+ if (!isConsensusBasedTopic(topicName, isTableModel)) {
continue;
}
try {
final Map<String, TopicConfig> topicConfigs =
-
SubscriptionAgent.topic().getTopicConfigs(java.util.Collections.singleton(topicName));
+ SubscriptionAgent.topic()
+ .getTopicConfigs(java.util.Collections.singleton(topicName),
isTableModel);
final TopicConfig topicConfig = topicConfigs.get(topicName);
if (topicConfig == null) {
continue;
@@ -292,8 +294,12 @@ public class ConsensusSubscriptionSetupHandler {
}
public static boolean isConsensusBasedTopic(final String topicName) {
+ return isConsensusBasedTopic(topicName, false);
+ }
+
+ public static boolean isConsensusBasedTopic(final String topicName, final
boolean isTableModel) {
try {
- final String topicMode =
SubscriptionAgent.topic().getTopicMode(topicName);
+ final String topicMode =
SubscriptionAgent.topic().getTopicMode(topicName, isTableModel);
final boolean result =
TopicConstant.MODE_INCREMENTAL_VALUE.equalsIgnoreCase(topicMode);
LOGGER.debug(
DataNodePipeMessages.PIPE_LOG_ISCONSENSUSBASEDTOPIC_CHECK_FOR_TOPIC_MODE_RESULT_19EFA0F9,
@@ -311,8 +317,9 @@ public class ConsensusSubscriptionSetupHandler {
}
}
- private static boolean isConsensusBasedTopicRequired(final String topicName)
{
- final String topicMode = SubscriptionAgent.topic().getTopicMode(topicName);
+ private static boolean isConsensusBasedTopicRequired(
+ final String topicName, final boolean isTableModel) {
+ final String topicMode = SubscriptionAgent.topic().getTopicMode(topicName,
isTableModel);
if (Objects.isNull(topicMode)) {
throw new SubscriptionException(
String.format(
@@ -325,6 +332,12 @@ public class ConsensusSubscriptionSetupHandler {
public static void setupConsensusSubscriptions(
final String consumerGroupId, final Set<String> topicNames) {
+ setupConsensusSubscriptions(
+ consumerGroupId, topicNames,
SubscriptionAgent.consumer().isTableModel(consumerGroupId));
+ }
+
+ public static void setupConsensusSubscriptions(
+ final String consumerGroupId, final Set<String> topicNames, final
boolean isTableModel) {
final IConsensus dataRegionConsensus =
DataRegionConsensusImpl.getInstance();
if (!(dataRegionConsensus instanceof IoTConsensus)) {
final String configuredProtocol =
IOTDB_CONFIG.getDataRegionConsensusProtocolClass();
@@ -359,9 +372,10 @@ public class ConsensusSubscriptionSetupHandler {
setupConsensusTopics(
consumerGroupId,
topicNames,
- ConsensusSubscriptionSetupHandler::isConsensusBasedTopicRequired,
+ topicName -> isConsensusBasedTopicRequired(topicName, isTableModel),
topicName ->
- setupConsensusQueueForTopic(consumerGroupId, topicName,
ioTConsensus, commitManager),
+ setupConsensusQueueForTopic(
+ consumerGroupId, topicName, isTableModel, ioTConsensus,
commitManager),
attemptedTopicNames ->
rollbackConsensusSubscriptionSetup(
consumerGroupId, attemptedTopicNames, commitManager,
setupSnapshot));
@@ -456,13 +470,15 @@ public class ConsensusSubscriptionSetupHandler {
private static void setupConsensusQueueForTopic(
final String consumerGroupId,
final String topicName,
+ final boolean isTableModel,
final IoTConsensus ioTConsensus,
final ConsensusSubscriptionCommitManager commitManager) {
final int myNodeId = IOTDB_CONFIG.getDataNodeId();
// Get topic config for building the converter
final Map<String, TopicConfig> topicConfigs =
-
SubscriptionAgent.topic().getTopicConfigs(java.util.Collections.singleton(topicName));
+ SubscriptionAgent.topic()
+ .getTopicConfigs(java.util.Collections.singleton(topicName),
isTableModel);
final TopicConfig topicConfig = topicConfigs.get(topicName);
if (topicConfig == null) {
throw new SubscriptionException(
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTabletEventBatch.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTabletEventBatch.java
index acbc1fc09d8..67321b04651 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTabletEventBatch.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTabletEventBatch.java
@@ -259,7 +259,9 @@ public class SubscriptionPipeTabletEventBatch extends
SubscriptionPipeEventBatch
final TopicConfig topicConfig =
SubscriptionAgent.topic()
-
.getTopicConfigs(Collections.singleton(prefetchingQueue.getTopicName()))
+ .getTopicConfigs(
+ Collections.singleton(prefetchingQueue.getTopicName()),
+
SubscriptionAgent.consumer().isTableModel(prefetchingQueue.getConsumerGroupId()))
.get(prefetchingQueue.getTopicName());
if (Objects.isNull(topicConfig)) {
return false;
@@ -331,7 +333,10 @@ public class SubscriptionPipeTabletEventBatch extends
SubscriptionPipeEventBatch
}
final ColumnFilterMatcher matcher =
-
SubscriptionAgent.broker().getColumnFilterMatcher(prefetchingQueue.getTopicName());
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ prefetchingQueue.getTopicName(),
+
SubscriptionAgent.consumer().isTableModel(prefetchingQueue.getConsumerGroupId()));
final List<Tablet> prunedTablets = new ArrayList<>(tablets.right.size());
for (final Tablet tablet : tablets.right) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTsFileEventBatch.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTsFileEventBatch.java
index a8735b59edd..7a27f464ebb 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTsFileEventBatch.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/batch/SubscriptionPipeTsFileEventBatch.java
@@ -158,7 +158,10 @@ public class SubscriptionPipeTsFileEventBatch extends
SubscriptionPipeEventBatch
private Tablet pruneTableModelTablet(final String databaseName, final Tablet
tablet) {
final ColumnFilterMatcher matcher =
-
SubscriptionAgent.broker().getColumnFilterMatcher(prefetchingQueue.getTopicName());
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ prefetchingQueue.getTopicName(),
+
SubscriptionAgent.consumer().isTableModel(prefetchingQueue.getConsumerGroupId()));
return TabletColumnPruner.pruneTableModelTablet(tablet, databaseName,
matcher);
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTabletResponse.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTabletResponse.java
index 91c136a4f42..1392c0cbb28 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTabletResponse.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTabletResponse.java
@@ -96,7 +96,10 @@ public class SubscriptionEventTabletResponse extends
SubscriptionEventExtendable
this.commitContext = commitContext;
this.rootCommitContext = rootCommitContext;
this.columnFilterMatcher =
-
SubscriptionAgent.broker().getColumnFilterMatcher(queue.getTopicName());
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ queue.getTopicName(),
+
SubscriptionAgent.consumer().isTableModel(queue.getConsumerGroupId()));
init();
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTsFileResponse.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTsFileResponse.java
index dd047384ff5..9ddeca25c4c 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTsFileResponse.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/response/SubscriptionEventTsFileResponse.java
@@ -79,7 +79,10 @@ public class SubscriptionEventTsFileResponse extends
SubscriptionEventExtendable
this.databaseName = databaseName;
this.commitContext = commitContext;
this.columnFilterMatcher =
-
SubscriptionAgent.broker().getColumnFilterMatcher(commitContext.getTopicName());
+ SubscriptionAgent.broker()
+ .getColumnFilterMatcher(
+ commitContext.getTopicName(),
+
SubscriptionAgent.consumer().isTableModel(commitContext.getConsumerGroupId()));
this.timeSelectedByTable =
columnFilterMatcher.getTimeSelectedByTable(databaseName);
init();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java
index c7c791ff128..268bb8df119 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java
@@ -373,7 +373,8 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
// fetch subscribed topics
final Map<String, TopicConfig> topics =
- SubscriptionAgent.topic().getTopicConfigs(subscribedTopicNames);
+ SubscriptionAgent.topic()
+ .getTopicConfigs(subscribedTopicNames,
isTableModel(consumerConfig));
// fetch available endpoints
final Map<Integer, TEndPoint> endPoints = new HashMap<>();
@@ -462,7 +463,8 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
.getTopicConfigs(
SubscriptionAgent.consumer()
.getTopicNamesSubscribedByConsumer(
- consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId())));
+ consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId()),
+ isTableModel(consumerConfig)));
}
private TPipeSubscribeResp handlePipeSubscribeUnsubscribe(final
PipeSubscribeUnsubscribeReq req) {
@@ -508,7 +510,8 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
.getTopicConfigs(
SubscriptionAgent.consumer()
.getTopicNamesSubscribedByConsumer(
- consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId())));
+ consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId()),
+ isTableModel(consumerConfig)));
}
private TPipeSubscribeResp handlePipeSubscribePoll(final
PipeSubscribePollReq req) {
@@ -658,7 +661,7 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
SubscriptionPrefetchingQueue.generatePrefetchingQueueId(
commitContext.getConsumerGroupId(),
commitContext.getTopicName());
if
(ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
- commitContext.getTopicName())) {
+ commitContext.getTopicName(),
isTableModel(consumerConfig))) {
ConsensusSubscriptionPrefetchingQueueMetrics.getInstance()
.mark(queueId, commitContext.getRegionId(), size);
} else {
@@ -1069,7 +1072,8 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
.getTopicConfigs(
SubscriptionAgent.consumer()
.getTopicNamesSubscribedByConsumer(
- consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId()));
+ consumerConfig.getConsumerGroupId(),
consumerConfig.getConsumerId()),
+ isTableModel(consumerConfig));
// fetch topics should be unsubscribed
final List<String> topicNamesToUnsubscribe =
@@ -1274,4 +1278,8 @@ public class SubscriptionReceiverV1 implements
SubscriptionReceiver {
SubscriptionConfig.getInstance().getSubscriptionDefaultTimeoutInMs(),
consumerConfig.getHeartbeatIntervalMs() *
HEARTBEAT_TIMEOUT_MULTIPLIER);
}
+
+ private static boolean isTableModel(final ConsumerConfig consumerConfig) {
+ return
SQL_DIALECT_TABLE_VALUE.equalsIgnoreCase(consumerConfig.getSqlDialect());
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtask.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtask.java
index 454ce2b80b6..6c26e0fab10 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtask.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtask.java
@@ -118,6 +118,7 @@ public class SubscriptionSinkSubtask extends
PipeSinkSubtask {
}
private boolean isConsensusDrivenTopic() {
- return ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName);
+ return ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName, SubscriptionAgent.consumer().isTableModel(consumerGroupId));
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtaskLifeCycle.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtaskLifeCycle.java
index 3a0f52e3f99..2fb50ec4a16 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtaskLifeCycle.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionSinkSubtaskLifeCycle.java
@@ -53,7 +53,9 @@ public class SubscriptionSinkSubtaskLifeCycle extends
PipeSinkSubtaskLifeCycle {
if (registeredTaskCount == 0) {
if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
- ((SubscriptionSinkSubtask) subtask).getTopicName())) {
+ ((SubscriptionSinkSubtask) subtask).getTopicName(),
+ SubscriptionAgent.consumer()
+ .isTableModel(((SubscriptionSinkSubtask)
subtask).getConsumerGroupId()))) {
SubscriptionAgent.broker().bindPrefetchingQueue((SubscriptionSinkSubtask)
subtask);
}
executor.register(subtask);
@@ -103,7 +105,8 @@ public class SubscriptionSinkSubtaskLifeCycle extends
PipeSinkSubtaskLifeCycle {
// when dropping the subscription.
final String consumerGroupId = ((SubscriptionSinkSubtask)
subtask).getConsumerGroupId();
final String topicName = ((SubscriptionSinkSubtask)
subtask).getTopicName();
- if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(topicName)) {
+ if (!ConsensusSubscriptionSetupHandler.isConsensusBasedTopic(
+ topicName,
SubscriptionAgent.consumer().isTableModel(consumerGroupId))) {
SubscriptionAgent.broker().unbindPrefetchingQueue(consumerGroupId,
topicName);
}
}
diff --git
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/PipeMessages.java
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/PipeMessages.java
index 010cf08f196..e8646e005a3 100644
---
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/PipeMessages.java
+++
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/PipeMessages.java
@@ -925,6 +925,7 @@ public final class PipeMessages {
public static final String
EXCEPTION_FAILED_REMOVE_SUBSCRIPTION_CONSUMER_GROUP_META_CONSUMER_ARG_DOES_NOT_75C319C3
=
"Failed to remove subscription from consumer group meta: consumer %s
does not exist in"
+ " consumer group %s";
+ public static final String
EXCEPTION_FAILED_TO_CREATE_CONSUMER_ARG_BECAUSE_INCONSISTENT_SQL_DIALECT_UNDER_THE_SAME_CONSUMER_GROUP_EXPECTED_ARG_ACTUAL_ARG_A7DA3FB9
= "Failed to create consumer %s because inconsistent sql dialect under the
same consumer group, expected %s, actual %s";
public static final String
EXCEPTION_PATH_PATTERN_ARG_NOT_VALID_SOURCE_ONLY_PREFIX_FULL_PATH_784778B8 =
"The path pattern %s is not valid for the source. Only prefix or full path is
allowed.";
public static final String
EXCEPTION_CAPTURE_TREE_CAN_NOT_SPECIFIED_FALSE_DOUBLE_LIVING_ENABLED_29A08445 =
"capture.tree can not be specified to false when double living is enabled";
public static final String
EXCEPTION_CAPTURE_TABLE_CAN_NOT_SPECIFIED_FALSE_DOUBLE_LIVING_ENABLED_8AEB8F7B
= "capture.table can not be specified to false when double living is enabled";
diff --git
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/PipeMessages.java
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/PipeMessages.java
index 8ea19a43f89..c6da4c6082e 100644
---
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/PipeMessages.java
+++
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/PipeMessages.java
@@ -894,6 +894,7 @@ public final class PipeMessages {
public static final String
EXCEPTION_INVALID_REGION_PROGRESS_VALUE_LENGTH_6192D17F = "region progress
value 长度无效:%d";
public static final String
EXCEPTION_FAILED_ADD_SUBSCRIPTION_CONSUMER_GROUP_META_CONSUMER_ARG_DOES_NOT_EF08EE87
= "添加 subscription 到 consumer group meta 失败:consumer %s 不存在于 consumer group
%s";
public static final String
EXCEPTION_FAILED_REMOVE_SUBSCRIPTION_CONSUMER_GROUP_META_CONSUMER_ARG_DOES_NOT_75C319C3
= "从 consumer group meta 移除 subscription 失败:consumer %s 不存在于 consumer group
%s";
+ public static final String
EXCEPTION_FAILED_TO_CREATE_CONSUMER_ARG_BECAUSE_INCONSISTENT_SQL_DIALECT_UNDER_THE_SAME_CONSUMER_GROUP_EXPECTED_ARG_ACTUAL_ARG_A7DA3FB9
= "创建 consumer %s 失败,因为同一 consumer group 下的 SQL dialect 不一致,预期为 %s,实际为 %s";
public static final String
EXCEPTION_PATH_PATTERN_ARG_NOT_VALID_SOURCE_ONLY_PREFIX_FULL_PATH_784778B8 =
"路径模式 %s 对 source 无效。仅允许前缀或完整路径。";
public static final String
EXCEPTION_CAPTURE_TREE_CAN_NOT_SPECIFIED_FALSE_DOUBLE_LIVING_ENABLED_29A08445 =
"启用 double living 时,capture.tree 不能指定为 false";
public static final String
EXCEPTION_CAPTURE_TABLE_CAN_NOT_SPECIFIED_FALSE_DOUBLE_LIVING_ENABLED_8AEB8F7B
= "启用 double living 时,capture.table 不能指定为 false";
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java
index af07dffa2cc..c6153db8668 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.commons.subscription.meta.consumer;
import org.apache.iotdb.commons.i18n.PipeMessages;
+import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
import org.apache.iotdb.rpc.subscription.exception.SubscriptionException;
import org.apache.thrift.annotation.Nullable;
@@ -163,6 +164,24 @@ public class ConsumerGroupMeta {
LOGGER.warn(exceptionMessage);
throw new SubscriptionException(exceptionMessage);
}
+
+ final String expectedSqlDialect =
existedConsumerMeta.getConfig().getSqlDialect();
+ final String actualSqlDialect = consumerMeta.getConfig().getSqlDialect();
+ final boolean isExpectedTableModel =
+
SystemConstant.SQL_DIALECT_TABLE_VALUE.equalsIgnoreCase(expectedSqlDialect);
+ final boolean isActualTableModel =
+
SystemConstant.SQL_DIALECT_TABLE_VALUE.equalsIgnoreCase(actualSqlDialect);
+ if (isExpectedTableModel != isActualTableModel) {
+ final String exceptionMessage =
+ String.format(
+ PipeMessages
+
.EXCEPTION_FAILED_TO_CREATE_CONSUMER_ARG_BECAUSE_INCONSISTENT_SQL_DIALECT_UNDER_THE_SAME_CONSUMER_GROUP_EXPECTED_ARG_ACTUAL_ARG_A7DA3FB9,
+ consumerMeta.getConsumerId(),
+ expectedSqlDialect,
+ actualSqlDialect);
+ LOGGER.warn(exceptionMessage);
+ throw new SubscriptionException(exceptionMessage);
+ }
}
public void addConsumer(final ConsumerMeta consumerMeta) {
@@ -196,6 +215,15 @@ public class ConsumerGroupMeta {
return consumerIdToConsumerMeta.get(consumerId);
}
+ public boolean visibleUnder(final boolean isTableModel) {
+ if (consumerIdToConsumerMeta.isEmpty()) {
+ return false;
+ }
+ final String sqlDialect =
+
consumerIdToConsumerMeta.values().iterator().next().getConfig().getSqlDialect();
+ return isTableModel ==
SystemConstant.SQL_DIALECT_TABLE_VALUE.equalsIgnoreCase(sqlDialect);
+ }
+
////////////////////////// subscription //////////////////////////
/** Get all topic names subscribed by this consumer group. */
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMetaKeeper.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMetaKeeper.java
index 34dbbbd761d..330ae2cf9ee 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMetaKeeper.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMetaKeeper.java
@@ -131,6 +131,17 @@ public class ConsumerGroupMetaKeeper {
.collect(Collectors.toSet());
}
+ public Set<String> getSubscribedConsumerGroupIds(
+ final String topicName, final boolean isTableModel) {
+ return consumerGroupIdToConsumerGroupMetaMap.entrySet().stream()
+ .filter(
+ entry ->
+ entry.getValue().visibleUnder(isTableModel)
+ &&
entry.getValue().isTopicSubscribedByConsumerGroup(topicName))
+ .map(Entry::getKey)
+ .collect(Collectors.toSet());
+ }
+
public boolean isTopicSubscribedByConsumerGroup(
final String topicName, final String consumerGroupId) {
return consumerGroupIdToConsumerGroupMetaMap.containsKey(consumerGroupId)
@@ -144,6 +155,15 @@ public class ConsumerGroupMetaKeeper {
.anyMatch(meta -> meta.isTopicSubscribedByConsumerGroup(topicName));
}
+ public boolean isTopicSubscribedByConsumerGroup(
+ final String topicName, final boolean isTableModel) {
+ return consumerGroupIdToConsumerGroupMetaMap.values().stream()
+ .anyMatch(
+ meta ->
+ meta.visibleUnder(isTableModel)
+ && meta.isTopicSubscribedByConsumerGroup(topicName));
+ }
+
///////////////////////////////// Snapshot
/////////////////////////////////
public void processTakeSnapshot(FileOutputStream fileOutputStream) throws
IOException {
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerMeta.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerMeta.java
index 75cca9ccbcd..006bd9b39cb 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerMeta.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerMeta.java
@@ -74,6 +74,10 @@ public class ConsumerMeta {
return Objects.nonNull(getEncryptedPassword()) ? getEncryptedPassword() :
getPassword();
}
+ public ConsumerConfig getConfig() {
+ return config;
+ }
+
public ByteBuffer serialize() throws IOException {
PublicBAOS byteArrayOutputStream = new PublicBAOS();
DataOutputStream outputStream = new
DataOutputStream(byteArrayOutputStream);
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMetaKeeper.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMetaKeeper.java
index 741f7c38058..07cd7465681 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMetaKeeper.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMetaKeeper.java
@@ -61,11 +61,16 @@ public class TopicMetaKeeper {
///////////////////////////////// TopicMeta
/////////////////////////////////
public void addTopicMeta(String topicName, TopicMeta topicMeta) {
- topicNameToTopicMetaMap.put(topicName, topicMeta);
+ topicNameToTopicMetaMap.put(generateTopicMetaKeeperKey(topicMeta),
topicMeta);
}
public TopicMeta getTopicMeta(String topicName) {
- return topicNameToTopicMetaMap.get(topicName);
+ final TopicMeta treeTopicMeta = getTopicMeta(topicName, false);
+ return Objects.nonNull(treeTopicMeta) ? treeTopicMeta :
getTopicMeta(topicName, true);
+ }
+
+ public TopicMeta getTopicMeta(String topicName, boolean isTableModel) {
+ return topicNameToTopicMetaMap.get(generateTopicMetaKeeperKey(topicName,
isTableModel));
}
public Iterable<TopicMeta> getAllTopicMeta() {
@@ -73,19 +78,22 @@ public class TopicMetaKeeper {
}
public void removeTopicMeta(String topicName) {
- topicNameToTopicMetaMap.remove(topicName);
+ final String treeModelKey = generateTopicMetaKeeperKey(topicName, false);
+ if (topicNameToTopicMetaMap.remove(treeModelKey) == null) {
+ topicNameToTopicMetaMap.remove(generateTopicMetaKeeperKey(topicName,
true));
+ }
+ }
+
+ public void removeTopicMeta(String topicName, boolean isTableModel) {
+ topicNameToTopicMetaMap.remove(generateTopicMetaKeeperKey(topicName,
isTableModel));
}
public boolean containsTopicMeta(String topicName) {
- return topicNameToTopicMetaMap.containsKey(topicName);
+ return containsTopicMeta(topicName, false) || containsTopicMeta(topicName,
true);
}
public boolean containsTopicMeta(String topicName, boolean isTableModel) {
- TopicMeta topicMeta = topicNameToTopicMetaMap.get(topicName);
- if (Objects.isNull(topicMeta)) {
- return false;
- }
- return topicMeta.visibleUnder(isTableModel);
+ return
topicNameToTopicMetaMap.containsKey(generateTopicMetaKeeperKey(topicName,
isTableModel));
}
public void clear() {
@@ -101,7 +109,7 @@ public class TopicMetaKeeper {
public void processTakeSnapshot(FileOutputStream fileOutputStream) throws
IOException {
ReadWriteIOUtils.write(topicNameToTopicMetaMap.size(), fileOutputStream);
for (Map.Entry<String, TopicMeta> entry :
topicNameToTopicMetaMap.entrySet()) {
- ReadWriteIOUtils.write(entry.getKey(), fileOutputStream);
+ ReadWriteIOUtils.write(entry.getValue().getTopicName(),
fileOutputStream);
entry.getValue().serialize(fileOutputStream);
}
}
@@ -112,7 +120,8 @@ public class TopicMetaKeeper {
final int size = ReadWriteIOUtils.readInt(fileInputStream);
for (int i = 0; i < size; i++) {
final String topicName = ReadWriteIOUtils.readString(fileInputStream);
- topicNameToTopicMetaMap.put(topicName,
TopicMeta.deserialize(fileInputStream));
+ final TopicMeta topicMeta = TopicMeta.deserialize(fileInputStream);
+ topicNameToTopicMetaMap.put(generateTopicMetaKeeperKey(topicMeta),
topicMeta);
}
}
@@ -139,4 +148,15 @@ public class TopicMetaKeeper {
public String toString() {
return "TopicMetaKeeper{" + "topicNameToTopicMetaMap=" +
topicNameToTopicMetaMap + '}';
}
+
+ ///////////////////////////////// Tree & Table Isolation
/////////////////////////////////
+
+ private static String generateTopicMetaKeeperKey(final TopicMeta topicMeta) {
+ return generateTopicMetaKeeperKey(topicMeta.getTopicName(),
topicMeta.visibleUnderTableModel());
+ }
+
+ private static String generateTopicMetaKeeperKey(
+ final String topicName, final boolean isTableModel) {
+ return (isTableModel ? "table:" : "tree:") + topicName;
+ }
}
diff --git
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/consumer/ConsumerGroupDeSerTest.java
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/consumer/ConsumerGroupDeSerTest.java
index 9ef7191ba66..fc8d0122b2b 100644
---
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/consumer/ConsumerGroupDeSerTest.java
+++
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/consumer/ConsumerGroupDeSerTest.java
@@ -19,8 +19,10 @@
package org.apache.iotdb.commons.subscription.consumer;
+import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
import org.apache.iotdb.commons.subscription.meta.consumer.ConsumerGroupMeta;
import org.apache.iotdb.commons.subscription.meta.consumer.ConsumerMeta;
+import org.apache.iotdb.rpc.subscription.config.ConsumerConstant;
import org.apache.iotdb.rpc.subscription.exception.SubscriptionException;
import org.junit.Assert;
@@ -89,4 +91,27 @@ public class ConsumerGroupDeSerTest {
consumerGroupMeta.getConsumersSubscribingTopic("test_topic").contains("test_consumer1"));
Assert.assertTrue(copiedConsumerGroupMeta.getConsumersSubscribingTopic("test_topic").isEmpty());
}
+
+ @Test
+ public void testConsumerGroupShouldRejectMixedSqlDialects() {
+ final Map<String, String> treeConsumerAttributes = new HashMap<>();
+ treeConsumerAttributes.put("username", "user");
+ treeConsumerAttributes.put("password", "password");
+ treeConsumerAttributes.put(
+ ConsumerConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TREE_VALUE);
+
+ final Map<String, String> tableConsumerAttributes = new
HashMap<>(treeConsumerAttributes);
+ tableConsumerAttributes.put(
+ ConsumerConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TABLE_VALUE);
+
+ final ConsumerGroupMeta consumerGroupMeta =
+ new ConsumerGroupMeta(
+ "test_consumer_group", 1, new ConsumerMeta("tree_consumer", 1,
treeConsumerAttributes));
+
+ Assert.assertThrows(
+ SubscriptionException.class,
+ () ->
+ consumerGroupMeta.checkAuthorityBeforeJoinConsumerGroup(
+ new ConsumerMeta("table_consumer", 2,
tableConsumerAttributes)));
+ }
}
diff --git
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/topic/TopicMetaKeeperTest.java
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/topic/TopicMetaKeeperTest.java
new file mode 100644
index 00000000000..00592403109
--- /dev/null
+++
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/subscription/topic/TopicMetaKeeperTest.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.commons.subscription.topic;
+
+import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
+import org.apache.iotdb.commons.subscription.meta.topic.TopicMeta;
+import org.apache.iotdb.commons.subscription.meta.topic.TopicMetaKeeper;
+
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+
+public class TopicMetaKeeperTest {
+
+ @Test
+ public void testSameNameTreeAndTableTopicsCanCoexist() {
+ final String topicName = "topic";
+ final TopicMeta treeTopicMeta =
+ new TopicMeta(
+ topicName,
+ 1L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TREE_VALUE));
+ final TopicMeta tableTopicMeta =
+ new TopicMeta(
+ topicName,
+ 2L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TABLE_VALUE));
+ final TopicMetaKeeper keeper = new TopicMetaKeeper();
+
+ keeper.addTopicMeta(topicName, treeTopicMeta);
+ keeper.addTopicMeta(topicName, tableTopicMeta);
+
+ Assert.assertSame(treeTopicMeta, keeper.getTopicMeta(topicName, false));
+ Assert.assertSame(tableTopicMeta, keeper.getTopicMeta(topicName, true));
+ Assert.assertSame(treeTopicMeta, keeper.getTopicMeta(topicName));
+ Assert.assertEquals(2, sizeOf(keeper.getAllTopicMeta()));
+
+ keeper.removeTopicMeta(topicName, false);
+ Assert.assertFalse(keeper.containsTopicMeta(topicName, false));
+ Assert.assertTrue(keeper.containsTopicMeta(topicName, true));
+ Assert.assertSame(tableTopicMeta, keeper.getTopicMeta(topicName));
+ }
+
+ @Test
+ public void testSnapshotPreservesSameNameTreeAndTableTopics() throws
Exception {
+ final String topicName = "topic";
+ final TopicMetaKeeper keeper = new TopicMetaKeeper();
+ keeper.addTopicMeta(
+ topicName,
+ new TopicMeta(
+ topicName,
+ 1L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TREE_VALUE)));
+ keeper.addTopicMeta(
+ topicName,
+ new TopicMeta(
+ topicName,
+ 2L,
+ Collections.singletonMap(
+ SystemConstant.SQL_DIALECT_KEY,
SystemConstant.SQL_DIALECT_TABLE_VALUE)));
+
+ final Path snapshotFile = Files.createTempFile("topic-meta-keeper",
".snapshot");
+ try {
+ try (final FileOutputStream outputStream = new
FileOutputStream(snapshotFile.toFile())) {
+ keeper.processTakeSnapshot(outputStream);
+ }
+
+ try (final FileInputStream inputStream = new
FileInputStream(snapshotFile.toFile())) {
+ Assert.assertEquals(2, ReadWriteIOUtils.readInt(inputStream));
+ for (int i = 0; i < 2; i++) {
+ Assert.assertEquals(topicName,
ReadWriteIOUtils.readString(inputStream));
+ TopicMeta.deserialize(inputStream);
+ }
+ }
+
+ final TopicMetaKeeper restoredKeeper = new TopicMetaKeeper();
+ try (final FileInputStream inputStream = new
FileInputStream(snapshotFile.toFile())) {
+ restoredKeeper.processLoadSnapshot(inputStream);
+ }
+ Assert.assertNotNull(restoredKeeper.getTopicMeta(topicName, false));
+ Assert.assertNotNull(restoredKeeper.getTopicMeta(topicName, true));
+ } finally {
+ Files.deleteIfExists(snapshotFile);
+ }
+ }
+
+ private static int sizeOf(final Iterable<TopicMeta> topicMetas) {
+ int size = 0;
+ for (final TopicMeta ignored : topicMetas) {
+ size++;
+ }
+ return size;
+ }
+}
diff --git a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
index cc5e0b7dc25..ea0f9467a2a 100644
--- a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
+++ b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
@@ -567,6 +567,7 @@ struct TPushTopicMetaReq {
struct TPushSingleTopicMetaReq {
1: optional binary topicMeta // Should not set both to null.
2: optional string topicNameToDrop
+ 3: optional bool isTableModel
}
struct TPushMultiTopicMetaReq {
@@ -594,6 +595,7 @@ struct TTopicOwnerLeaseEntry {
2: required string ownerId
3: required i64 ownerEpoch
4: required i64 leaseRemainingMs
+ 5: optional bool isTableModel
}
struct TPushTopicOwnerLeaseReq {