Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5e9353f
Support internal sessions through inherited client RPC services
shuwenwei Nov 4, 2026
a7af2c8
Support internal table subscription pull consumers
shuwenwei Nov 4, 2026
282fc56
Support internal table session pools
shuwenwei Nov 4, 2026
2d3bdcd
Revert inherited internal client RPC implementation
shuwenwei Nov 5, 2026
e908971
Use multiplexed client RPC service on internal endpoint
shuwenwei Nov 5, 2026
d012cc0
Fix Spotless formatting for internal session builders
shuwenwei Nov 5, 2026
1f1971c
Fix SessionPool internal session type
shuwenwei Nov 5, 2026
f9e559a
Fix internal login compatibility with baseline
shuwenwei Nov 5, 2026
62d3824
Test internal client RPC routing and SSL propagation
shuwenwei Nov 5, 2026
ea7d8d1
Remove unavailable test dependencies from subscription SSL test
shuwenwei Nov 5, 2026
fabd1e8
Move internal session builders to node commons
shuwenwei Nov 6, 2026
f1a7762
Refine internal session extension points
shuwenwei Nov 6, 2026
5760a36
Use session hooks for internal pool behavior
shuwenwei Nov 6, 2026
9af3ad0
Simplify internal node supplier ownership
shuwenwei Nov 6, 2026
7be93fc
Support configurable internal session endpoints
shuwenwei Nov 6, 2026
4a49e61
Use getter hook for RPC service name
shuwenwei Nov 6, 2026
8ac650d
Use node initialization hooks for internal sessions
shuwenwei Nov 6, 2026
78e7151
Refine internal session pool construction
shuwenwei Nov 6, 2026
7f26457
Use overrides for internal session pool initialization
shuwenwei Nov 6, 2026
20252f8
Support custom node suppliers in internal session pools
shuwenwei Nov 6, 2026
568497b
Restore table session pool inheritance for internal pools
shuwenwei Nov 6, 2026
1dd4f91
Use tree session builder for internal table pool sessions
shuwenwei Nov 6, 2026
858fd6e
Use internal RPC endpoints for redirects
shuwenwei Nov 6, 2026
e22fd5b
Refine internal session auto-fetch requirements
shuwenwei Nov 6, 2026
1ec246e
Refine internal session lifecycle and authorization
shuwenwei Nov 6, 2026
405844d
Merge branch 'iotdb_master' into feature/internal-rpc-inherit-client-rpc
shuwenwei Nov 6, 2026
2c33cab
Narrow database internal session propagation
shuwenwei Nov 6, 2026
415d5e6
Preserve internal session flags during load conversion
shuwenwei Nov 6, 2026
d608659
Remove unused session message constants
shuwenwei Nov 6, 2026
db18fe0
spotless
shuwenwei Nov 6, 2026
9824dfa
Declare isession dependency in node commons
shuwenwei Nov 6, 2026
1ff0e4f
Remove internal RPC flag from local client sessions
shuwenwei Nov 6, 2026
e76cc51
Seed table region before redirect test discovery
shuwenwei Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* 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.it.utils;

import org.apache.iotdb.common.rpc.thrift.TEndPoint;
import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
import org.apache.iotdb.isession.INodeSupplier;
import org.apache.iotdb.isession.ITableSession;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper;
import org.apache.iotdb.rpc.UrlUtils;
import org.apache.iotdb.session.DummyNodesSupplier;
import org.apache.iotdb.session.Session;

import org.apache.tsfile.read.common.Field;
import org.apache.tsfile.read.common.RowRecord;
import org.awaitility.Awaitility;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import static org.junit.Assert.assertFalse;

public final class InternalSessionITUtils {

private static final String DATA_REGION = "DataRegion";
private static final String LEADER = "Leader";

private InternalSessionITUtils() {}

public static TEndPoint getInternalEndPoint(final DataNodeWrapper dataNode) {
return new TEndPoint(dataNode.getInternalAddress(), dataNode.getInternalPort());
}

public static String getEndPointUrl(final TEndPoint endPoint) {
return UrlUtils.convertTEndPointIpv4AndIpv6Url(endPoint);
}

public static List<TEndPoint> getInternalEndPoints() {
final List<TEndPoint> endPoints = new ArrayList<>();
for (final DataNodeWrapper dataNode : EnvFactory.getEnv().getDataNodeWrapperList()) {
endPoints.add(getInternalEndPoint(dataNode));
}
return endPoints;
}

public static INodeSupplier createInternalNodeSupplier() {
return new DummyNodesSupplier(getInternalEndPoints());
}

public static TEndPoint findNonLeaderInternalEndPoint(
final Set<TEndPoint> leaderInternalEndPoints) {
for (final TEndPoint endPoint : getInternalEndPoints()) {
if (!leaderInternalEndPoints.contains(endPoint)) {
return endPoint;
}
}
throw new IllegalStateException("No non-leader DataNode is available");
}

public static Set<TEndPoint> awaitDataRegionLeaderInternalEndPoints(
final Session session, final String database) {
final AtomicReference<Set<TEndPoint>> leaderEndPoints =
new AtomicReference<>(Collections.emptySet());
Awaitility.await()
.atMost(30, TimeUnit.SECONDS)
.untilAsserted(
() -> {
final Set<TEndPoint> currentLeaderEndPoints =
queryDataRegionLeaderInternalEndPoints(session, database);
assertFalse(currentLeaderEndPoints.isEmpty());
leaderEndPoints.set(currentLeaderEndPoints);
});
return leaderEndPoints.get();
}

public static Session getUnderlyingSession(final ITableSession tableSession)
throws ReflectiveOperationException {
Class<?> currentClass = tableSession.getClass();
while (currentClass != null) {
for (final java.lang.reflect.Field field : currentClass.getDeclaredFields()) {
if (Session.class.equals(field.getType())) {
field.setAccessible(true);
return (Session) field.get(tableSession);
}
}
currentClass = currentClass.getSuperclass();
}
throw new NoSuchFieldException("Session field not found in " + tableSession.getClass());
}

@SuppressWarnings("unchecked")
public static <T> T getSessionField(final Session session, final String fieldName)
throws ReflectiveOperationException {
final java.lang.reflect.Field field = Session.class.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(session);
}

private static Set<TEndPoint> queryDataRegionLeaderInternalEndPoints(
final Session session, final String database) throws Exception {
final Set<TEndPoint> leaderEndPoints = new HashSet<>();
try (SessionDataSet dataSet = session.executeQueryStatement("SHOW REGIONS")) {
final List<String> columnNames = dataSet.getColumnNames();
final int typeIndex = columnNames.indexOf(ColumnHeaderConstant.TYPE);
final int databaseIndex = columnNames.indexOf(ColumnHeaderConstant.DATABASE);
final int rpcAddressIndex = columnNames.indexOf(ColumnHeaderConstant.RPC_ADDRESS);
final int rpcPortIndex = columnNames.indexOf(ColumnHeaderConstant.RPC_PORT);
final int roleIndex = columnNames.indexOf(ColumnHeaderConstant.ROLE);

while (dataSet.hasNext()) {
final RowRecord rowRecord = dataSet.next();
if (!DATA_REGION.equals(getString(rowRecord, typeIndex))
|| !database.equals(getString(rowRecord, databaseIndex))
|| !LEADER.equalsIgnoreCase(getString(rowRecord, roleIndex))) {
continue;
}
final String rpcAddress = getString(rowRecord, rpcAddressIndex);
final int rpcPort = rowRecord.getFields().get(rpcPortIndex).getIntV();
for (final DataNodeWrapper dataNode : EnvFactory.getEnv().getDataNodeWrapperList()) {
if (dataNode.getIp().equals(rpcAddress) && dataNode.getPort() == rpcPort) {
leaderEndPoints.add(getInternalEndPoint(dataNode));
break;
}
}
}
}
return leaderEndPoints;
}

private static String getString(final RowRecord rowRecord, final int index) {
final Field field = rowRecord.getFields().get(index);
return field == null ? null : field.getStringValue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* 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.relational.it.session;

import org.apache.iotdb.commons.client.internal.session.InternalTableSessionBuilder;
import org.apache.iotdb.commons.client.internal.session.InternalTableSessionPoolBuilder;
import org.apache.iotdb.isession.ITableSession;
import org.apache.iotdb.isession.SessionConfig;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.pool.ITableSessionPool;
import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper;
import org.apache.iotdb.it.framework.IoTDBTestRunner;
import org.apache.iotdb.it.utils.InternalSessionITUtils;
import org.apache.iotdb.itbase.category.TableClusterIT;
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;

import org.apache.tsfile.enums.ColumnCategory;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.IMeasurementSchema;
import org.apache.tsfile.write.schema.MeasurementSchema;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(IoTDBTestRunner.class)
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
public class InternalTableSessionIT {

private static final String DATABASE = "internal_table_session_it";
private static final String TABLE = "t";

@Before
public void setUp() throws Exception {
EnvFactory.getEnv().initClusterEnvironment();
}

@After
public void tearDown() throws Exception {
EnvFactory.getEnv().cleanClusterEnvironment();
}

@Test
public void testInternalTableSessionUsesInternalPort() throws Exception {
final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
try (ITableSession session =
new InternalTableSessionBuilder(InternalSessionITUtils.createInternalNodeSupplier())
.nodeUrls(
Collections.singletonList(
InternalSessionITUtils.getEndPointUrl(
InternalSessionITUtils.getInternalEndPoint(dataNode))))
.username(SessionConfig.DEFAULT_USER)
.password(SessionConfig.DEFAULT_PASSWORD)
.build()) {
session.executeNonQueryStatement("CREATE DATABASE " + DATABASE);
try {
createTableAndInsert(session);
assertTableValue(session);
} finally {
session.executeNonQueryStatement("DROP DATABASE " + DATABASE);
}
}
}

@Test
public void testInternalTableSessionPoolUsesInternalPort() throws Exception {
final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
try (ITableSessionPool sessionPool =
new InternalTableSessionPoolBuilder(InternalSessionITUtils.createInternalNodeSupplier())
.nodeUrls(
Collections.singletonList(
InternalSessionITUtils.getEndPointUrl(
InternalSessionITUtils.getInternalEndPoint(dataNode))))
.user(SessionConfig.DEFAULT_USER)
.password(SessionConfig.DEFAULT_PASSWORD)
.maxSize(1)
.build()) {
try (ITableSession session = sessionPool.getSession()) {
session.executeNonQueryStatement("CREATE DATABASE " + DATABASE);
try {
createTableAndInsert(session);
assertTableValue(session);
} finally {
session.executeNonQueryStatement("DROP DATABASE " + DATABASE);
}
}
}
}

@Test
public void testInternalTableSessionWithoutAutoFetchUsesConfiguredInternalEndpoint()
throws Exception {
final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
try (ITableSession session =
new InternalTableSessionBuilder()
.enableAutoFetch(false)
.nodeUrls(
Collections.singletonList(
InternalSessionITUtils.getEndPointUrl(
InternalSessionITUtils.getInternalEndPoint(dataNode))))
.username(SessionConfig.DEFAULT_USER)
.password(SessionConfig.DEFAULT_PASSWORD)
.build()) {
session.executeNonQueryStatement("CREATE DATABASE " + DATABASE);
try {
session.executeNonQueryStatement(
"CREATE TABLE " + DATABASE + "." + TABLE + " (tag1 STRING TAG, value INT64 FIELD)");
} finally {
session.executeNonQueryStatement("DROP DATABASE " + DATABASE);
}
}
}

private static void createTableAndInsert(final ITableSession session) throws Exception {
session.executeNonQueryStatement("USE " + DATABASE);
session.executeNonQueryStatement(
"CREATE TABLE " + TABLE + " (tag1 STRING TAG, value INT64 FIELD)");
session.insert(createTablet());
session.insert(createTablet());
}

private static void assertTableValue(final ITableSession session) throws Exception {
try (SessionDataSet dataSet =
session.executeQueryStatement("SELECT value FROM " + DATABASE + "." + TABLE)) {
assertTrue(dataSet.hasNext());
assertEquals(42L, dataSet.next().getFields().get(0).getLongV());
}
}

private static Tablet createTablet() {
final List<IMeasurementSchema> schemas =
Arrays.asList(
new MeasurementSchema("tag1", TSDataType.STRING),
new MeasurementSchema("value", TSDataType.INT64));
final Tablet tablet =
new Tablet(
TABLE,
IMeasurementSchema.getMeasurementNameList(schemas),
IMeasurementSchema.getDataTypeList(schemas),
Arrays.asList(ColumnCategory.TAG, ColumnCategory.FIELD),
1);
tablet.addTimestamp(0, 1L);
tablet.addValue("tag1", 0, "d1");
tablet.addValue("value", 0, 42L);
return tablet;
}
}
Loading
Loading