package com.hedera.mirror.grpc.jmeter.handler; /*- * * Hedera Mirror Node * * Copyright (C) 2019 - 2020 Hedera Hashgraph, LLC * * Licensed 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. * */ import java.time.Instant; import java.util.ArrayList; import java.util.List; import lombok.extern.log4j.Log4j2; import org.postgresql.ds.PGSimpleDataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import com.hedera.mirror.grpc.domain.TopicMessage; @Log4j2 public class ConnectionHandler { private static final int BATCH_SIZE = 100; private static final byte[] BYTES = new byte[] {'a', 'b', 'c'}; private final JdbcTemplate jdbcTemplate; public ConnectionHandler(String host, int port, String dbName, String dbUser, String dbPassword) { PGSimpleDataSource dataSource = new PGSimpleDataSource(); dataSource.setPortNumbers(new int[] {port}); dataSource.setServerNames(new String[] {host}); dataSource.setDatabaseName(dbName); dataSource.setPassword(dbPassword); dataSource.setUser(dbUser); jdbcTemplate = new JdbcTemplate(dataSource); } public void createTopic(long topicNum) { String sql = "insert into t_entities" + " (entity_num, entity_realm, entity_shard, fk_entity_type_id)" + " values (?, 0, 0, 4) on conflict do nothing"; jdbcTemplate.update(sql, new Object[] {topicNum}); log.info("Created new Topic {}", topicNum); } public void insertTopicMessage(int newTopicsMessageCount, long topicNum, Instant startTime, long seqStart) { if (newTopicsMessageCount <= 0) { // no messages to create, abort and db logic return; } createTopic(topicNum); long nextSequenceNum = seqStart == -1 ? getNextAvailableSequenceNumber(topicNum) : seqStart; log.info("Inserting {} topic messages starting from sequence number {} and time {}", newTopicsMessageCount, nextSequenceNum, startTime); List<SqlParameterSource> parameterSources = new ArrayList<>(); SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate.getDataSource()) .withTableName("topic_message"); for (int i = 1; i <= newTopicsMessageCount; i++) { long sequenceNum = nextSequenceNum + i; Instant consensusInstant = startTime.plusNanos(sequenceNum); TopicMessage topicMessage = TopicMessage.builder() .consensusTimestamp(consensusInstant) .sequenceNumber(sequenceNum) .message(BYTES) .runningHash(BYTES) .realmNum(0) .build(); parameterSources.add(new BeanPropertySqlParameterSource(topicMessage)); if (i % BATCH_SIZE == 0) { simpleJdbcInsert.executeBatch(parameterSources.toArray(new SqlParameterSource[] {})); parameterSources.clear(); } } if (!parameterSources.isEmpty()) { simpleJdbcInsert.executeBatch(parameterSources.toArray(new SqlParameterSource[] {})); } log.debug("Successfully inserted {} topic messages", newTopicsMessageCount); } public long getNextAvailableSequenceNumber(long topicId) { String sql = "SELECT MAX(sequence_number) FROM topic_message WHERE topic_num = ?"; Long maxSequenceNumber = jdbcTemplate.queryForObject(sql, new Object[] {topicId}, Long.class); long nextSeqNum = maxSequenceNumber != null ? maxSequenceNumber + 1 : 0; log.trace("Next available topic ID sequence number is {}", nextSeqNum); return nextSeqNum; } public void clearTopicMessages(long topicId, long seqNumFrom) { if (topicId < 0 || seqNumFrom < 0) { log.warn("TopicId : {} or SeqNum : {} are outside of acceptable range. clearTopicMessages() will be " + "skipped.", topicId, seqNumFrom); return; } jdbcTemplate .update("delete from topic_message where topic_num = ? and sequence_number >= ?", new Object[] {topicId, seqNumFrom}); log.info("Cleared topic messages for topic ID {} after sequence {}", topicId, seqNumFrom); } }