diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java index b692194382..ec2db21f01 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java @@ -21,17 +21,18 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.thingsboard.server.service.install.update.DefaultDataUpdateService; -import java.util.List; +import java.util.Map; @Service @Slf4j @RequiredArgsConstructor public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSettingsService { - // This list should include all versions that are compatible for the upgrade in 4 digits format (like 4.2.0.0, etc.). - // The compatibility cycle usually breaks when we have some scripts written in Java that may not work after a new release. - // TODO: don't check the "patch" number, since upgrade is not required for patch releases - private static final List SUPPORTED_VERSIONS_FOR_UPGRADE = List.of("4.3.0.0", "4.3.0.1"); + // map of versions from which the upgrade to the current version is possible + // key - supported version prefix, value - display name + private static final Map SUPPORTED_VERSIONS_FOR_UPGRADE = Map.of( + "4.3.0", "4.3.0.x" + ); private final ProjectInfo projectInfo; private final JdbcTemplate jdbcTemplate; @@ -56,9 +57,9 @@ public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSetti onSchemaSettingsError("Upgrade failed: database already upgraded to current version. You can set SKIP_SCHEMA_VERSION_CHECK to 'true' if force re-upgrade needed."); } - if (!SUPPORTED_VERSIONS_FOR_UPGRADE.contains(dbSchemaVersion)) { + if (SUPPORTED_VERSIONS_FOR_UPGRADE.keySet().stream().noneMatch(dbSchemaVersion::startsWith)) { onSchemaSettingsError(String.format("Upgrade failed: database version '%s' is not supported for upgrade. Supported versions are: %s.", - dbSchemaVersion, SUPPORTED_VERSIONS_FOR_UPGRADE + dbSchemaVersion, SUPPORTED_VERSIONS_FOR_UPGRADE.values() )); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/ConstraintValidatorTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/ConstraintValidatorTest.java index 668400423d..ca54775ea2 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/ConstraintValidatorTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/ConstraintValidatorTest.java @@ -16,16 +16,12 @@ package org.thingsboard.server.dao.service; import org.junit.Assert; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.exception.DataValidationException; class ConstraintValidatorTest { - private static final int MIN_IN_MS = 60000; - private static final int _1M = 1_000_000; - @Test void validateFields() { StringDataEntry stringDataEntryValid = new StringDataEntry("key", "value"); @@ -35,16 +31,4 @@ class ConstraintValidatorTest { ConstraintValidator.validateFields(stringDataEntryValid); } - @Test - void validatePerMinute() { - StringDataEntry stringDataEntryValid = new StringDataEntry("key", "value"); - - long start = System.currentTimeMillis(); - for (int i = 0; i < _1M; i++) { - ConstraintValidator.validateFields(stringDataEntryValid); - } - long end = System.currentTimeMillis(); - - Assertions.assertTrue(MIN_IN_MS > end - start); - } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/sql/LatestTimeseriesPerformanceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/sql/LatestTimeseriesPerformanceTest.java deleted file mode 100644 index 100ef1c11e..0000000000 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/sql/LatestTimeseriesPerformanceTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright © 2016-2026 The Thingsboard Authors - * - * 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. - */ -package org.thingsboard.server.dao.service.timeseries.sql; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomStringUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.BooleanDataEntry; -import org.thingsboard.server.common.data.kv.DoubleDataEntry; -import org.thingsboard.server.common.data.kv.LongDataEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.dao.service.AbstractServiceTest; -import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.dao.timeseries.TimeseriesLatestDao; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -@DaoSqlTest -@Slf4j -public class LatestTimeseriesPerformanceTest extends AbstractServiceTest { - - private static final String STRING_KEY = "stringKey"; - private static final String LONG_KEY = "longKey"; - private static final String DOUBLE_KEY = "doubleKey"; - private static final String BOOLEAN_KEY = "booleanKey"; - private static final int AMOUNT_OF_UNIQ_KEY = 10000; - private static final int TIMEOUT = 100; - - private final Random random = new Random(); - - @Autowired - private TimeseriesLatestDao timeseriesLatestDao; - - private ListeningExecutorService testExecutor; - - private EntityId entityId; - - private AtomicLong saveCounter; - - @Before - public void before() { - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = tenantService.saveTenant(tenant); - Assert.assertNotNull(savedTenant); - tenantId = savedTenant.getId(); - entityId = new DeviceId(UUID.randomUUID()); - saveCounter = new AtomicLong(0); - testExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(200, ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-test-scope"))); - } - - @After - public void after() { - tenantService.deleteTenant(tenantId); - if (testExecutor != null) { - testExecutor.shutdownNow(); - } - } - - @Test - public void test_save_latest_timeseries() throws Exception { - warmup(); - saveCounter.set(0); - - long startTime = System.currentTimeMillis(); - List> futures = new ArrayList<>(); - for (int i = 0; i < 25_000; i++) { - futures.add(save(generateStrEntry(getRandomKey()))); - futures.add(save(generateLngEntry(getRandomKey()))); - futures.add(save(generateDblEntry(getRandomKey()))); - futures.add(save(generateBoolEntry(getRandomKey()))); - } - Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - long endTime = System.currentTimeMillis(); - - long totalTime = endTime - startTime; - - log.info("Total time: {}", totalTime); - log.info("Saved count: {}", saveCounter.get()); - log.warn("Saved per 1 sec: {}", saveCounter.get() * 1000 / totalTime); - } - - private void warmup() throws Exception { - List> futures = new ArrayList<>(); - for (int i = 0; i < AMOUNT_OF_UNIQ_KEY; i++) { - futures.add(save(generateStrEntry(i))); - futures.add(save(generateLngEntry(i))); - futures.add(save(generateDblEntry(i))); - futures.add(save(generateBoolEntry(i))); - } - Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - } - - private ListenableFuture save(TsKvEntry tsKvEntry) { - return Futures.transformAsync(testExecutor.submit(() -> timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry)), result -> { - saveCounter.incrementAndGet(); - return result; - }, testExecutor); - } - - private TsKvEntry generateStrEntry(int keyIndex) { - return new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(STRING_KEY + keyIndex, RandomStringUtils.random(10))); - } - - private TsKvEntry generateLngEntry(int keyIndex) { - return new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(LONG_KEY + keyIndex, random.nextLong())); - } - - private TsKvEntry generateDblEntry(int keyIndex) { - return new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry(DOUBLE_KEY + keyIndex, random.nextDouble())); - } - - private TsKvEntry generateBoolEntry(int keyIndex) { - return new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(BOOLEAN_KEY + keyIndex, random.nextBoolean())); - } - - private int getRandomKey() { - return random.nextInt(AMOUNT_OF_UNIQ_KEY); - } - -}