Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.session.pool;
import org.apache.iotdb.common.rpc.thrift.TAggregationType;
import org.apache.iotdb.common.rpc.thrift.TEndPoint;
import org.apache.iotdb.isession.INodeSupplier;
import org.apache.iotdb.isession.ISession;
import org.apache.iotdb.isession.SessionConfig;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.pool.ISessionPool;
import org.apache.iotdb.isession.pool.SessionDataSetWrapper;
import org.apache.iotdb.isession.template.Template;
import org.apache.iotdb.isession.util.Version;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.service.rpc.thrift.TSBackupConfigurationResp;
import org.apache.iotdb.service.rpc.thrift.TSConnectionInfoResp;
import org.apache.iotdb.session.DummyNodesSupplier;
import org.apache.iotdb.session.NodesSupplier;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.session.util.SessionUtils;
import org.apache.thrift.TException;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.file.metadata.enums.CompressionType;
import org.apache.tsfile.file.metadata.enums.TSEncoding;
import org.apache.tsfile.write.record.Tablet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
* SessionPool is a wrapper of a Session Set. Using SessionPool, the user do not need to consider
* how to reuse a session connection. Even if the session is disconnected, the session pool can
* recognize it and remove the broken session connection and create a new one.
*
*
If there is no available connections and the pool reaches its max size, the all methods will
* hang until there is a available connection.
*
*
If a user has waited for a session for more than 60 seconds, a warn log will be printed.
*
*
The only thing you have to remember is that:
*
*
For a query, if you have get all data, i.e., SessionDataSetWrapper.hasNext() == false, it is
* ok. Otherwise, i.e., you want to stop the query before you get all data
* (SessionDataSetWrapper.hasNext() == true), then you have to call
* closeResultSet(SessionDataSetWrapper wrapper) manually. Otherwise the connection is occupied by
* the query.
*
*
Another case that you have to manually call closeResultSet() is that when there is exception
* when you call SessionDataSetWrapper.hasNext() or next()
*/
// ignore Generic exceptions & Throwable should never be throw, ignore Either log or rethrow this
// exception.
@SuppressWarnings({"squid:S112", "java:S1181", "java:S2139"})
public class SessionPool implements ISessionPool {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionPool.class);
public static final String SESSION_POOL_IS_CLOSED = "Session pool is closed";
public static final String CLOSE_THE_SESSION_FAILED = "close the session failed.";
protected static final int RETRY = 3;
protected static final int FINAL_RETRY = RETRY - 1;
protected final ConcurrentLinkedDeque queue = new ConcurrentLinkedDeque<>();
// for session whose resultSet is not released.
protected final ConcurrentMap occupied = new ConcurrentHashMap<>();
protected int size = 0;
protected int maxSize = 0;
protected final long waitToGetSessionTimeoutInMs;
// parameters for Session constructor
protected final String host;
protected final int port;
protected final String user;
protected final String password;
protected int fetchSize;
protected ZoneId zoneId;
// this field only take effect in write request, nothing to do with any other type requests,
// like query, load and so on.
// if set to true, it means that we may redirect the write request to its corresponding leader
// if set to false, it means that we will only send write request to first available DataNode(it
// may be changed while current DataNode is not available, for example, we may retry to connect
// to another available DataNode)
// so even if enableRedirection is set to false, we may also send write request to another
// datanode while encountering retriable errors in current DataNode
protected boolean enableRedirection;
protected boolean enableQueryRedirection = false;
protected boolean useSSL;
protected String trustStore;
protected String trustStorePwd;
protected Map deviceIdToEndpoint;
protected int thriftDefaultBufferSize;
protected int thriftMaxFrameSize;
protected boolean enableRecordsAutoConvertTablet;
/**
* Timeout of query can be set by users. A negative number means using the default configuration
* of server. And value 0 will disable the function of query timeout.
*/
protected long queryTimeoutInMs = -1;
// The version number of the client which used for compatibility in the server
protected Version version;
// parameters for Session#open()
protected final int connectionTimeoutInMs;
protected final boolean enableCompression;
// whether the queue is closed.
protected boolean closed;
// Redirect-able SessionPool
protected final List nodeUrls;
// formatted nodeUrls for logging e.g. "host:port" or "[host:port, host:port, host:port]"
private final String formattedNodeUrls;
// used to update datanodeList periodically
@SuppressWarnings("java:S3077")
private volatile ScheduledExecutorService executorService;
private INodeSupplier availableNodes;
// set to true, means that we will start a background thread to fetch all available (Status is
// not Removing) datanodes in cluster, and these available nodes will be used in retrying stage
private boolean enableAutoFetch = true;
// max retry count, if set to 0, means that we won't do any retry
// we can use any available DataNodes(fetched in background thread if enableAutoFetch is true,
// or nodeUrls user specified) to retry, even if enableRedirection is false
protected int maxRetryCount = SessionConfig.MAX_RETRY_COUNT;
protected long retryIntervalInMs = SessionConfig.RETRY_INTERVAL_IN_MS;
private static final String INSERT_RECORD_FAIL = "insertRecord failed";
private static final String INSERT_RECORD_ERROR_MSG = "unexpected error in insertRecord";
private static final String INSERT_RECORDS_ERROR_MSG = "unexpected error in insertRecords";
private static final String EXECUTE_LASTDATAQUERY_FAIL = "executeLastDataQuery failed";
private static final String EXECUTE_LASTDATAQUERY_ERROR =
"unexpected error in executeLastDataQuery";
private static final String EXECUTE_AGGREGATION_QUERY_FAIL = "executeAggregationQuery failed";
private static final String INSERT_RECORDS_OF_ONE_DEVICE_ERROR_MSG =
"unexpected error in insertRecordsOfOneDevice";
private static final String DELETE_DATA_ERROR_MSG = "unexpected error in deleteData";
private static final String CREATE_SCHEMA_TEMPLATE_ERROR_MSG =
"unexpected error in createSchemaTemplate";
private static final String EXECUTE_AGGREGATION_QUERY_ERROR_MSG =
"unexpected error in executeAggregationQuery";
private static final String DELETE_DATA_FAIL = "deleteData failed";
private static final String INSERT_RECORDS_OF_ONE_DEVICE_FAIL = "insertRecordsOfOneDevice failed";
private static final String CREATE_SCHEMA_TEMPLATE_FAIL = "createSchemaTemplate failed";
public SessionPool(String host, int port, String user, String password, int maxSize) {
this(
host,
port,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
false,
null,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(List nodeUrls, String user, String password, int maxSize) {
this(
nodeUrls,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
false,
null,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
String host, int port, String user, String password, int maxSize, boolean enableCompression) {
this(
host,
port,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
enableCompression,
null,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
List nodeUrls, String user, String password, int maxSize, boolean enableCompression) {
this(
nodeUrls,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
enableCompression,
null,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
String host,
int port,
String user,
String password,
int maxSize,
boolean enableCompression,
boolean enableRedirection) {
this(
host,
port,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
enableCompression,
null,
enableRedirection,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
List nodeUrls,
String user,
String password,
int maxSize,
boolean enableCompression,
boolean enableRedirection) {
this(
nodeUrls,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
enableCompression,
null,
enableRedirection,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
String host, int port, String user, String password, int maxSize, ZoneId zoneId) {
this(
host,
port,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
false,
zoneId,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
public SessionPool(
List nodeUrls, String user, String password, int maxSize, ZoneId zoneId) {
this(
nodeUrls,
user,
password,
maxSize,
SessionConfig.DEFAULT_FETCH_SIZE,
60_000,
false,
zoneId,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS,
SessionConfig.DEFAULT_VERSION,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE);
}
@SuppressWarnings("squid:S107")
public SessionPool(
String host,
int port,
String user,
String password,
int maxSize,
int fetchSize,
long waitToGetSessionTimeoutInMs,
boolean enableCompression,
ZoneId zoneId,
boolean enableRedirection,
int connectionTimeoutInMs,
Version version,
int thriftDefaultBufferSize,
int thriftMaxFrameSize) {
this.maxSize = maxSize;
this.host = host;
this.port = port;
this.nodeUrls = null;
this.user = user;
this.password = password;
this.fetchSize = fetchSize;
this.waitToGetSessionTimeoutInMs = waitToGetSessionTimeoutInMs;
this.enableCompression = enableCompression;
this.zoneId = zoneId;
this.enableRedirection = enableRedirection;
if (this.enableRedirection) {
deviceIdToEndpoint = new ConcurrentHashMap<>();
}
this.connectionTimeoutInMs = connectionTimeoutInMs;
this.version = version;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
this.thriftMaxFrameSize = thriftMaxFrameSize;
this.formattedNodeUrls = String.format("%s:%s", host, port);
initThreadPool();
initAvailableNodes(Collections.singletonList(new TEndPoint(host, port)));
}
public SessionPool(
String host,
int port,
String user,
String password,
int maxSize,
int fetchSize,
long waitToGetSessionTimeoutInMs,
boolean enableCompression,
ZoneId zoneId,
boolean enableRedirection,
int connectionTimeoutInMs,
Version version,
int thriftDefaultBufferSize,
int thriftMaxFrameSize,
boolean useSSL,
String trustStore,
String trustStorePwd) {
this.maxSize = maxSize;
this.host = host;
this.port = port;
this.nodeUrls = null;
this.user = user;
this.password = password;
this.fetchSize = fetchSize;
this.waitToGetSessionTimeoutInMs = waitToGetSessionTimeoutInMs;
this.enableCompression = enableCompression;
this.zoneId = zoneId;
this.enableRedirection = enableRedirection;
if (this.enableRedirection) {
deviceIdToEndpoint = new ConcurrentHashMap<>();
}
this.connectionTimeoutInMs = connectionTimeoutInMs;
this.version = version;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
this.thriftMaxFrameSize = thriftMaxFrameSize;
this.formattedNodeUrls = String.format("%s:%s", host, port);
this.useSSL = useSSL;
this.trustStore = trustStore;
this.trustStorePwd = trustStorePwd;
initThreadPool();
initAvailableNodes(Collections.singletonList(new TEndPoint(host, port)));
}
@SuppressWarnings("squid:S107") // ignore Methods should not have too many parameters
public SessionPool(
List nodeUrls,
String user,
String password,
int maxSize,
int fetchSize,
long waitToGetSessionTimeoutInMs,
boolean enableCompression,
ZoneId zoneId,
boolean enableRedirection,
int connectionTimeoutInMs,
Version version,
int thriftDefaultBufferSize,
int thriftMaxFrameSize) {
this.maxSize = maxSize;
this.host = null;
this.port = -1;
if (nodeUrls.isEmpty()) {
throw new IllegalArgumentException("nodeUrls shouldn't be empty.");
}
this.nodeUrls = nodeUrls;
this.user = user;
this.password = password;
this.fetchSize = fetchSize;
this.waitToGetSessionTimeoutInMs = waitToGetSessionTimeoutInMs;
this.enableCompression = enableCompression;
this.zoneId = zoneId;
this.enableRedirection = enableRedirection;
if (this.enableRedirection) {
deviceIdToEndpoint = new ConcurrentHashMap<>();
}
this.connectionTimeoutInMs = connectionTimeoutInMs;
this.version = version;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
this.thriftMaxFrameSize = thriftMaxFrameSize;
this.formattedNodeUrls = nodeUrls.toString();
initThreadPool();
initAvailableNodes(SessionUtils.parseSeedNodeUrls(nodeUrls));
}
public SessionPool(Builder builder) {
this.maxSize = builder.maxSize;
this.user = builder.user;
this.password = builder.pw;
this.fetchSize = builder.fetchSize;
this.waitToGetSessionTimeoutInMs = builder.waitToGetSessionTimeoutInMs;
this.enableCompression = builder.enableCompression;
this.zoneId = builder.zoneId;
this.enableRedirection = builder.enableRedirection;
if (this.enableRedirection) {
deviceIdToEndpoint = new ConcurrentHashMap<>();
}
this.enableRecordsAutoConvertTablet = builder.enableRecordsAutoConvertTablet;
this.connectionTimeoutInMs = builder.connectionTimeoutInMs;
this.version = builder.version;
this.thriftDefaultBufferSize = builder.thriftDefaultBufferSize;
this.thriftMaxFrameSize = builder.thriftMaxFrameSize;
this.enableAutoFetch = builder.enableAutoFetch;
this.useSSL = builder.useSSL;
this.trustStore = builder.trustStore;
this.trustStorePwd = builder.trustStorePwd;
this.maxRetryCount = builder.maxRetryCount;
this.retryIntervalInMs = builder.retryIntervalInMs;
this.queryTimeoutInMs = builder.queryTimeoutInMs;
if (enableAutoFetch) {
initThreadPool();
}
if (builder.nodeUrls != null) {
if (builder.nodeUrls.isEmpty()) {
throw new IllegalArgumentException("nodeUrls shouldn't be empty.");
}
this.nodeUrls = builder.nodeUrls;
this.host = null;
this.port = -1;
this.formattedNodeUrls = builder.nodeUrls.toString();
if (enableAutoFetch) {
initAvailableNodes(SessionUtils.parseSeedNodeUrls(nodeUrls));
} else {
this.availableNodes = new DummyNodesSupplier(SessionUtils.parseSeedNodeUrls(nodeUrls));
}
} else {
this.host = builder.host;
this.port = builder.port;
this.nodeUrls = null;
this.formattedNodeUrls = String.format("%s:%s", host, port);
if (enableAutoFetch) {
initAvailableNodes(Collections.singletonList(new TEndPoint(host, port)));
} else {
this.availableNodes =
new DummyNodesSupplier(Collections.singletonList(new TEndPoint(host, port)));
}
}
}
protected ISession constructNewSession() {
Session session;
if (nodeUrls == null) {
// Construct custom Session
session =
new Session.Builder()
.host(host)
.port(port)
.username(user)
.password(password)
.fetchSize(fetchSize)
.zoneId(zoneId)
.thriftDefaultBufferSize(thriftDefaultBufferSize)
.thriftMaxFrameSize(thriftMaxFrameSize)
.enableRedirection(enableRedirection)
.enableRecordsAutoConvertTablet(enableRecordsAutoConvertTablet)
.version(version)
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.timeOut(queryTimeoutInMs)
.build();
} else {
// Construct redirect-able Session
session =
new Session.Builder()
.nodeUrls(nodeUrls)
.username(user)
.password(password)
.fetchSize(fetchSize)
.zoneId(zoneId)
.thriftDefaultBufferSize(thriftDefaultBufferSize)
.thriftMaxFrameSize(thriftMaxFrameSize)
.enableRedirection(enableRedirection)
.enableRecordsAutoConvertTablet(enableRecordsAutoConvertTablet)
.version(version)
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.timeOut(queryTimeoutInMs)
.build();
}
session.setEnableQueryRedirection(enableQueryRedirection);
return session;
}
private void initThreadPool() {
this.executorService =
Executors.newSingleThreadScheduledExecutor(
r -> {
Thread t =
new Thread(
Thread.currentThread().getThreadGroup(), r, "PeriodicalUpdateDNList", 0);
if (!t.isDaemon()) {
t.setDaemon(true);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
});
}
private void initAvailableNodes(List endPointList) {
this.availableNodes =
NodesSupplier.createNodeSupplier(
endPointList,
executorService,
user,
password,
zoneId,
thriftDefaultBufferSize,
thriftMaxFrameSize,
connectionTimeoutInMs,
useSSL,
trustStore,
trustStorePwd,
enableCompression,
version.toString());
}
// if this method throws an exception, either the server is broken, or the ip/port/user/password
// is incorrect.
@SuppressWarnings({"squid:S3776", "squid:S2446"}) // Suppress high Cognitive Complexity warning
protected ISession getSession() throws IoTDBConnectionException {
ISession session = queue.poll();
if (closed) {
throw new IoTDBConnectionException(SESSION_POOL_IS_CLOSED);
}
if (session != null) {
return session;
}
boolean shouldCreate = false;
long start = System.currentTimeMillis();
while (session == null) {
synchronized (this) {
if (size < maxSize) {
// we can create more session
size++;
shouldCreate = true;
// but we do it after skip synchronized block because connection a session is time
// consuming.
break;
}
// we have to wait for someone returns a session.
try {
this.wait(1000);
long timeOut = Math.min(waitToGetSessionTimeoutInMs, 60_000);
if (System.currentTimeMillis() - start > timeOut) {
LOGGER.warn(
"the SessionPool has wait for {} seconds to get a new connection: {} with {}, {}",
(System.currentTimeMillis() - start) / 1000,
formattedNodeUrls,
user,
password);
LOGGER.warn(
"current occupied size {}, queue size {}, considered size {} ",
occupied.size(),
queue.size(),
size);
if (System.currentTimeMillis() - start > waitToGetSessionTimeoutInMs) {
throw new IoTDBConnectionException(
String.format("timeout to get a connection from %s", formattedNodeUrls));
}
}
} catch (InterruptedException e) {
LOGGER.warn("Interrupted!", e);
Thread.currentThread().interrupt();
// wake up from this.wait(1000) by this.notify()
}
session = queue.poll();
// for putBack or size--
this.notify();
if (closed) {
throw new IoTDBConnectionException(SESSION_POOL_IS_CLOSED);
}
}
}
if (shouldCreate) {
// create a new one.
session = constructNewSession();
try {
session.open(enableCompression, connectionTimeoutInMs, deviceIdToEndpoint, availableNodes);
// avoid someone has called close() the session pool
synchronized (this) {
if (closed) {
// have to release the connection...
session.close();
throw new IoTDBConnectionException(SESSION_POOL_IS_CLOSED);
}
}
} catch (IoTDBConnectionException e) {
// if exception, we will throw the exception.
// Meanwhile, we have to set size--
synchronized (this) {
size--;
// we do not need to notifyAll as any waited thread can continue to work after waked up.
this.notify();
}
throw e;
}
}
return session;
}
@Override
public int currentAvailableSize() {
return queue.size();
}
@Override
public int currentOccupiedSize() {
return occupied.size();
}
@SuppressWarnings({"squid:S2446"})
protected void putBack(ISession session) {
queue.push(session);
synchronized (this) {
// we do not need to notifyAll as any waited thread can continue to work after waked up.
this.notify();
// comment the following codes as putBack is too frequently called.
// if (logger.isTraceEnabled()) {
// logger.trace("put a session back and notify others..., queue.size = {}",
// queue.size());
// }
}
}
protected void occupy(ISession session) {
occupied.put(session, session);
}
/** close all connections in the pool */
@Override
public synchronized void close() {
for (ISession session : queue) {
try {
session.close();
} catch (IoTDBConnectionException e) {
// do nothing
LOGGER.warn(CLOSE_THE_SESSION_FAILED, e);
}
}
for (ISession session : occupied.keySet()) {
try {
session.close();
} catch (IoTDBConnectionException e) {
// do nothing
LOGGER.warn(CLOSE_THE_SESSION_FAILED, e);
}
}
if (this.executorService != null) {
this.executorService.shutdown();
this.executorService = null;
}
if (availableNodes != null) {
this.availableNodes.close();
this.availableNodes = null;
}
LOGGER.info("closing the session pool, cleaning queues...");
this.closed = true;
queue.clear();
occupied.clear();
}
@Override
public void closeResultSet(SessionDataSetWrapper wrapper) {
boolean putback = true;
try {
wrapper.getSessionDataSet().closeOperationHandle();
} catch (IoTDBConnectionException | StatementExecutionException e) {
tryConstructNewSession();
putback = false;
} finally {
ISession session = occupied.remove(wrapper.getSession());
if (putback && session != null) {
putBack(wrapper.getSession());
}
}
}
@SuppressWarnings({"squid:S2446"})
private void tryConstructNewSession() {
ISession session = constructNewSession();
try {
session.open(enableCompression, connectionTimeoutInMs, deviceIdToEndpoint, availableNodes);
// avoid someone has called close() the session pool
synchronized (this) {
if (closed) {
// have to release the connection...
session.close();
throw new IoTDBConnectionException(SESSION_POOL_IS_CLOSED);
}
queue.push(session);
this.notify();
}
} catch (IoTDBConnectionException e) {
synchronized (this) {
size--;
// we do not need to notifyAll as any waited thread can continue to work after waked up.
this.notify();
}
}
}
private void closeSession(ISession session) {
if (session != null) {
try {
session.close();
} catch (Exception e2) {
// do nothing. We just want to guarantee the session is closed.
LOGGER.warn(CLOSE_THE_SESSION_FAILED, e2);
}
}
}
protected void cleanSessionAndMayThrowConnectionException(
ISession session, int times, IoTDBConnectionException e) throws IoTDBConnectionException {
closeSession(session);
tryConstructNewSession();
if (times == FINAL_RETRY) {
throw new IoTDBConnectionException(
String.format(
"retry to execute statement on %s failed %d times: %s",
formattedNodeUrls, RETRY, e.getMessage()),
e);
}
}
/**
* insert the data of a device. For each timestamp, the number of measurements is the same.
*
* @param tablet data batch
*/
@Override
public void insertTablet(Tablet tablet)
throws IoTDBConnectionException, StatementExecutionException {
/*
* A Tablet example:
* device1
* time s1, s2, s3
* 1, 1, 1, 1
* 2, 2, 2, 2
* 3, 3, 3, 3
*
* times in Tablet may be not in ascending orde
*/
insertTablet(tablet, false);
}
/**
* insert the data of a device. For each timestamp, the number of measurements is the same.
*
*
Users need to control the count of Tablet and write a batch when it reaches the maxBatchSize
*
* @param tablet a tablet data of one device
* @param sorted whether times in Tablet are in ascending order
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be throw
@Override
public void insertTablet(Tablet tablet, boolean sorted)
throws IoTDBConnectionException, StatementExecutionException {
/*
* A Tablet example:
* device1
* time s1, s2, s3
* 1, 1, 1, 1
* 2, 2, 2, 2
* 3, 3, 3, 3
*/
ISession session = getSession();
try {
session.insertTablet(tablet, sorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertTablet failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertTablet", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* insert the data of a device. For each timestamp, the number of measurements is the same.
*
*
Users need to control the count of Tablet and write a batch when it reaches the maxBatchSize
*
* @param tablet a tablet data of one device
*/
@Override
public void insertAlignedTablet(Tablet tablet)
throws IoTDBConnectionException, StatementExecutionException {
insertAlignedTablet(tablet, false);
}
/**
* insert the data of a device. For each timestamp, the number of measurements is the same.
*
*
Users need to control the count of Tablet and write a batch when it reaches the maxBatchSize
*
* @param tablet a tablet data of one device
* @param sorted whether times in Tablet are in ascending order
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be throw
@Override
public void insertAlignedTablet(Tablet tablet, boolean sorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedTablet(tablet, sorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedTablet failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedTablet", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* use batch interface to insert data
*
* @param tablets multiple batch
*/
@Override
public void insertTablets(Map tablets)
throws IoTDBConnectionException, StatementExecutionException {
insertTablets(tablets, false);
}
/**
* use batch interface to insert data
*
* @param tablets multiple batch
*/
@Override
public void insertAlignedTablets(Map tablets)
throws IoTDBConnectionException, StatementExecutionException {
insertAlignedTablets(tablets, false);
}
/**
* use batch interface to insert aligned data
*
* @param tablets multiple batch
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be throw
@Override
public void insertTablets(Map tablets, boolean sorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertTablets(tablets, sorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertTablets failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertTablets", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* use batch interface to insert aligned data
*
* @param tablets multiple batch
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be throw
@Override
public void insertAlignedTablets(Map tablets, boolean sorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedTablets(tablets, sorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedTablets failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedTablets", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data in batch format, which can reduce the overhead of network. This method is just like
* jdbc batch insert, we pack some insert request in batch and send them to server If you want
* improve your performance, please see insertTablet method
*
* @see Session#insertTablet(Tablet)
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be throw
@Override
public void insertRecords(
List deviceIds,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecords(deviceIds, times, measurementsList, typesList, valuesList);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertRecords failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data in batch format, which can reduce the overhead of network. This method is
* just like jdbc batch insert, we pack some insert request in batch and send them to server. If
* you want to improve your performance, please see insertTablet method.
*
* @see Session#insertTablet(Tablet)
*/
@SuppressWarnings({"squid:S112"}) // ignore Generic exceptions should never be thrown
@Override
public void insertAlignedRecords(
List multiSeriesIds,
List times,
List> multiMeasurementComponentsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedRecords(
multiSeriesIds, times, multiMeasurementComponentsList, typesList, valuesList);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedRecords failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedRecords", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data that belong to the same device in batch format, which can reduce the overhead of
* network. This method is just like jdbc batch insert, we pack some insert request in batch and
* send them to server If you want improve your performance, please see insertTablet method
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, false);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn(INSERT_RECORDS_OF_ONE_DEVICE_FAIL, e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_OF_ONE_DEVICE_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data that belong to the same device in batch format, which can reduce the overhead of
* network. This method is just like jdbc batch insert, we pack some insert request in batch and
* send them to server If you want improve your performance, please see insertTablet method
*
* @see Session#insertTablet(Tablet)
* @deprecated
*/
@Deprecated
@Override
public void insertOneDeviceRecords(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, false);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn(INSERT_RECORDS_OF_ONE_DEVICE_FAIL, e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_OF_ONE_DEVICE_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert String format data that belong to the same device in batch format, which can reduce the
* overhead of network. This method is just like jdbc batch insert, we pack some insert request in
* batch and send them to server If you want improve your performance, please see insertTablet
* method
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertStringRecordsOfOneDevice(deviceId, times, measurementsList, valuesList, false);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertStringRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertStringRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data that belong to the same device in batch format, which can reduce the overhead of
* network. This method is just like jdbc batch insert, we pack some insert request in batch and
* send them to server If you want improve your performance, please see insertTablet method
*
* @param haveSorted whether the times list has been ordered.
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, haveSorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn(INSERT_RECORDS_OF_ONE_DEVICE_FAIL, e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_OF_ONE_DEVICE_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data that belong to the same device in batch format, which can reduce the overhead of
* network. This method is just like jdbc batch insert, we pack some insert request in batch and
* send them to server If you want improve your performance, please see insertTablet method
*
* @param haveSorted whether the times list has been ordered.
* @see Session#insertTablet(Tablet)
* @deprecated
*/
@Override
@Deprecated
public void insertOneDeviceRecords(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, haveSorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn(INSERT_RECORDS_OF_ONE_DEVICE_FAIL, e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_OF_ONE_DEVICE_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert String format data that belong to the same device in batch format, which can reduce the
* overhead of network. This method is just like jdbc batch insert, we pack some insert request in
* batch and send them to server If you want improve your performance, please see insertTablet
* method
*
* @param haveSorted whether the times list has been ordered.
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertStringRecordsOfOneDevice(
deviceId, times, measurementsList, valuesList, haveSorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertStringRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertStringRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data that belong to the same device in batch format, which can reduce the
* overhead of network. This method is just like jdbc batch insert, we pack some insert request in
* batch and send them to server If you want improve your performance, please see insertTablet
* method.
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, false);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data as String format that belong to the same device in batch format, which can
* reduce the overhead of network. This method is just like jdbc batch insert, we pack some insert
* request in batch and send them to server If you want improve your performance, please see
* insertTablet method.
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedStringRecordsOfOneDevice(deviceId, times, measurementsList, valuesList);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedStringRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedStringRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data that belong to the same device in batch format, which can reduce the
* overhead of network. This method is just like jdbc batch insert, we pack some insert request in
* batch and send them to server If you want improve your performance, please see insertTablet
* method.
*
* @param haveSorted whether the times list has been ordered.
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, haveSorted);
putBack(session);
return;
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data as String format that belong to the same device in batch format, which can
* reduce the overhead of network. This method is just like jdbc batch insert, we pack some insert
* request in batch and send them to server If you want improve your performance, please see
* insertTablet method.
*
* @param haveSorted whether the times list has been ordered.
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedStringRecordsOfOneDevice(
deviceId, times, measurementsList, valuesList, haveSorted);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedStringRecordsOfOneDevice failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedStringRecordsOfOneDevice", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert data in batch format, which can reduce the overhead of network. This method is just like
* jdbc batch insert, we pack some insert request in batch and send them to server If you want
* improve your performance, please see insertTablet method
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecords(
List deviceIds,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecords(deviceIds, times, measurementsList, valuesList);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertRecords failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORDS_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* Insert aligned data in batch format, which can reduce the overhead of network. This method is
* just like jdbc batch insert, we pack some insert request in batch and send them to server If
* you want improve your performance, please see insertTablet method.
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecords(
List multiSeriesIds,
List times,
List> multiMeasurementComponentsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertAlignedRecords(
multiSeriesIds, times, multiMeasurementComponentsList, valuesList);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.warn("insertAlignedRecords failed", e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error("unexpected error in insertAlignedRecords", e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* insert data in one row, if you want improve your performance, please use insertRecords method
* or insertTablet method
*
* @see Session#insertRecords(List, List, List, List, List)
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecord(
String deviceId,
long time,
List measurements,
List types,
Object... values)
throws IoTDBConnectionException, StatementExecutionException {
ISession session = getSession();
try {
session.insertRecord(deviceId, time, measurements, types, values);
putBack(session);
} catch (IoTDBConnectionException e) {
// TException means the connection is broken, remove it and get a new one.
LOGGER.error(INSERT_RECORD_FAIL, e);
cleanSessionAndMayThrowConnectionException(session, FINAL_RETRY, e);
} catch (StatementExecutionException | RuntimeException e) {
putBack(session);
throw e;
} catch (Throwable e) {
LOGGER.error(INSERT_RECORD_ERROR_MSG, e);
putBack(session);
throw new RuntimeException(e);
}
}
/**
* insert data in one row, if you want improve your performance, please use insertRecords method
* or insertTablet method
*
* @see Session#insertRecords(List, List, List, List, List)
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecord(
String deviceId,
long time,
List measurements,
List types,
List