Please wait. This can take some minutes ...
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.
org.apache.iotdb.session.Session Maven / Gradle / Ivy
/*
* 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;
import org.apache.iotdb.common.rpc.thrift.TAggregationType;
import org.apache.iotdb.common.rpc.thrift.TEndPoint;
import org.apache.iotdb.isession.ISession;
import org.apache.iotdb.isession.SessionConfig;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.template.Template;
import org.apache.iotdb.isession.util.Version;
import org.apache.iotdb.rpc.BatchExecutionException;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.NoValidValueException;
import org.apache.iotdb.rpc.RedirectException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.service.rpc.thrift.TCreateTimeseriesUsingSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSAppendSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSBackupConfigurationResp;
import org.apache.iotdb.service.rpc.thrift.TSConnectionInfoResp;
import org.apache.iotdb.service.rpc.thrift.TSCreateAlignedTimeseriesReq;
import org.apache.iotdb.service.rpc.thrift.TSCreateMultiTimeseriesReq;
import org.apache.iotdb.service.rpc.thrift.TSCreateSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSCreateTimeseriesReq;
import org.apache.iotdb.service.rpc.thrift.TSDeleteDataReq;
import org.apache.iotdb.service.rpc.thrift.TSDropSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertRecordReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertRecordsOfOneDeviceReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertRecordsReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertStringRecordReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertStringRecordsOfOneDeviceReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertStringRecordsReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertTabletReq;
import org.apache.iotdb.service.rpc.thrift.TSInsertTabletsReq;
import org.apache.iotdb.service.rpc.thrift.TSProtocolVersion;
import org.apache.iotdb.service.rpc.thrift.TSPruneSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSQueryTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSQueryTemplateResp;
import org.apache.iotdb.service.rpc.thrift.TSSetSchemaTemplateReq;
import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq;
import org.apache.iotdb.session.template.MeasurementNode;
import org.apache.iotdb.session.template.TemplateQueryType;
import org.apache.iotdb.session.util.SessionUtils;
import org.apache.iotdb.session.util.ThreadUtils;
import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.utils.Binary;
import org.apache.iotdb.tsfile.utils.BitMap;
import org.apache.iotdb.tsfile.write.record.Tablet;
import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@SuppressWarnings({"java:S107", "java:S1135"}) // need enough parameters, ignore todos
public class Session implements ISession {
private static final Logger logger = LoggerFactory.getLogger(Session.class);
protected static final TSProtocolVersion protocolVersion =
TSProtocolVersion.IOTDB_SERVICE_PROTOCOL_V3;
public static final String MSG_UNSUPPORTED_DATA_TYPE = "Unsupported data type:";
public static final String MSG_DONOT_ENABLE_REDIRECT =
"Query do not enable redirect," + " please confirm the session and server conf.";
private static final ThreadPoolExecutor OPERATION_EXECUTOR =
new ThreadPoolExecutor(
SessionConfig.DEFAULT_SESSION_EXECUTOR_THREAD_NUM,
SessionConfig.DEFAULT_SESSION_EXECUTOR_THREAD_NUM,
0,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(SessionConfig.DEFAULT_SESSION_EXECUTOR_TASK_NUM),
ThreadUtils.createThreadFactory("SessionExecutor", true));
protected List nodeUrls;
protected String username;
protected String password;
protected int fetchSize;
private static final byte TYPE_NULL = -2;
/**
* 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.
*/
private long queryTimeoutInMs = -1;
protected boolean enableRPCCompression;
protected int connectionTimeoutInMs;
protected ZoneId zoneId;
protected int thriftDefaultBufferSize;
protected int thriftMaxFrameSize;
protected TEndPoint defaultEndPoint;
protected SessionConnection defaultSessionConnection;
private boolean isClosed = true;
// Cluster version cache
protected boolean enableRedirection;
protected volatile Map deviceIdToEndpoint;
protected volatile Map endPointToSessionConnection;
protected boolean enableQueryRedirection = false;
// The version number of the client which used for compatibility in the server
protected Version version;
public Session(String host, int rpcPort) {
this(
host,
rpcPort,
SessionConfig.DEFAULT_USER,
SessionConfig.DEFAULT_PASSWORD,
SessionConfig.DEFAULT_FETCH_SIZE,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(String host, String rpcPort, String username, String password) {
this(
host,
Integer.parseInt(rpcPort),
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(String host, int rpcPort, String username, String password) {
this(
host,
rpcPort,
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(String host, int rpcPort, String username, String password, int fetchSize) {
this(
host,
rpcPort,
username,
password,
fetchSize,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(
String host,
int rpcPort,
String username,
String password,
int fetchSize,
long queryTimeoutInMs) {
this(
host,
rpcPort,
username,
password,
fetchSize,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
this.queryTimeoutInMs = queryTimeoutInMs;
}
public Session(String host, int rpcPort, String username, String password, ZoneId zoneId) {
this(
host,
rpcPort,
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
zoneId,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(
String host, int rpcPort, String username, String password, boolean enableRedirection) {
this(
host,
rpcPort,
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
enableRedirection,
SessionConfig.DEFAULT_VERSION);
}
public Session(
String host,
int rpcPort,
String username,
String password,
int fetchSize,
ZoneId zoneId,
boolean enableRedirection) {
this(
host,
rpcPort,
username,
password,
fetchSize,
zoneId,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
enableRedirection,
SessionConfig.DEFAULT_VERSION);
}
@SuppressWarnings("squid:S107")
public Session(
String host,
int rpcPort,
String username,
String password,
int fetchSize,
ZoneId zoneId,
int thriftDefaultBufferSize,
int thriftMaxFrameSize,
boolean enableRedirection,
Version version) {
this.defaultEndPoint = new TEndPoint(host, rpcPort);
this.username = username;
this.password = password;
this.fetchSize = fetchSize;
this.zoneId = zoneId;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
this.thriftMaxFrameSize = thriftMaxFrameSize;
this.enableRedirection = enableRedirection;
this.version = version;
}
public Session(List nodeUrls, String username, String password) {
this(
nodeUrls,
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
/**
* Multiple nodeUrl,If one node down, connect to the next one
*
* @param nodeUrls List Multiple ip:rpcPort eg.127.0.0.1:9001
*/
public Session(List nodeUrls, String username, String password, int fetchSize) {
this(
nodeUrls,
username,
password,
fetchSize,
null,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(List nodeUrls, String username, String password, ZoneId zoneId) {
this(
nodeUrls,
username,
password,
SessionConfig.DEFAULT_FETCH_SIZE,
zoneId,
SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY,
SessionConfig.DEFAULT_MAX_FRAME_SIZE,
SessionConfig.DEFAULT_REDIRECTION_MODE,
SessionConfig.DEFAULT_VERSION);
}
public Session(
List nodeUrls,
String username,
String password,
int fetchSize,
ZoneId zoneId,
int thriftDefaultBufferSize,
int thriftMaxFrameSize,
boolean enableRedirection,
Version version) {
this.nodeUrls = nodeUrls;
this.username = username;
this.password = password;
this.fetchSize = fetchSize;
this.zoneId = zoneId;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
this.thriftMaxFrameSize = thriftMaxFrameSize;
this.enableRedirection = enableRedirection;
this.version = version;
}
@Override
public void setFetchSize(int fetchSize) {
this.fetchSize = fetchSize;
}
@Override
public int getFetchSize() {
return this.fetchSize;
}
@Override
public Version getVersion() {
return version;
}
@Override
public void setVersion(Version version) {
this.version = version;
}
@Override
public synchronized void open() throws IoTDBConnectionException {
open(false, SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS);
}
@Override
public synchronized void open(boolean enableRPCCompression) throws IoTDBConnectionException {
open(enableRPCCompression, SessionConfig.DEFAULT_CONNECTION_TIMEOUT_MS);
}
@Override
public synchronized void open(boolean enableRPCCompression, int connectionTimeoutInMs)
throws IoTDBConnectionException {
if (!isClosed) {
return;
}
this.enableRPCCompression = enableRPCCompression;
this.connectionTimeoutInMs = connectionTimeoutInMs;
defaultSessionConnection = constructSessionConnection(this, defaultEndPoint, zoneId);
defaultSessionConnection.setEnableRedirect(enableQueryRedirection);
isClosed = false;
if (enableRedirection || enableQueryRedirection) {
deviceIdToEndpoint = new ConcurrentHashMap<>();
endPointToSessionConnection = new ConcurrentHashMap<>();
endPointToSessionConnection.put(defaultEndPoint, defaultSessionConnection);
}
}
@Override
public synchronized void open(
boolean enableRPCCompression,
int connectionTimeoutInMs,
Map deviceIdToEndpoint)
throws IoTDBConnectionException {
if (!isClosed) {
return;
}
this.enableRPCCompression = enableRPCCompression;
this.connectionTimeoutInMs = connectionTimeoutInMs;
defaultSessionConnection = constructSessionConnection(this, defaultEndPoint, zoneId);
defaultSessionConnection.setEnableRedirect(enableQueryRedirection);
isClosed = false;
if (enableRedirection || enableQueryRedirection) {
this.deviceIdToEndpoint = deviceIdToEndpoint;
endPointToSessionConnection = new ConcurrentHashMap<>();
endPointToSessionConnection.put(defaultEndPoint, defaultSessionConnection);
}
}
@Override
public synchronized void close() throws IoTDBConnectionException {
if (isClosed) {
return;
}
try {
if (enableRedirection) {
for (SessionConnection sessionConnection : endPointToSessionConnection.values()) {
sessionConnection.close();
}
} else {
defaultSessionConnection.close();
}
} finally {
isClosed = true;
}
}
public SessionConnection constructSessionConnection(
Session session, TEndPoint endpoint, ZoneId zoneId) throws IoTDBConnectionException {
if (endpoint == null) {
return new SessionConnection(session, zoneId);
}
return new SessionConnection(session, endpoint, zoneId);
}
@Override
public synchronized String getTimeZone() {
return defaultSessionConnection.getTimeZone();
}
@Override
public synchronized void setTimeZone(String zoneId)
throws StatementExecutionException, IoTDBConnectionException {
defaultSessionConnection.setTimeZone(zoneId);
this.zoneId = ZoneId.of(zoneId);
}
/** Only changes the member variable of the Session object without sending it to server. */
@Override
public void setTimeZoneOfSession(String zoneId) {
defaultSessionConnection.setTimeZoneOfSession(zoneId);
this.zoneId = ZoneId.of(zoneId);
}
@Override
public void setStorageGroup(String storageGroup)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.setStorageGroup(storageGroup);
}
@Override
public void deleteStorageGroup(String storageGroup)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.deleteStorageGroups(Collections.singletonList(storageGroup));
}
@Override
public void deleteStorageGroups(List storageGroups)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.deleteStorageGroups(storageGroups);
}
@Override
public void createDatabase(String database)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.setStorageGroup(database);
}
@Override
public void deleteDatabase(String database)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.deleteStorageGroups(Collections.singletonList(database));
}
@Override
public void deleteDatabases(List databases)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.deleteStorageGroups(databases);
}
@Override
public void createTimeseries(
String path, TSDataType dataType, TSEncoding encoding, CompressionType compressor)
throws IoTDBConnectionException, StatementExecutionException {
TSCreateTimeseriesReq request =
genTSCreateTimeseriesReq(path, dataType, encoding, compressor, null, null, null, null);
defaultSessionConnection.createTimeseries(request);
}
@Override
public void createTimeseries(
String path,
TSDataType dataType,
TSEncoding encoding,
CompressionType compressor,
Map props,
Map tags,
Map attributes,
String measurementAlias)
throws IoTDBConnectionException, StatementExecutionException {
TSCreateTimeseriesReq request =
genTSCreateTimeseriesReq(
path, dataType, encoding, compressor, props, tags, attributes, measurementAlias);
defaultSessionConnection.createTimeseries(request);
}
private TSCreateTimeseriesReq genTSCreateTimeseriesReq(
String path,
TSDataType dataType,
TSEncoding encoding,
CompressionType compressor,
Map props,
Map tags,
Map attributes,
String measurementAlias) {
TSCreateTimeseriesReq request = new TSCreateTimeseriesReq();
request.setPath(path);
request.setDataType(dataType.ordinal());
request.setEncoding(encoding.ordinal());
request.setCompressor(compressor.serialize());
request.setProps(props);
request.setTags(tags);
request.setAttributes(attributes);
request.setMeasurementAlias(measurementAlias);
return request;
}
@Override
public void createAlignedTimeseries(
String deviceId,
List measurements,
List dataTypes,
List encodings,
List compressors,
List measurementAliasList)
throws IoTDBConnectionException, StatementExecutionException {
TSCreateAlignedTimeseriesReq request =
getTSCreateAlignedTimeseriesReq(
deviceId,
measurements,
dataTypes,
encodings,
compressors,
measurementAliasList,
null,
null);
defaultSessionConnection.createAlignedTimeseries(request);
}
@Override
public void createAlignedTimeseries(
String deviceId,
List measurements,
List dataTypes,
List encodings,
List compressors,
List measurementAliasList,
List> tagsList,
List> attributesList)
throws IoTDBConnectionException, StatementExecutionException {
TSCreateAlignedTimeseriesReq request =
getTSCreateAlignedTimeseriesReq(
deviceId,
measurements,
dataTypes,
encodings,
compressors,
measurementAliasList,
tagsList,
attributesList);
defaultSessionConnection.createAlignedTimeseries(request);
}
private TSCreateAlignedTimeseriesReq getTSCreateAlignedTimeseriesReq(
String prefixPath,
List measurements,
List dataTypes,
List encodings,
List compressors,
List measurementAliasList,
List> tagsList,
List> attributesList) {
TSCreateAlignedTimeseriesReq request = new TSCreateAlignedTimeseriesReq();
request.setPrefixPath(prefixPath);
request.setMeasurements(measurements);
request.setDataTypes(dataTypes.stream().map(TSDataType::ordinal).collect(Collectors.toList()));
request.setEncodings(encodings.stream().map(TSEncoding::ordinal).collect(Collectors.toList()));
request.setCompressors(
compressors.stream().map(i -> (int) i.serialize()).collect(Collectors.toList()));
request.setMeasurementAlias(measurementAliasList);
request.setTagsList(tagsList);
request.setAttributesList(attributesList);
return request;
}
@Override
public void createMultiTimeseries(
List paths,
List dataTypes,
List encodings,
List compressors,
List> propsList,
List> tagsList,
List> attributesList,
List measurementAliasList)
throws IoTDBConnectionException, StatementExecutionException {
TSCreateMultiTimeseriesReq request =
genTSCreateMultiTimeseriesReq(
paths,
dataTypes,
encodings,
compressors,
propsList,
tagsList,
attributesList,
measurementAliasList);
defaultSessionConnection.createMultiTimeseries(request);
}
private TSCreateMultiTimeseriesReq genTSCreateMultiTimeseriesReq(
List paths,
List dataTypes,
List encodings,
List compressors,
List> propsList,
List> tagsList,
List> attributesList,
List measurementAliasList) {
TSCreateMultiTimeseriesReq request = new TSCreateMultiTimeseriesReq();
request.setPaths(paths);
List dataTypeOrdinals = new ArrayList<>(dataTypes.size());
for (TSDataType dataType : dataTypes) {
dataTypeOrdinals.add(dataType.ordinal());
}
request.setDataTypes(dataTypeOrdinals);
List encodingOrdinals = new ArrayList<>(dataTypes.size());
for (TSEncoding encoding : encodings) {
encodingOrdinals.add(encoding.ordinal());
}
request.setEncodings(encodingOrdinals);
List compressionOrdinals = new ArrayList<>(paths.size());
for (CompressionType compression : compressors) {
compressionOrdinals.add((int) compression.serialize());
}
request.setCompressors(compressionOrdinals);
request.setPropsList(propsList);
request.setTagsList(tagsList);
request.setAttributesList(attributesList);
request.setMeasurementAliasList(measurementAliasList);
return request;
}
@Override
public boolean checkTimeseriesExists(String path)
throws IoTDBConnectionException, StatementExecutionException {
return defaultSessionConnection.checkTimeseriesExists(path, queryTimeoutInMs);
}
@Override
public void setQueryTimeout(long timeoutInMs) {
this.queryTimeoutInMs = timeoutInMs;
}
@Override
public long getQueryTimeout() {
return queryTimeoutInMs;
}
/**
* execute query sql
*
* @param sql query statement
* @return result set
*/
@Override
public SessionDataSet executeQueryStatement(String sql)
throws StatementExecutionException, IoTDBConnectionException {
return executeStatementMayRedirect(sql, queryTimeoutInMs);
}
/**
* execute query sql with explicit timeout
*
* @param sql query statement
* @param timeoutInMs the timeout of this query, in milliseconds
* @return result set
*/
@Override
public SessionDataSet executeQueryStatement(String sql, long timeoutInMs)
throws StatementExecutionException, IoTDBConnectionException {
return executeStatementMayRedirect(sql, timeoutInMs);
}
/**
* execute the query, may redirect query to other node.
*
* @param sql the query statement
* @param timeoutInMs time in ms
* @return data set
* @throws StatementExecutionException statement is not right
* @throws IoTDBConnectionException the network is not good
*/
private SessionDataSet executeStatementMayRedirect(String sql, long timeoutInMs)
throws StatementExecutionException, IoTDBConnectionException {
try {
logger.debug("{} execute sql {}", defaultSessionConnection.getEndPoint(), sql);
return defaultSessionConnection.executeQueryStatement(sql, timeoutInMs);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
logger.debug(
"{} redirect query {} to {}",
defaultSessionConnection.getEndPoint(),
sql,
e.getEndPoint());
// retry
try {
return defaultSessionConnection.executeQueryStatement(sql, queryTimeoutInMs);
} catch (RedirectException redirectException) {
logger.error("{} redirect twice", sql, redirectException);
throw new StatementExecutionException(sql + " redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
/**
* execute non query statement
*
* @param sql non query statement
*/
@Override
public void executeNonQueryStatement(String sql)
throws IoTDBConnectionException, StatementExecutionException {
defaultSessionConnection.executeNonQueryStatement(sql);
}
/**
* query eg. select * from paths where time >= startTime and time < endTime time interval include
* startTime and exclude endTime
*
* @param paths series path
* @param startTime included
* @param endTime excluded
* @return data set
* @throws StatementExecutionException statement is not right
* @throws IoTDBConnectionException the network is not good
*/
@Override
public SessionDataSet executeRawDataQuery(
List paths, long startTime, long endTime, long timeOut)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeRawDataQuery(paths, startTime, endTime, timeOut);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
logger.debug("redirect query {} to {}", paths, e.getEndPoint());
// retry
try {
return defaultSessionConnection.executeRawDataQuery(paths, startTime, endTime, timeOut);
} catch (RedirectException redirectException) {
logger.error("Redirect twice", redirectException);
throw new StatementExecutionException("Redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
@Override
public SessionDataSet executeRawDataQuery(List paths, long startTime, long endTime)
throws StatementExecutionException, IoTDBConnectionException {
return executeRawDataQuery(paths, startTime, endTime, queryTimeoutInMs);
}
@Override
public SessionDataSet executeLastDataQuery(List paths, long lastTime)
throws StatementExecutionException, IoTDBConnectionException {
return executeLastDataQuery(paths, lastTime, queryTimeoutInMs);
}
/**
* query e.g. select last data from paths where time >= lastTime
*
* @param paths timeSeries eg. root.ln.d1.s1,root.ln.d1.s2
* @param lastTime get the last data, whose timestamp is greater than or equal lastTime e.g.
* 1621326244168
*/
@Override
public SessionDataSet executeLastDataQuery(List paths, long lastTime, long timeOut)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeLastDataQuery(paths, lastTime, timeOut);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
// retry
try {
return defaultSessionConnection.executeLastDataQuery(paths, lastTime, timeOut);
} catch (RedirectException redirectException) {
logger.error("redirect twice", redirectException);
throw new StatementExecutionException("redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
/**
* query eg. select last status from root.ln.wf01.wt01; + =
*
* @param paths timeSeries. eg.root.ln.d1.s1,root.ln.d1.s2
*/
@Override
public SessionDataSet executeLastDataQuery(List paths)
throws StatementExecutionException, IoTDBConnectionException {
long time = 0L;
return executeLastDataQuery(paths, time, queryTimeoutInMs);
}
@Override
public SessionDataSet executeAggregationQuery(
List paths, List aggregations)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeAggregationQuery(paths, aggregations);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
// retry
try {
return defaultSessionConnection.executeAggregationQuery(paths, aggregations);
} catch (RedirectException redirectException) {
logger.error("redirect twice", redirectException);
throw new StatementExecutionException("redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
@Override
public SessionDataSet executeAggregationQuery(
List paths, List aggregations, long startTime, long endTime)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
// retry
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime);
} catch (RedirectException redirectException) {
logger.error("redirect twice", redirectException);
throw new StatementExecutionException("redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
@Override
public SessionDataSet executeAggregationQuery(
List paths,
List aggregations,
long startTime,
long endTime,
long interval)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime, interval);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
// retry
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime, interval);
} catch (RedirectException redirectException) {
logger.error("redirect twice", redirectException);
throw new StatementExecutionException("redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
@Override
public SessionDataSet executeAggregationQuery(
List paths,
List aggregations,
long startTime,
long endTime,
long interval,
long slidingStep)
throws StatementExecutionException, IoTDBConnectionException {
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime, interval, slidingStep);
} catch (RedirectException e) {
handleQueryRedirection(e.getEndPoint());
if (enableQueryRedirection) {
// retry
try {
return defaultSessionConnection.executeAggregationQuery(
paths, aggregations, startTime, endTime, interval, slidingStep);
} catch (RedirectException redirectException) {
logger.error("redirect twice", redirectException);
throw new StatementExecutionException("redirect twice, please try again.");
}
} else {
throw new StatementExecutionException(MSG_DONOT_ENABLE_REDIRECT);
}
}
}
/**
* insert data in one row, if you want to 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 {
TSInsertRecordReq request;
try {
request =
filterAndGenTSInsertRecordReq(
deviceId, time, measurements, types, Arrays.asList(values), false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceId,
time,
measurements.toString());
return;
}
insertRecord(deviceId, request);
}
private void insertRecord(String prefixPath, TSInsertRecordReq request)
throws IoTDBConnectionException, StatementExecutionException {
try {
getSessionConnection(prefixPath).insertRecord(request);
} catch (RedirectException e) {
handleRedirection(prefixPath, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(prefixPath) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(prefixPath));
deviceIdToEndpoint.remove(prefixPath);
// reconnect with default connection
try {
defaultSessionConnection.insertRecord(request);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
private void insertRecord(String deviceId, TSInsertStringRecordReq request)
throws IoTDBConnectionException, StatementExecutionException {
try {
getSessionConnection(deviceId).insertRecord(request);
} catch (RedirectException e) {
handleRedirection(deviceId, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(deviceId) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(deviceId));
deviceIdToEndpoint.remove(deviceId);
// reconnect with default connection
try {
defaultSessionConnection.insertRecord(request);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
private SessionConnection getSessionConnection(String deviceId) {
TEndPoint endPoint;
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& (endPoint = deviceIdToEndpoint.get(deviceId)) != null
&& endPointToSessionConnection.containsKey(endPoint)) {
return endPointToSessionConnection.get(endPoint);
} else {
return defaultSessionConnection;
}
}
@Override
public String getTimestampPrecision() throws TException {
return defaultSessionConnection.getClient().getProperties().getTimestampPrecision();
}
// TODO https://issues.apache.org/jira/browse/IOTDB-1399
private void removeBrokenSessionConnection(SessionConnection sessionConnection) {
// remove the cached broken leader session
if (enableRedirection) {
TEndPoint endPoint = null;
for (Iterator> it =
endPointToSessionConnection.entrySet().iterator();
it.hasNext(); ) {
Map.Entry entry = it.next();
if (entry.getValue().equals(sessionConnection)) {
endPoint = entry.getKey();
it.remove();
break;
}
}
for (Iterator> it = deviceIdToEndpoint.entrySet().iterator();
it.hasNext(); ) {
Map.Entry entry = it.next();
if (entry.getValue().equals(endPoint)) {
it.remove();
}
}
}
}
private void handleRedirection(String deviceId, TEndPoint endpoint) {
if (enableRedirection) {
// no need to redirection
if (endpoint.ip.equals("0.0.0.0")) {
return;
}
AtomicReference exceptionReference = new AtomicReference<>();
if (!deviceIdToEndpoint.containsKey(deviceId)
|| !deviceIdToEndpoint.get(deviceId).equals(endpoint)) {
deviceIdToEndpoint.put(deviceId, endpoint);
}
SessionConnection connection =
endPointToSessionConnection.computeIfAbsent(
endpoint,
k -> {
try {
return constructSessionConnection(this, endpoint, zoneId);
} catch (IoTDBConnectionException ex) {
exceptionReference.set(ex);
return null;
}
});
if (connection == null) {
deviceIdToEndpoint.remove(deviceId);
logger.warn("Can not redirect to {}, because session can not connect to it.", endpoint);
}
}
}
private void handleQueryRedirection(TEndPoint endPoint) throws IoTDBConnectionException {
if (enableQueryRedirection) {
AtomicReference exceptionReference = new AtomicReference<>();
SessionConnection connection =
endPointToSessionConnection.computeIfAbsent(
endPoint,
k -> {
try {
SessionConnection sessionConnection =
constructSessionConnection(this, endPoint, zoneId);
sessionConnection.setEnableRedirect(enableQueryRedirection);
return sessionConnection;
} catch (IoTDBConnectionException ex) {
exceptionReference.set(ex);
return null;
}
});
if (connection == null) {
throw new IoTDBConnectionException(exceptionReference.get());
}
defaultSessionConnection = connection;
}
}
/**
* 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 values)
throws IoTDBConnectionException, StatementExecutionException {
// not vector by default
TSInsertRecordReq request;
try {
request = filterAndGenTSInsertRecordReq(deviceId, time, measurements, types, values, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceId,
time,
measurements.toString());
return;
}
insertRecord(deviceId, request);
}
/**
* insert aligned data in one row, if you want improve your performance, please use
* insertAlignedRecords method or insertTablet method.
*
* @see Session#insertAlignedRecords(List, List, List, List, List)
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecord(
String deviceId,
long time,
List measurements,
List types,
List values)
throws IoTDBConnectionException, StatementExecutionException {
TSInsertRecordReq request;
try {
request = filterAndGenTSInsertRecordReq(deviceId, time, measurements, types, values, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceId,
time,
measurements.toString());
return;
}
insertRecord(deviceId, request);
}
private TSInsertRecordReq filterAndGenTSInsertRecordReq(
String prefixPath,
long time,
List measurements,
List types,
List values,
boolean isAligned)
throws IoTDBConnectionException {
if (hasNull(values)) {
measurements = new ArrayList<>(measurements);
values = new ArrayList<>(values);
types = new ArrayList<>(types);
boolean isAllValuesNull =
filterNullValueAndMeasurement(prefixPath, measurements, types, values);
if (isAllValuesNull) {
throw new NoValidValueException("All inserted data is null.");
}
}
return genTSInsertRecordReq(prefixPath, time, measurements, types, values, isAligned);
}
private TSInsertRecordReq genTSInsertRecordReq(
String prefixPath,
long time,
List measurements,
List types,
List values,
boolean isAligned)
throws IoTDBConnectionException {
TSInsertRecordReq request = new TSInsertRecordReq();
request.setPrefixPath(prefixPath);
request.setTimestamp(time);
request.setMeasurements(measurements);
ByteBuffer buffer = SessionUtils.getValueBuffer(types, values);
request.setValues(buffer);
request.setIsAligned(isAligned);
return request;
}
/**
* 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 values)
throws IoTDBConnectionException, StatementExecutionException {
TSInsertStringRecordReq request;
try {
request = filterAndGenTSInsertStringRecordReq(deviceId, time, measurements, values, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceId,
time,
measurements.toString());
return;
}
insertRecord(deviceId, request);
}
/**
* insert aligned data in one row, if you want improve your performance, please use
* insertAlignedRecords method or insertTablet method.
*
* @see Session#insertAlignedRecords(List, List, List, List, List)
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecord(
String deviceId, long time, List measurements, List values)
throws IoTDBConnectionException, StatementExecutionException {
TSInsertStringRecordReq request;
try {
request = filterAndGenTSInsertStringRecordReq(deviceId, time, measurements, values, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceId,
time,
measurements.toString());
return;
}
insertRecord(deviceId, request);
}
private TSInsertStringRecordReq filterAndGenTSInsertStringRecordReq(
String prefixPath,
long time,
List measurements,
List values,
boolean isAligned) {
if (hasNull(values)) {
measurements = new ArrayList<>(measurements);
values = new ArrayList<>(values);
boolean isAllValueNull =
filterNullValueAndMeasurementWithStringType(values, prefixPath, measurements);
if (isAllValueNull) {
throw new NoValidValueException("All inserted data is null.");
}
}
return genTSInsertStringRecordReq(prefixPath, time, measurements, values, isAligned);
}
private TSInsertStringRecordReq genTSInsertStringRecordReq(
String prefixPath,
long time,
List measurements,
List values,
boolean isAligned) {
TSInsertStringRecordReq request = new TSInsertStringRecordReq();
request.setPrefixPath(prefixPath);
request.setTimestamp(time);
request.setMeasurements(measurements);
request.setValues(values);
request.setIsAligned(isAligned);
return request;
}
/**
* Insert multiple rows, which can reduce the overhead of network. This method is just like jdbc
* executeBatch, we pack some insert request in batch and send them to server. If you want improve
* your performance, please see insertTablet method
*
* Each row is independent, which could have different deviceId, time, number of measurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecords(
List deviceIds,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
int len = deviceIds.size();
if (len != times.size() || len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"deviceIds, times, measurementsList and valuesList's size should be equal");
}
if (enableRedirection) {
insertStringRecordsWithLeaderCache(deviceIds, times, measurementsList, valuesList, false);
} else {
TSInsertStringRecordsReq request;
try {
request =
filterAndGenTSInsertStringRecordsReq(
deviceIds, times, measurementsList, valuesList, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceIds are [{}],times are [{}],measurements are [{}]",
deviceIds.toString(),
times.toString(),
measurementsList.toString());
return;
}
try {
defaultSessionConnection.insertRecords(request);
} catch (RedirectException ignored) {
}
}
}
/**
* When the value is null,filter this,don't use this measurement.
*
* @param times
* @param measurementsList
* @param valuesList
* @param typesList
*/
private void filterNullValueAndMeasurement(
List deviceIds,
List times,
List> measurementsList,
List> valuesList,
List> typesList) {
for (int i = valuesList.size() - 1; i >= 0; i--) {
List values = valuesList.get(i);
List measurements = measurementsList.get(i);
List types = typesList.get(i);
boolean isAllValuesNull =
filterNullValueAndMeasurement(deviceIds.get(i), measurements, types, values);
if (isAllValuesNull) {
valuesList.remove(i);
measurementsList.remove(i);
deviceIds.remove(i);
times.remove(i);
typesList.remove(i);
}
}
if (valuesList.size() == 0) {
throw new NoValidValueException("All inserted data is null.");
}
}
/**
* Filter the null value of list。
*
* @param deviceId
* @param times
* @param measurementsList
* @param typesList
* @param valuesList
*/
private void filterNullValueAndMeasurementOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList) {
for (int i = valuesList.size() - 1; i >= 0; i--) {
List values = valuesList.get(i);
List measurements = measurementsList.get(i);
List types = typesList.get(i);
boolean isAllValuesNull =
filterNullValueAndMeasurement(deviceId, measurements, types, values);
if (isAllValuesNull) {
valuesList.remove(i);
measurementsList.remove(i);
typesList.remove(i);
times.remove(i);
}
}
if (valuesList.size() == 0) {
throw new NoValidValueException("All inserted data is null.");
}
}
/**
* Filter the null value of list。
*
* @param times
* @param deviceId
* @param measurementsList
* @param valuesList
*/
private void filterNullValueAndMeasurementWithStringTypeOfOneDevice(
List times,
String deviceId,
List> measurementsList,
List> valuesList) {
for (int i = valuesList.size() - 1; i >= 0; i--) {
List values = valuesList.get(i);
List measurements = measurementsList.get(i);
boolean isAllValuesNull =
filterNullValueAndMeasurementWithStringType(values, deviceId, measurements);
if (isAllValuesNull) {
valuesList.remove(i);
measurementsList.remove(i);
times.remove(i);
}
}
if (valuesList.size() == 0) {
throw new NoValidValueException("All inserted data is null.");
}
}
/**
* Filter the null object of list。
*
* @param deviceId
* @param measurementsList
* @param types
* @param valuesList
* @return true:all value is null;false:not all null value is null.
*/
private boolean filterNullValueAndMeasurement(
String deviceId,
List measurementsList,
List types,
List valuesList) {
Map nullMap = new HashMap<>();
for (int i = valuesList.size() - 1; i >= 0; i--) {
if (valuesList.get(i) == null) {
nullMap.put(measurementsList.get(i), valuesList.get(i));
valuesList.remove(i);
measurementsList.remove(i);
types.remove(i);
}
}
if (valuesList.size() == 0) {
logger.info("All values of the {} are null,null values are {}", deviceId, nullMap.toString());
return true;
} else {
logger.info("Some values of {} are null,null values are {}", deviceId, nullMap.toString());
}
return false;
}
/**
* Filter the null object of list。
*
* @param prefixPaths devices path。
* @param times
* @param measurementsList
* @param valuesList
* @return true:all values of valuesList are null;false:Not all values of valuesList are null.
*/
private void filterNullValueAndMeasurementWithStringType(
List prefixPaths,
List times,
List> measurementsList,
List> valuesList) {
for (int i = valuesList.size() - 1; i >= 0; i--) {
List values = valuesList.get(i);
List measurements = measurementsList.get(i);
boolean isAllValueNull =
filterNullValueAndMeasurementWithStringType(values, prefixPaths.get(i), measurements);
if (isAllValueNull) {
valuesList.remove(i);
measurementsList.remove(i);
times.remove(i);
prefixPaths.remove(i);
}
}
if (valuesList.size() == 0) {
throw new NoValidValueException("All inserted data is null.");
}
}
/**
* When the value is null,filter this,don't use this measurement.
*
* @param valuesList
* @param measurementsList
* @return true:all value is null;false:not all null value is null.
*/
private boolean filterNullValueAndMeasurementWithStringType(
List valuesList, String deviceId, List measurementsList) {
Map nullMap = new HashMap<>();
for (int i = valuesList.size() - 1; i >= 0; i--) {
if (valuesList.get(i) == null) {
nullMap.put(measurementsList.get(i), valuesList.get(i));
valuesList.remove(i);
measurementsList.remove(i);
}
}
if (valuesList.size() == 0) {
logger.info("All values of the {} are null,null values are {}", deviceId, nullMap.toString());
return true;
} else {
logger.info("Some values of {} are null,null values are {}", deviceId, nullMap.toString());
}
return false;
}
private boolean hasNull(List valuesList) {
boolean haveNull = false;
for (int i1 = 0; i1 < valuesList.size(); i1++) {
Object o = valuesList.get(i1);
if (o instanceof List) {
List o1 = (List) o;
if (hasNull(o1)) {
haveNull = true;
break;
}
} else {
if (o == null) {
haveNull = true;
break;
}
}
}
return haveNull;
}
/**
* Insert aligned multiple rows, which can reduce the overhead of network. This method is just
* like jdbc executeBatch, we pack some insert request in batch and send them to server. If you
* want improve your performance, please see insertTablet method
*
* Each row is independent, which could have different prefixPath, time, number of
* subMeasurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecords(
List deviceIds,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
int len = deviceIds.size();
if (len != times.size() || len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"prefixPaths, times, subMeasurementsList and valuesList's size should be equal");
}
if (enableRedirection) {
insertStringRecordsWithLeaderCache(deviceIds, times, measurementsList, valuesList, true);
} else {
TSInsertStringRecordsReq request;
try {
request =
filterAndGenTSInsertStringRecordsReq(
deviceIds, times, measurementsList, valuesList, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceIds are [{}],times are [{}],measurements are [{}]",
deviceIds.toString(),
times.toString(),
measurementsList.toString());
return;
}
try {
defaultSessionConnection.insertRecords(request);
} catch (RedirectException ignored) {
}
}
}
private void insertStringRecordsWithLeaderCache(
List deviceIds,
List times,
List> measurementsList,
List> valuesList,
boolean isAligned)
throws IoTDBConnectionException, StatementExecutionException {
Map recordsGroup = new HashMap<>();
for (int i = 0; i < deviceIds.size(); i++) {
final SessionConnection connection = getSessionConnection(deviceIds.get(i));
TSInsertStringRecordsReq request =
recordsGroup.getOrDefault(connection, new TSInsertStringRecordsReq());
request.setIsAligned(isAligned);
try {
filterAndUpdateTSInsertStringRecordsReq(
request, deviceIds.get(i), times.get(i), measurementsList.get(i), valuesList.get(i));
recordsGroup.putIfAbsent(connection, request);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements is [{}]",
deviceIds.get(i),
times.get(i),
measurementsList.get(i).toString());
}
}
insertByGroup(recordsGroup, SessionConnection::insertRecords);
}
private TSInsertStringRecordsReq filterAndGenTSInsertStringRecordsReq(
List prefixPaths,
List time,
List> measurements,
List> values,
boolean isAligned) {
if (hasNull(values)) {
values = changeToArrayListWithStringType(values);
measurements = changeToArrayListWithStringType(measurements);
prefixPaths = new ArrayList<>(prefixPaths);
time = new ArrayList<>(time);
filterNullValueAndMeasurementWithStringType(prefixPaths, time, measurements, values);
}
return genTSInsertStringRecordsReq(prefixPaths, time, measurements, values, isAligned);
}
private List> changeToArrayListWithStringType(List> values) {
if (!(values instanceof ArrayList)) {
values = new ArrayList<>(values);
}
for (int i = 0; i < values.size(); i++) {
List currentValue = values.get(i);
if (!(currentValue instanceof ArrayList)) {
values.set(i, new ArrayList<>(currentValue));
}
}
return values;
}
private List> changeToArrayList(List> values) {
if (!(values instanceof ArrayList)) {
values = new ArrayList<>(values);
}
for (int i = 0; i < values.size(); i++) {
List currentValue = values.get(i);
if (!(currentValue instanceof ArrayList)) {
values.set(i, new ArrayList<>(currentValue));
}
}
return values;
}
private List> changeToArrayListWithTSDataType(List> values) {
if (!(values instanceof ArrayList)) {
values = new ArrayList<>(values);
}
for (int i = 0; i < values.size(); i++) {
List currentValue = values.get(i);
if (!(currentValue instanceof ArrayList)) {
values.set(i, new ArrayList<>(currentValue));
}
}
return values;
}
private TSInsertStringRecordsReq genTSInsertStringRecordsReq(
List prefixPaths,
List time,
List> measurements,
List> values,
boolean isAligned) {
TSInsertStringRecordsReq request = new TSInsertStringRecordsReq();
request.setPrefixPaths(prefixPaths);
request.setTimestamps(time);
request.setMeasurementsList(measurements);
request.setValuesList(values);
request.setIsAligned(isAligned);
return request;
}
private void filterAndUpdateTSInsertStringRecordsReq(
TSInsertStringRecordsReq request,
String deviceId,
long time,
List measurements,
List values) {
if (hasNull(values)) {
measurements = new ArrayList<>(measurements);
values = new ArrayList<>(values);
boolean isAllValueNull =
filterNullValueAndMeasurementWithStringType(values, deviceId, measurements);
if (isAllValueNull) {
throw new NoValidValueException("All inserted data is null.");
}
}
updateTSInsertStringRecordsReq(request, deviceId, time, measurements, values);
}
private void updateTSInsertStringRecordsReq(
TSInsertStringRecordsReq request,
String deviceId,
long time,
List measurements,
List values) {
request.addToPrefixPaths(deviceId);
request.addToTimestamps(time);
request.addToMeasurementsList(measurements);
request.addToValuesList(values);
}
/**
* Insert multiple rows, which can reduce the overhead of network. This method is just like jdbc
* executeBatch, we pack some insert request in batch and send them to server. If you want improve
* your performance, please see insertTablet method
*
* Each row is independent, which could have different deviceId, time, number of measurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecords(
List deviceIds,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
int len = deviceIds.size();
if (len != times.size() || len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"deviceIds, times, measurementsList and valuesList's size should be equal");
}
if (enableRedirection) {
insertRecordsWithLeaderCache(
deviceIds, times, measurementsList, typesList, valuesList, false);
} else {
TSInsertRecordsReq request;
try {
request =
filterAndGenTSInsertRecordsReq(
deviceIds, times, measurementsList, typesList, valuesList, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceIds are [{}],times are [{}],measurements are [{}]",
deviceIds.toString(),
times.toString(),
measurementsList.toString());
return;
}
try {
defaultSessionConnection.insertRecords(request);
} catch (RedirectException ignored) {
}
}
}
/**
* Insert aligned multiple rows, which can reduce the overhead of network. This method is just
* like jdbc executeBatch, we pack some insert request in batch and send them to server. If you
* want improve your performance, please see insertTablet method
*
* Each row is independent, which could have different prefixPath, time, number of
* subMeasurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecords(
List deviceIds,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
int len = deviceIds.size();
if (len != times.size() || len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"prefixPaths, times, subMeasurementsList and valuesList's size should be equal");
}
if (enableRedirection) {
insertRecordsWithLeaderCache(deviceIds, times, measurementsList, typesList, valuesList, true);
} else {
TSInsertRecordsReq request;
try {
request =
filterAndGenTSInsertRecordsReq(
deviceIds, times, measurementsList, typesList, valuesList, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceIds are [{}],times are [{}],measurements are [{}]",
deviceIds.toString(),
times.toString(),
measurementsList.toString());
return;
}
try {
defaultSessionConnection.insertRecords(request);
} catch (RedirectException ignored) {
}
}
}
/**
* Insert multiple rows, which can reduce the overhead of network. This method is just like jdbc
* executeBatch, we pack some insert request in batch and send them to server. If you want improve
* your performance, please see insertTablet method
*
* Each row could have same deviceId but different time, number of measurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
insertRecordsOfOneDevice(deviceId, times, measurementsList, typesList, valuesList, false);
}
/**
* Insert multiple rows, which can reduce the overhead of network. This method is just like jdbc
* executeBatch, we pack some insert request in batch and send them to server. If you want improve
* your performance, please see insertTablet method
*
* Each row could have same deviceId but different time, number of measurements
*
* @param haveSorted deprecated, whether the times have been sorted
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, measurementsList and valuesList's size should be equal");
}
TSInsertRecordsOfOneDeviceReq request;
try {
request =
filterAndGenTSInsertRecordsOfOneDeviceReq(
deviceId, times, measurementsList, typesList, valuesList, haveSorted, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],times are [{}],measurements are [{}]",
deviceId,
times.toString(),
measurementsList.toString());
return;
}
try {
getSessionConnection(deviceId).insertRecordsOfOneDevice(request);
} catch (RedirectException e) {
handleRedirection(deviceId, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(deviceId) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(deviceId));
deviceIdToEndpoint.remove(deviceId);
// reconnect with default connection
try {
defaultSessionConnection.insertRecordsOfOneDevice(request);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
/**
* Insert multiple rows with String format data, which can reduce the overhead of network. This
* method is just like jdbc executeBatch, we pack some insert request in batch and send them to
* server. If you want improve your performance, please see insertTablet method
*
* Each row could have same deviceId but different time, number of measurements, number of
* values as String
*
* @param haveSorted deprecated, whether the times have been sorted
*/
@Override
public void insertStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, measurementsList and valuesList's size should be equal");
}
TSInsertStringRecordsOfOneDeviceReq req;
try {
req =
filterAndGenTSInsertStringRecordsOfOneDeviceReq(
deviceId, times, measurementsList, valuesList, haveSorted, false);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],times are [{}],measurements are [{}]",
deviceId,
times.toString(),
measurementsList.toString());
return;
}
try {
getSessionConnection(deviceId).insertStringRecordsOfOneDevice(req);
} catch (RedirectException e) {
handleRedirection(deviceId, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(deviceId) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(deviceId));
deviceIdToEndpoint.remove(deviceId);
// reconnect with default connection
try {
defaultSessionConnection.insertStringRecordsOfOneDevice(req);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
/**
* Insert multiple rows with String format data, which can reduce the overhead of network. This
* method is just like jdbc executeBatch, we pack some insert request in batch and send them to
* server. If you want improve your performance, please see insertTablet method
*
* Each row could have same deviceId but different time, number of measurements, number of
* values as String
*/
@Override
public void insertStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
insertStringRecordsOfOneDevice(deviceId, times, measurementsList, valuesList, false);
}
/**
* Insert aligned multiple rows, which can reduce the overhead of network. This method is just
* like jdbc executeBatch, we pack some insert request in batch and send them to server. If you
* want improve your performance, please see insertTablet method
*
* Each row could have same prefixPath but different time, number of measurements
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
insertAlignedRecordsOfOneDevice(
deviceId, times, measurementsList, typesList, valuesList, false);
}
/**
* Insert aligned multiple rows, which can reduce the overhead of network. This method is just
* like jdbc executeBatch, we pack some insert request in batch and send them to server. If you
* want improve your performance, please see insertTablet method
*
* Each row could have same prefixPath but different time, number of measurements
*
* @param haveSorted deprecated, whether the times have been sorted
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, subMeasurementsList and valuesList's size should be equal");
}
TSInsertRecordsOfOneDeviceReq request;
try {
request =
filterAndGenTSInsertRecordsOfOneDeviceReq(
deviceId, times, measurementsList, typesList, valuesList, haveSorted, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],times are [{}],measurements are [{}]",
deviceId,
times.toString(),
measurementsList.toString());
return;
}
try {
getSessionConnection(deviceId).insertRecordsOfOneDevice(request);
} catch (RedirectException e) {
handleRedirection(deviceId, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(deviceId) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(deviceId));
deviceIdToEndpoint.remove(deviceId);
// reconnect with default connection
try {
defaultSessionConnection.insertRecordsOfOneDevice(request);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
/**
* Insert multiple rows with String format data, which can reduce the overhead of network. This
* method is just like jdbc executeBatch, we pack some insert request in batch and send them to
* server. If you want improve your performance, please see insertTablet method
*
* Each row could have same deviceId but different time, number of measurements, number of
* values as String
*
* @param haveSorted deprecated, whether the times have been sorted
*/
@Override
public void insertAlignedStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted)
throws IoTDBConnectionException, StatementExecutionException {
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, measurementsList and valuesList's size should be equal");
}
TSInsertStringRecordsOfOneDeviceReq req;
try {
req =
filterAndGenTSInsertStringRecordsOfOneDeviceReq(
deviceId, times, measurementsList, valuesList, haveSorted, true);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],times are [{}],measurements are [{}]",
deviceId,
times.toString(),
measurementsList.toString());
return;
}
try {
getSessionConnection(deviceId).insertStringRecordsOfOneDevice(req);
} catch (RedirectException e) {
handleRedirection(deviceId, e.getEndPoint());
} catch (IoTDBConnectionException e) {
if (enableRedirection
&& !deviceIdToEndpoint.isEmpty()
&& deviceIdToEndpoint.get(deviceId) != null) {
logger.warn("Session can not connect to {}", deviceIdToEndpoint.get(deviceId));
deviceIdToEndpoint.remove(deviceId);
// reconnect with default connection
try {
defaultSessionConnection.insertStringRecordsOfOneDevice(req);
} catch (RedirectException ignored) {
}
} else {
throw e;
}
}
}
/**
* Insert aligned multiple rows with String format data, which can reduce the overhead of network.
* This method is just like jdbc executeBatch, we pack some insert request in batch and send them
* to server. If you want improve your performance, please see insertTablet method
*
* Each row could have same prefixPath but different time, number of measurements, number of
* values as String
*
* @see Session#insertTablet(Tablet)
*/
@Override
public void insertAlignedStringRecordsOfOneDevice(
String deviceId,
List times,
List> measurementsList,
List> valuesList)
throws IoTDBConnectionException, StatementExecutionException {
insertAlignedStringRecordsOfOneDevice(deviceId, times, measurementsList, valuesList, false);
}
private TSInsertRecordsOfOneDeviceReq filterAndGenTSInsertRecordsOfOneDeviceReq(
String prefixPath,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted,
boolean isAligned)
throws IoTDBConnectionException, BatchExecutionException {
if (hasNull(valuesList)) {
measurementsList = changeToArrayListWithStringType(measurementsList);
valuesList = changeToArrayList(valuesList);
typesList = changeToArrayListWithTSDataType(typesList);
times = new ArrayList<>(times);
filterNullValueAndMeasurementOfOneDevice(
prefixPath, times, measurementsList, typesList, valuesList);
}
return genTSInsertRecordsOfOneDeviceReq(
prefixPath, times, measurementsList, typesList, valuesList, haveSorted, isAligned);
}
private TSInsertRecordsOfOneDeviceReq genTSInsertRecordsOfOneDeviceReq(
String prefixPath,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean haveSorted,
boolean isAligned)
throws IoTDBConnectionException, BatchExecutionException {
// check params size
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, measurementsList and valuesList's size should be equal");
}
if (!checkSorted(times)) {
// sort
Integer[] index = new Integer[times.size()];
for (int i = 0; i < times.size(); i++) {
index[i] = i;
}
Arrays.sort(index, Comparator.comparingLong(times::get));
times.sort(Long::compareTo);
// sort measurementList
measurementsList = sortList(measurementsList, index);
// sort typesList
typesList = sortList(typesList, index);
// sort values
valuesList = sortList(valuesList, index);
}
TSInsertRecordsOfOneDeviceReq request = new TSInsertRecordsOfOneDeviceReq();
request.setPrefixPath(prefixPath);
request.setTimestamps(times);
request.setMeasurementsList(measurementsList);
List buffersList = objectValuesListToByteBufferList(valuesList, typesList);
request.setValuesList(buffersList);
request.setIsAligned(isAligned);
return request;
}
private TSInsertStringRecordsOfOneDeviceReq filterAndGenTSInsertStringRecordsOfOneDeviceReq(
String prefixPath,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted,
boolean isAligned) {
if (hasNull(valuesList)) {
measurementsList = changeToArrayListWithStringType(measurementsList);
valuesList = changeToArrayListWithStringType(valuesList);
times = new ArrayList<>(times);
filterNullValueAndMeasurementWithStringTypeOfOneDevice(
times, prefixPath, measurementsList, valuesList);
}
return genTSInsertStringRecordsOfOneDeviceReq(
prefixPath, times, measurementsList, valuesList, haveSorted, isAligned);
}
private TSInsertStringRecordsOfOneDeviceReq genTSInsertStringRecordsOfOneDeviceReq(
String prefixPath,
List times,
List> measurementsList,
List> valuesList,
boolean haveSorted,
boolean isAligned) {
// check params size
int len = times.size();
if (len != measurementsList.size() || len != valuesList.size()) {
throw new IllegalArgumentException(
"times, measurementsList and valuesList's size should be equal");
}
if (!checkSorted(times)) {
Integer[] index = new Integer[times.size()];
for (int i = 0; i < index.length; i++) {
index[i] = i;
}
Arrays.sort(index, Comparator.comparingLong(times::get));
times.sort(Long::compareTo);
// sort measurementsList
measurementsList = sortList(measurementsList, index);
// sort valuesList
valuesList = sortList(valuesList, index);
}
TSInsertStringRecordsOfOneDeviceReq req = new TSInsertStringRecordsOfOneDeviceReq();
req.setPrefixPath(prefixPath);
req.setTimestamps(times);
req.setMeasurementsList(measurementsList);
req.setValuesList(valuesList);
req.setIsAligned(isAligned);
return req;
}
/**
* Sort the input source list.
*
* e.g. source: [1,2,3,4,5], index:[1,0,3,2,4], return : [2,1,4,3,5]
*
* @param source Input list
* @param index retuen order
* @param Input type
* @return ordered list
*/
private static List sortList(List source, Integer[] index) {
return Arrays.stream(index).map(source::get).collect(Collectors.toList());
}
private List objectValuesListToByteBufferList(
List> valuesList, List> typesList)
throws IoTDBConnectionException {
List buffersList = new ArrayList<>();
for (int i = 0; i < valuesList.size(); i++) {
ByteBuffer buffer = SessionUtils.getValueBuffer(typesList.get(i), valuesList.get(i));
buffersList.add(buffer);
}
return buffersList;
}
private void insertRecordsWithLeaderCache(
List deviceIds,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean isAligned)
throws IoTDBConnectionException, StatementExecutionException {
Map recordsGroup = new HashMap<>();
for (int i = 0; i < deviceIds.size(); i++) {
final SessionConnection connection = getSessionConnection(deviceIds.get(i));
TSInsertRecordsReq request = recordsGroup.getOrDefault(connection, new TSInsertRecordsReq());
request.setIsAligned(isAligned);
try {
filterAndUpdateTSInsertRecordsReq(
request,
deviceIds.get(i),
times.get(i),
measurementsList.get(i),
typesList.get(i),
valuesList.get(i));
recordsGroup.putIfAbsent(connection, request);
} catch (NoValidValueException e) {
logger.warn(
"All values are null and this submission is ignored,deviceId is [{}],time is [{}],measurements are [{}]",
deviceIds.get(i),
times.get(i),
measurementsList.get(i).toString());
}
}
insertByGroup(recordsGroup, SessionConnection::insertRecords);
}
private TSInsertRecordsReq filterAndGenTSInsertRecordsReq(
List deviceIds,
List times,
List> measurementsList,
List> typesList,
List> valuesList,
boolean isAligned)
throws IoTDBConnectionException {
if (hasNull(valuesList)) {
measurementsList = changeToArrayListWithStringType(measurementsList);
valuesList = changeToArrayList(valuesList);
deviceIds = new ArrayList<>(deviceIds);
times = new ArrayList<>(times);
typesList = changeToArrayListWithTSDataType(typesList);
filterNullValueAndMeasurement(deviceIds, times, measurementsList, valuesList, typesList);
}
return genTSInsertRecordsReq(
deviceIds, times, measurementsList, typesList, valuesList, isAligned);
}
private TSInsertRecordsReq genTSInsertRecordsReq(
List