diff --git a/docs/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md b/docs/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md index 8adf34af275a..afd12b8d3778 100644 --- a/docs/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md +++ b/docs/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md @@ -59,10 +59,15 @@ IoTDB> CREATE SNAPSHOT FOR SCHEMA ``` -## Kill Query +## Timeout -When using IoTDB, you may encounter the following situations: you have entered a query statement, but can not get the result for a long time, as this query contains too much data or some other reasons, and have to wait until the query ends. -Since version 0.12, IoTDB has provided two solutions for queries with long execution time: query timeout and query abort. +IoTDB supports session and query level timeout. + +### Session timeout + +Session timeout controls when idle sessions are closed. An idle session is one that had not initiated any query or non-query operations for a period of time. + +Session timeout is disabled by default and can be set using the `session_timeout_threshold` parameter in IoTDB configuration file. ### Query timeout @@ -73,7 +78,7 @@ IoTDB> select * from root; Msg: 701 Current query is time out, please check your statement or modify timeout parameter. ``` -The default timeout of the system is 60000 ms,which can be customized in the configuration file through the `query_timeout_threshold` parameter. +The default timeout of a query is 60000 ms,which can be customized in the configuration file through the `query_timeout_threshold` parameter. If you use JDBC or Session, we also support setting a timeout for a single query(Unit: ms): diff --git a/docs/zh/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md b/docs/zh/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md index 192f6a0d6ffe..675a3641804b 100644 --- a/docs/zh/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md +++ b/docs/zh/UserGuide/IoTDB-SQL-Language/Maintenance-Command.md @@ -56,11 +56,15 @@ IoTDB> CLEAR CACHE IoTDB> CREATE SNAPSHOT FOR SCHEMA ``` -## 中止查询 +## 超时 -当使用 IoTDB 时,您可能会遇到以下情形:输入了一个查询,但是由于其包含的数据量过大或是其他原因,导致长时间无法返回结果,但是迫于生产环境无法中止该命令,只能被迫等待。 +IoTDB 支持 Session 超时和查询超时。 -从 0.12 版本开始,IoTDB 对执行时间过长的查询给出了两种解决方案:查询超时和查询中止。 +### Session 超时 + +Session 超时控制何时关闭空闲 Session。空闲 Session 指在一段时间内没有发起任何操作的 Session。 + +Session 超时默认未开启。可以在配置文件中通过 `session_timeout_threshold` 参数进行配置。 ### 查询超时 diff --git a/server/src/assembly/resources/conf/iotdb-engine.properties b/server/src/assembly/resources/conf/iotdb-engine.properties index 22706da96307..9eb19dde5363 100644 --- a/server/src/assembly/resources/conf/iotdb-engine.properties +++ b/server/src/assembly/resources/conf/iotdb-engine.properties @@ -462,6 +462,12 @@ timestamp_precision=ms # Datatype: int # merge_write_throughput_mb_per_sec=8 +# The maximum session idle time. unit: ms +# Idle sessions are the ones that performs neither query or non-query operations for a period of time +# Set to 0 to disable session timeout +# Datatype: int +# session_timeout_threshold=0 + # The max executing time of query. unit: ms # Datatype: int # query_timeout_threshold=60000 diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java index 6f7820c66450..4b8d6b869bea 100644 --- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java +++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java @@ -407,6 +407,9 @@ public class IoTDBConfig { /** the max executing time of query in ms. Unit: millisecond */ private int queryTimeoutThreshold = 60000; + /** the max time to live of a session in ms. Unit: millisecond */ + private int sessionTimeoutThreshold = 0; + /** Replace implementation class of JDBC service */ private String rpcImplClassName = TSServiceImpl.class.getName(); @@ -1217,6 +1220,14 @@ public void setQueryTimeoutThreshold(int queryTimeoutThreshold) { this.queryTimeoutThreshold = queryTimeoutThreshold; } + public int getSessionTimeoutThreshold() { + return sessionTimeoutThreshold; + } + + public void setSessionTimeoutThreshold(int sessionTimeoutThreshold) { + this.sessionTimeoutThreshold = sessionTimeoutThreshold; + } + public boolean isReadOnly() { return readOnly; } diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java index 0ba95d464182..cf0a6cacd1c4 100644 --- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java +++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java @@ -360,6 +360,12 @@ private void loadProps() { properties.getProperty( "query_timeout_threshold", Integer.toString(conf.getQueryTimeoutThreshold())))); + conf.setSessionTimeoutThreshold( + Integer.parseInt( + properties.getProperty( + "session_timeout_threshold", + Integer.toString(conf.getSessionTimeoutThreshold())))); + conf.setSyncEnable( Boolean.parseBoolean( properties.getProperty("is_sync_enable", Boolean.toString(conf.isSyncEnable())))); diff --git a/server/src/main/java/org/apache/iotdb/db/query/control/QueryTimeManager.java b/server/src/main/java/org/apache/iotdb/db/query/control/QueryTimeManager.java index 59e646f47595..3d78a92a6062 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/control/QueryTimeManager.java +++ b/server/src/main/java/org/apache/iotdb/db/query/control/QueryTimeManager.java @@ -94,6 +94,8 @@ public AtomicBoolean unRegisterQuery(long queryId) { if (scheduledFuture != null) { scheduledFuture.cancel(false); } + SessionTimeoutManager.getInstance() + .refresh(SessionManager.getInstance().getSessionIdByQueryId(queryId)); return null; }); return successRemoved; diff --git a/server/src/main/java/org/apache/iotdb/db/query/control/SessionManager.java b/server/src/main/java/org/apache/iotdb/db/query/control/SessionManager.java index a2a253ffbccd..368dbfca7e8e 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/control/SessionManager.java +++ b/server/src/main/java/org/apache/iotdb/db/query/control/SessionManager.java @@ -77,6 +77,20 @@ public boolean releaseSessionResource(long sessionId) { return sessionIdToUsername.remove(sessionId) != null; } + public long getSessionIdByQueryId(long queryId) { + // TODO: make this more efficient with a queryId -> sessionId map + for (Map.Entry> statementToQueries : statementIdToQueryId.entrySet()) { + if (statementToQueries.getValue().contains(queryId)) { + for (Map.Entry> sessionToStatements : sessionIdToStatementId.entrySet()) { + if (sessionToStatements.getValue().contains(statementToQueries.getKey())) { + return sessionToStatements.getKey(); + } + } + } + } + return -1; + } + public long requestStatementId(long sessionId) { long statementId = statementIdGenerator.incrementAndGet(); sessionIdToStatementId diff --git a/server/src/main/java/org/apache/iotdb/db/query/control/SessionTimeoutManager.java b/server/src/main/java/org/apache/iotdb/db/query/control/SessionTimeoutManager.java new file mode 100644 index 000000000000..abd557ec26c5 --- /dev/null +++ b/server/src/main/java/org/apache/iotdb/db/query/control/SessionTimeoutManager.java @@ -0,0 +1,114 @@ +/* + * 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.db.query.control; + +import org.apache.iotdb.db.concurrent.IoTDBThreadPoolFactory; +import org.apache.iotdb.db.conf.IoTDBDescriptor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class SessionTimeoutManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionTimeoutManager.class); + private static final long MINIMUM_CLEANUP_PERIOD = 2000; + private static final long SESSION_TIMEOUT = + IoTDBDescriptor.getInstance().getConfig().getSessionTimeoutThreshold(); + + private Map sessionIdToLastActiveTime; + private ScheduledExecutorService executorService; + + private SessionTimeoutManager() { + if (SESSION_TIMEOUT == 0) { + return; + } + + this.sessionIdToLastActiveTime = new ConcurrentHashMap<>(); + this.executorService = + IoTDBThreadPoolFactory.newScheduledThreadPool(1, "session-timeout-manager"); + + executorService.scheduleAtFixedRate( + () -> { + LOGGER.info("cleaning up expired sessions"); + cleanup(); + }, + 0, + Math.max(MINIMUM_CLEANUP_PERIOD, SESSION_TIMEOUT / 5), + TimeUnit.MILLISECONDS); + } + + public void register(long id) { + if (SESSION_TIMEOUT == 0) { + return; + } + + sessionIdToLastActiveTime.put(id, System.currentTimeMillis()); + } + + public boolean unregister(long id) { + if (SESSION_TIMEOUT == 0) { + return SessionManager.getInstance().releaseSessionResource(id); + } + + if (SessionManager.getInstance().releaseSessionResource(id)) { + return sessionIdToLastActiveTime.remove(id) != null; + } + + return false; + } + + public void refresh(long id) { + if (SESSION_TIMEOUT == 0) { + return; + } + + sessionIdToLastActiveTime.computeIfPresent(id, (k, v) -> System.currentTimeMillis()); + } + + private void cleanup() { + long currentTime = System.currentTimeMillis(); + sessionIdToLastActiveTime.entrySet().stream() + .filter(entry -> entry.getValue() + SESSION_TIMEOUT < currentTime) + .forEach( + entry -> { + if (unregister(entry.getKey())) { + LOGGER.debug( + String.format( + "session-%s timed out in %d ms", + entry.getKey(), currentTime - entry.getValue())); + } + }); + } + + public static SessionTimeoutManager getInstance() { + return SessionTimeoutManagerHelper.INSTANCE; + } + + private static class SessionTimeoutManagerHelper { + + private static final SessionTimeoutManager INSTANCE = new SessionTimeoutManager(); + + private SessionTimeoutManagerHelper() {} + } +} diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java index 3dcaff1a7dfd..0616f613aef3 100644 --- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java +++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java @@ -75,6 +75,7 @@ import org.apache.iotdb.db.query.context.QueryContext; import org.apache.iotdb.db.query.control.QueryTimeManager; import org.apache.iotdb.db.query.control.SessionManager; +import org.apache.iotdb.db.query.control.SessionTimeoutManager; import org.apache.iotdb.db.query.control.TracingManager; import org.apache.iotdb.db.query.dataset.AlignByDeviceDataSet; import org.apache.iotdb.db.query.dataset.DirectAlignByTimeDataSet; @@ -276,6 +277,8 @@ public TSOpenSessionResp openSession(TSOpenSessionReq req) throws TException { "User {} opens Session failed with an incorrect password", req.getUsername()); } + SessionTimeoutManager.getInstance().register(sessionId); + TSOpenSessionResp resp = new TSOpenSessionResp(tsStatus, CURRENT_RPC_VERSION); return resp.setSessionId(sessionId); } @@ -292,7 +295,7 @@ public TSStatus closeSession(TSCloseSessionReq req) { currSessionId.remove(); return new TSStatus( - !sessionManager.releaseSessionResource(sessionId) + !SessionTimeoutManager.getInstance().unregister(sessionId) ? RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR) : RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS)); } @@ -306,7 +309,7 @@ public TSStatus cancelOperation(TSCancelOperationReq req) { @Override public TSStatus closeOperation(TSCloseOperationReq req) { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -339,7 +342,7 @@ public TSFetchMetadataResp fetchMetadata(TSFetchMetadataReq req) { TSFetchMetadataResp resp = new TSFetchMetadataResp(); if (!checkLogin(req.getSessionId())) { - return resp.setStatus(RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR)); + return resp.setStatus(getNotLoggedInStatus()); } TSStatus status; @@ -485,7 +488,7 @@ public TSStatus executeBatchStatement(TSExecuteBatchStatementReq req) { List result = new ArrayList<>(); boolean isAllSuccessful = true; if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } InsertRowsPlan insertRowsPlan; @@ -590,7 +593,7 @@ public TSStatus executeBatchStatement(TSExecuteBatchStatementReq req) { public TSExecuteStatementResp executeStatement(TSExecuteStatementReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSExecuteStatementResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSExecuteStatementResp(getNotLoggedInStatus()); } String statement = req.getStatement(); @@ -621,7 +624,7 @@ public TSExecuteStatementResp executeStatement(TSExecuteStatementReq req) { public TSExecuteStatementResp executeQueryStatement(TSExecuteStatementReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSExecuteStatementResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSExecuteStatementResp(getNotLoggedInStatus()); } String statement = req.getStatement(); @@ -655,7 +658,7 @@ public TSExecuteStatementResp executeQueryStatement(TSExecuteStatementReq req) { public TSExecuteStatementResp executeRawDataQuery(TSRawDataQueryReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSExecuteStatementResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSExecuteStatementResp(getNotLoggedInStatus()); } PhysicalPlan physicalPlan = @@ -686,7 +689,7 @@ public TSExecuteStatementResp executeRawDataQuery(TSRawDataQueryReq req) { public TSExecuteStatementResp executeLastDataQuery(TSLastDataQueryReq req) throws TException { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSExecuteStatementResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSExecuteStatementResp(getNotLoggedInStatus()); } PhysicalPlan physicalPlan = @@ -1045,7 +1048,7 @@ private void getAlignByDeviceQueryHeaders( public TSFetchResultsResp fetchResults(TSFetchResultsReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSFetchResultsResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSFetchResultsResp(getNotLoggedInStatus()); } if (!sessionManager.hasDataset(req.queryId)) { @@ -1165,7 +1168,7 @@ protected QueryContext genQueryContext(long queryId, boolean debug) { @Override public TSExecuteStatementResp executeUpdateStatement(TSExecuteStatementReq req) { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getTSExecuteStatementResp(TSStatusCode.NOT_LOGIN_ERROR); + return RpcUtils.getTSExecuteStatementResp(getNotLoggedInStatus()); } try { @@ -1213,9 +1216,11 @@ private TSExecuteStatementResp executeUpdateStatement(String statement, long ses * @return true: If logged in; false: If not logged in */ private boolean checkLogin(long sessionId) { - boolean isLoggedIn = sessionManager.getZoneId(sessionId) != null; + boolean isLoggedIn = sessionManager.getUsername(sessionId) != null; if (!isLoggedIn) { LOGGER.info(INFO_NOT_LOGIN, IoTDBConstant.GLOBAL_DB_NAME); + } else { + SessionTimeoutManager.getInstance().refresh(sessionId); } return isLoggedIn; } @@ -1278,7 +1283,7 @@ public ServerProperties getProperties() { @Override public TSStatus insertRecords(TSInsertRecordsReq req) { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1344,7 +1349,7 @@ private TSStatus judgeFinalTsStatus( @Override public TSStatus insertRecordsOfOneDevice(TSInsertRecordsOfOneDeviceReq req) { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1386,7 +1391,7 @@ public TSStatus insertRecordsOfOneDevice(TSInsertRecordsOfOneDeviceReq req) { @Override public TSStatus insertStringRecords(TSInsertStringRecordsReq req) { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1493,7 +1498,7 @@ public TSStatus testInsertStringRecords(TSInsertStringRecordsReq req) { public TSStatus insertRecord(TSInsertRecordReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } AUDIT_LOGGER.debug( @@ -1522,7 +1527,7 @@ public TSStatus insertRecord(TSInsertRecordReq req) { public TSStatus insertStringRecord(TSInsertStringRecordReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } AUDIT_LOGGER.debug( @@ -1551,7 +1556,7 @@ public TSStatus insertStringRecord(TSInsertStringRecordReq req) { public TSStatus deleteData(TSDeleteDataReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } DeletePlan plan = new DeletePlan(); @@ -1575,7 +1580,7 @@ public TSStatus insertTablet(TSInsertTabletReq req) { long t1 = System.currentTimeMillis(); try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } InsertTabletPlan insertTabletPlan = @@ -1605,7 +1610,7 @@ public TSStatus insertTablets(TSInsertTabletsReq req) { long t1 = System.currentTimeMillis(); try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } return insertTabletsInternal(req); @@ -1662,7 +1667,7 @@ public TSStatus insertTabletsInternal(TSInsertTabletsReq req) throws IllegalPath public TSStatus setStorageGroup(long sessionId, String storageGroup) { try { if (!checkLogin(sessionId)) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } SetStorageGroupPlan plan = new SetStorageGroupPlan(new PartialPath(storageGroup)); @@ -1679,7 +1684,7 @@ public TSStatus setStorageGroup(long sessionId, String storageGroup) { public TSStatus deleteStorageGroups(long sessionId, List storageGroups) { try { if (!checkLogin(sessionId)) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } List storageGroupList = new ArrayList<>(); @@ -1700,7 +1705,7 @@ public TSStatus deleteStorageGroups(long sessionId, List storageGroups) public TSStatus createTimeseries(TSCreateTimeseriesReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1730,7 +1735,7 @@ public TSStatus createTimeseries(TSCreateTimeseriesReq req) { public TSStatus createAlignedTimeseries(TSCreateAlignedTimeseriesReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } // if measurements.size() == 1, convert to create timeseries @@ -1783,7 +1788,7 @@ public TSStatus createAlignedTimeseries(TSCreateAlignedTimeseriesReq req) { public TSStatus createMultiTimeseries(TSCreateMultiTimeseriesReq req) { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1869,7 +1874,7 @@ public TSStatus createMultiTimeseries(TSCreateMultiTimeseriesReq req) { public TSStatus deleteTimeseries(long sessionId, List paths) { try { if (!checkLogin(sessionId)) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } List pathList = new ArrayList<>(); @@ -1895,7 +1900,7 @@ public long requestStatementId(long sessionId) { public TSStatus createSchemaTemplate(TSCreateSchemaTemplateReq req) throws TException { try { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -1953,7 +1958,7 @@ public TSStatus createSchemaTemplate(TSCreateSchemaTemplateReq req) throws TExce @Override public TSStatus setSchemaTemplate(TSSetSchemaTemplateReq req) throws TException { if (!checkLogin(req.getSessionId())) { - return RpcUtils.getStatus(TSStatusCode.NOT_LOGIN_ERROR); + return getNotLoggedInStatus(); } if (AUDIT_LOGGER.isDebugEnabled()) { @@ -2082,6 +2087,12 @@ private TSStatus onNPEOrUnexpectedException( return RpcUtils.getStatus(statusCode, message + e.getMessage()); } + private TSStatus getNotLoggedInStatus() { + return RpcUtils.getStatus( + TSStatusCode.NOT_LOGIN_ERROR, + "Log in failed. Either you are not authorized or the session has timed out."); + } + private String getRootCause(Throwable e) { while (e.getCause() != null) { e = e.getCause(); diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSessionTimeoutIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSessionTimeoutIT.java new file mode 100644 index 000000000000..d4c8918f5ded --- /dev/null +++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSessionTimeoutIT.java @@ -0,0 +1,82 @@ +/* + * 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.db.integration; + +import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.utils.EnvironmentUtils; +import org.apache.iotdb.jdbc.Config; +import org.apache.iotdb.jdbc.IoTDBSQLException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class IoTDBSessionTimeoutIT { + + public static final int SESSION_TIMEOUT = 2000; + + @Before + public void setUp() throws ClassNotFoundException { + EnvironmentUtils.closeStatMonitor(); + IoTDBDescriptor.getInstance().getConfig().setSessionTimeoutThreshold(1000); + EnvironmentUtils.envSetUp(); + Class.forName(Config.JDBC_DRIVER_NAME); + } + + @After + public void tearDown() throws Exception { + EnvironmentUtils.cleanEnv(); + IoTDBDescriptor.getInstance().getConfig().setSessionTimeoutThreshold(0); + } + + @Test + @Ignore + public void sessionTimeoutTest() { + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + Thread.sleep(SESSION_TIMEOUT + 10000); + statement.execute("show storage group"); + fail("session did not timeout as expected"); + } catch (IoTDBSQLException e) { + assertEquals( + "601: Log in failed. Either you are not authorized or the session has timed out.", + e.getMessage()); + } catch (Exception e) { + fail(e.getMessage()); + } + + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + Thread.sleep(SESSION_TIMEOUT / 2); + statement.execute("select * from root.sg.d1"); + } catch (Exception e) { + fail(e.getMessage()); + } + } +}