Commit 6af34cf043da68943fd4aa26c608e548c3140776
Committed by
Andrew Shvayka
1 parent
083dc38c
refactoring ttl cleanup services
Showing
15 changed files
with
312 additions
and
142 deletions
@@ -18,17 +18,18 @@ CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar | @@ -18,17 +18,18 @@ CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar | ||
18 | LANGUAGE plpgsql AS | 18 | LANGUAGE plpgsql AS |
19 | $$ | 19 | $$ |
20 | DECLARE | 20 | DECLARE |
21 | - max_tenant_ttl bigint; | ||
22 | - max_customer_ttl bigint; | ||
23 | - max_ttl bigint; | ||
24 | - date timestamp; | ||
25 | - partition_by_max_ttl_date varchar; | ||
26 | - partition_month varchar; | ||
27 | - partition_day varchar; | ||
28 | - partition_year varchar; | ||
29 | - partition varchar; | ||
30 | - partition_to_delete varchar; | ||
31 | - | 21 | + max_tenant_ttl bigint; |
22 | + max_customer_ttl bigint; | ||
23 | + max_ttl bigint; | ||
24 | + date timestamp; | ||
25 | + partition_by_max_ttl_date varchar; | ||
26 | + partition_by_max_ttl_month varchar; | ||
27 | + partition_by_max_ttl_day varchar; | ||
28 | + partition_by_max_ttl_year varchar; | ||
29 | + partition varchar; | ||
30 | + partition_year integer; | ||
31 | + partition_month integer; | ||
32 | + partition_day integer; | ||
32 | 33 | ||
33 | BEGIN | 34 | BEGIN |
34 | SELECT max(attribute_kv.long_v) | 35 | SELECT max(attribute_kv.long_v) |
@@ -45,53 +46,138 @@ BEGIN | @@ -45,53 +46,138 @@ BEGIN | ||
45 | if max_ttl IS NOT NULL AND max_ttl > 0 THEN | 46 | if max_ttl IS NOT NULL AND max_ttl > 0 THEN |
46 | date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl); | 47 | date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl); |
47 | partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); | 48 | partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); |
49 | + RAISE NOTICE 'Date by max ttl: %', date; | ||
48 | RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; | 50 | RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; |
49 | IF partition_by_max_ttl_date IS NOT NULL THEN | 51 | IF partition_by_max_ttl_date IS NOT NULL THEN |
50 | CASE | 52 | CASE |
51 | WHEN partition_type = 'DAYS' THEN | 53 | WHEN partition_type = 'DAYS' THEN |
52 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | ||
53 | - partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
54 | - partition_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); | 54 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
55 | + partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
56 | + partition_by_max_ttl_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); | ||
55 | WHEN partition_type = 'MONTHS' THEN | 57 | WHEN partition_type = 'MONTHS' THEN |
56 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | ||
57 | - partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | 58 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
59 | + partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
58 | ELSE | 60 | ELSE |
59 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | 61 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
60 | END CASE; | 62 | END CASE; |
61 | - FOR partition IN SELECT tablename | ||
62 | - FROM pg_tables | ||
63 | - WHERE schemaname = 'public' | ||
64 | - AND tablename like 'ts_kv_' || '%' | ||
65 | - AND tablename != 'ts_kv_latest' | ||
66 | - AND tablename != 'ts_kv_dictionary' | ||
67 | - AND tablename != 'ts_kv_indefinite' | ||
68 | - LOOP | ||
69 | - IF partition != partition_by_max_ttl_date THEN | ||
70 | - IF partition_year IS NOT NULL THEN | ||
71 | - IF SPLIT_PART(partition, '_', 3)::integer < partition_year::integer THEN | ||
72 | - partition_to_delete := partition; | ||
73 | - ELSE | ||
74 | - IF partition_month IS NOT NULL THEN | ||
75 | - IF SPLIT_PART(partition, '_', 4)::integer < partition_month::integer THEN | ||
76 | - partition_to_delete := partition; | 63 | + IF partition_by_max_ttl_year IS NULL THEN |
64 | + RAISE NOTICE 'Failed to remove partitions by max ttl date due to partition_by_max_ttl_year is null!'; | ||
65 | + ELSE | ||
66 | + IF partition_type = 'YEARS' THEN | ||
67 | + FOR partition IN SELECT tablename | ||
68 | + FROM pg_tables | ||
69 | + WHERE schemaname = 'public' | ||
70 | + AND tablename like 'ts_kv_' || '%' | ||
71 | + AND tablename != 'ts_kv_latest' | ||
72 | + AND tablename != 'ts_kv_dictionary' | ||
73 | + AND tablename != 'ts_kv_indefinite' | ||
74 | + AND tablename != partition_by_max_ttl_date | ||
75 | + LOOP | ||
76 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
77 | + IF partition_year < partition_by_max_ttl_year::integer THEN | ||
78 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
79 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
80 | + deleted := deleted + 1; | ||
81 | + END IF; | ||
82 | + END LOOP; | ||
83 | + ELSE | ||
84 | + IF partition_type = 'MONTHS' THEN | ||
85 | + IF partition_by_max_ttl_month IS NULL THEN | ||
86 | + RAISE NOTICE 'Failed to remove months partitions by max ttl date due to partition_by_max_ttl_month is null!'; | ||
87 | + ELSE | ||
88 | + FOR partition IN SELECT tablename | ||
89 | + FROM pg_tables | ||
90 | + WHERE schemaname = 'public' | ||
91 | + AND tablename like 'ts_kv_' || '%' | ||
92 | + AND tablename != 'ts_kv_latest' | ||
93 | + AND tablename != 'ts_kv_dictionary' | ||
94 | + AND tablename != 'ts_kv_indefinite' | ||
95 | + AND tablename != partition_by_max_ttl_date | ||
96 | + LOOP | ||
97 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
98 | + IF partition_year > partition_by_max_ttl_year::integer THEN | ||
99 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
100 | + CONTINUE; | ||
77 | ELSE | 101 | ELSE |
78 | - IF partition_day IS NOT NULL THEN | ||
79 | - IF SPLIT_PART(partition, '_', 5)::integer < partition_day::integer THEN | ||
80 | - partition_to_delete := partition; | 102 | + IF partition_year < partition_by_max_ttl_year::integer THEN |
103 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
104 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
105 | + deleted := deleted + 1; | ||
106 | + ELSE | ||
107 | + partition_month := SPLIT_PART(partition, '_', 4)::integer; | ||
108 | + IF partition_year = partition_by_max_ttl_year::integer THEN | ||
109 | + IF partition_month >= partition_by_max_ttl_month::integer THEN | ||
110 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
111 | + CONTINUE; | ||
112 | + ELSE | ||
113 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
114 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
115 | + deleted := deleted + 1; | ||
116 | + END IF; | ||
81 | END IF; | 117 | END IF; |
82 | END IF; | 118 | END IF; |
83 | END IF; | 119 | END IF; |
120 | + END LOOP; | ||
121 | + END IF; | ||
122 | + ELSE | ||
123 | + IF partition_type = 'DAYS' THEN | ||
124 | + IF partition_by_max_ttl_month IS NULL THEN | ||
125 | + RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_month is null!'; | ||
126 | + ELSE | ||
127 | + IF partition_by_max_ttl_day IS NULL THEN | ||
128 | + RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_day is null!'; | ||
129 | + ELSE | ||
130 | + FOR partition IN SELECT tablename | ||
131 | + FROM pg_tables | ||
132 | + WHERE schemaname = 'public' | ||
133 | + AND tablename like 'ts_kv_' || '%' | ||
134 | + AND tablename != 'ts_kv_latest' | ||
135 | + AND tablename != 'ts_kv_dictionary' | ||
136 | + AND tablename != 'ts_kv_indefinite' | ||
137 | + AND tablename != partition_by_max_ttl_date | ||
138 | + LOOP | ||
139 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
140 | + IF partition_year > partition_by_max_ttl_year::integer THEN | ||
141 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
142 | + CONTINUE; | ||
143 | + ELSE | ||
144 | + IF partition_year < partition_by_max_ttl_year::integer THEN | ||
145 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
146 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
147 | + deleted := deleted + 1; | ||
148 | + ELSE | ||
149 | + partition_month := SPLIT_PART(partition, '_', 4)::integer; | ||
150 | + IF partition_month > partition_by_max_ttl_month::integer THEN | ||
151 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
152 | + CONTINUE; | ||
153 | + ELSE | ||
154 | + IF partition_month < partition_by_max_ttl_month::integer THEN | ||
155 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
156 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
157 | + deleted := deleted + 1; | ||
158 | + ELSE | ||
159 | + partition_day := SPLIT_PART(partition, '_', 5)::integer; | ||
160 | + IF partition_day >= partition_by_max_ttl_day::integer THEN | ||
161 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
162 | + CONTINUE; | ||
163 | + ELSE | ||
164 | + IF partition_day < partition_by_max_ttl_day::integer THEN | ||
165 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
166 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
167 | + deleted := deleted + 1; | ||
168 | + END IF; | ||
169 | + END IF; | ||
170 | + END IF; | ||
171 | + END IF; | ||
172 | + END IF; | ||
173 | + END IF; | ||
174 | + END LOOP; | ||
84 | END IF; | 175 | END IF; |
85 | END IF; | 176 | END IF; |
86 | END IF; | 177 | END IF; |
87 | - IF partition_to_delete IS NOT NULL THEN | ||
88 | - RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete; | ||
89 | - EXECUTE format('DROP TABLE IF EXISTS %I', partition_to_delete); | ||
90 | - partition_to_delete := NULL; | ||
91 | - deleted := deleted + 1; | ||
92 | - END IF; | ||
93 | END IF; | 178 | END IF; |
94 | - END LOOP; | 179 | + END IF; |
180 | + END IF; | ||
95 | END IF; | 181 | END IF; |
96 | END IF; | 182 | END IF; |
97 | END | 183 | END |
@@ -107,8 +193,6 @@ BEGIN | @@ -107,8 +193,6 @@ BEGIN | ||
107 | partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); | 193 | partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); |
108 | WHEN partition_type = 'YEARS' THEN | 194 | WHEN partition_type = 'YEARS' THEN |
109 | partition := 'ts_kv_' || to_char(date, 'yyyy'); | 195 | partition := 'ts_kv_' || to_char(date, 'yyyy'); |
110 | - WHEN partition_type = 'INDEFINITE' THEN | ||
111 | - partition := NULL; | ||
112 | ELSE | 196 | ELSE |
113 | partition := NULL; | 197 | partition := NULL; |
114 | END CASE; | 198 | END CASE; |
@@ -45,9 +45,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | @@ -45,9 +45,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | ||
45 | @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") | 45 | @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") |
46 | public void cleanUp() { | 46 | public void cleanUp() { |
47 | if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { | 47 | if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { |
48 | - log.info("Going to cleanup old edge events using ttl: {}s", ttl); | ||
49 | - long totalEdgeEventsRemoved = edgeService.cleanupEvents(ttl); | ||
50 | - log.info("Total edge events removed by TTL: [{}]", totalEdgeEventsRemoved); | 48 | + edgeService.cleanupEvents(ttl); |
51 | } | 49 | } |
52 | } | 50 | } |
53 | 51 |
@@ -48,9 +48,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | @@ -48,9 +48,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | ||
48 | @Scheduled(initialDelayString = "${sql.ttl.events.execution_interval_ms}", fixedDelayString = "${sql.ttl.events.execution_interval_ms}") | 48 | @Scheduled(initialDelayString = "${sql.ttl.events.execution_interval_ms}", fixedDelayString = "${sql.ttl.events.execution_interval_ms}") |
49 | public void cleanUp() { | 49 | public void cleanUp() { |
50 | if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { | 50 | if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { |
51 | - log.info("Going to cleanup old events using debug events ttl: {}s and other events ttl: {}s", debugTtl, ttl); | ||
52 | - long totalEventsRemoved = eventService.cleanupEvents(ttl, debugTtl); | ||
53 | - log.info("Total events removed by TTL: [{}]", totalEventsRemoved); | 51 | + eventService.cleanupEvents(ttl, debugTtl); |
54 | } | 52 | } |
55 | } | 53 | } |
56 | 54 |
@@ -18,11 +18,15 @@ package org.thingsboard.server.service.ttl; | @@ -18,11 +18,15 @@ package org.thingsboard.server.service.ttl; | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.beans.factory.annotation.Value; | 19 | import org.springframework.beans.factory.annotation.Value; |
20 | import org.springframework.scheduling.annotation.Scheduled; | 20 | import org.springframework.scheduling.annotation.Scheduled; |
21 | +import org.springframework.stereotype.Service; | ||
21 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 22 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
22 | import org.thingsboard.server.queue.discovery.PartitionService; | 23 | import org.thingsboard.server.queue.discovery.PartitionService; |
24 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
23 | import org.thingsboard.server.service.ttl.AbstractCleanUpService; | 25 | import org.thingsboard.server.service.ttl.AbstractCleanUpService; |
24 | 26 | ||
27 | +@TbCoreComponent | ||
25 | @Slf4j | 28 | @Slf4j |
29 | +@Service | ||
26 | public class TimeseriesCleanUpService extends AbstractCleanUpService { | 30 | public class TimeseriesCleanUpService extends AbstractCleanUpService { |
27 | 31 | ||
28 | @Value("${sql.ttl.ts.ts_key_value_ttl}") | 32 | @Value("${sql.ttl.ts.ts_key_value_ttl}") |
@@ -94,5 +94,5 @@ public interface EdgeService { | @@ -94,5 +94,5 @@ public interface EdgeService { | ||
94 | 94 | ||
95 | String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId); | 95 | String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId); |
96 | 96 | ||
97 | - long cleanupEvents(long ttl); | 97 | + void cleanupEvents(long ttl); |
98 | } | 98 | } |
@@ -46,6 +46,6 @@ public interface EventService { | @@ -46,6 +46,6 @@ public interface EventService { | ||
46 | 46 | ||
47 | void removeEvents(TenantId tenantId, EntityId entityId); | 47 | void removeEvents(TenantId tenantId, EntityId entityId); |
48 | 48 | ||
49 | - long cleanupEvents(long ttl, long debugTtl); | 49 | + void cleanupEvents(long ttl, long debugTtl); |
50 | 50 | ||
51 | } | 51 | } |
@@ -180,7 +180,6 @@ public interface EdgeDao extends Dao<Edge> { | @@ -180,7 +180,6 @@ public interface EdgeDao extends Dao<Edge> { | ||
180 | /** | 180 | /** |
181 | * Executes stored procedure to cleanup old edge events. | 181 | * Executes stored procedure to cleanup old edge events. |
182 | * @param ttl the ttl for edge events in seconds | 182 | * @param ttl the ttl for edge events in seconds |
183 | - * @return the number of deleted edge events | ||
184 | */ | 183 | */ |
185 | - long cleanupEvents(long ttl); | 184 | + void cleanupEvents(long ttl); |
186 | } | 185 | } |
@@ -628,8 +628,8 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | @@ -628,8 +628,8 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | ||
628 | } | 628 | } |
629 | 629 | ||
630 | @Override | 630 | @Override |
631 | - public long cleanupEvents(long ttl) { | ||
632 | - return edgeDao.cleanupEvents(ttl); | 631 | + public void cleanupEvents(long ttl) { |
632 | + edgeDao.cleanupEvents(ttl); | ||
633 | } | 633 | } |
634 | 634 | ||
635 | private List<RuleChain> findEdgeRuleChains(TenantId tenantId, EdgeId edgeId) { | 635 | private List<RuleChain> findEdgeRuleChains(TenantId tenantId, EdgeId edgeId) { |
@@ -132,8 +132,8 @@ public class BaseEventService implements EventService { | @@ -132,8 +132,8 @@ public class BaseEventService implements EventService { | ||
132 | } | 132 | } |
133 | 133 | ||
134 | @Override | 134 | @Override |
135 | - public long cleanupEvents(long ttl, long debugTtl) { | ||
136 | - return eventDao.cleanupEvents(ttl, debugTtl); | 135 | + public void cleanupEvents(long ttl, long debugTtl) { |
136 | + eventDao.cleanupEvents(ttl, debugTtl); | ||
137 | } | 137 | } |
138 | 138 | ||
139 | private DataValidator<Event> eventValidator = | 139 | private DataValidator<Event> eventValidator = |
@@ -106,7 +106,6 @@ public interface EventDao extends Dao<Event> { | @@ -106,7 +106,6 @@ public interface EventDao extends Dao<Event> { | ||
106 | * Executes stored procedure to cleanup old events. Uses separate ttl for debug and other events. | 106 | * Executes stored procedure to cleanup old events. Uses separate ttl for debug and other events. |
107 | * @param otherEventsTtl the ttl for events in seconds | 107 | * @param otherEventsTtl the ttl for events in seconds |
108 | * @param debugEventsTtl the ttl for debug events in seconds | 108 | * @param debugEventsTtl the ttl for debug events in seconds |
109 | - * @return the number of deleted events | ||
110 | */ | 109 | */ |
111 | - long cleanupEvents(long otherEventsTtl, long debugEventsTtl); | 110 | + void cleanupEvents(long otherEventsTtl, long debugEventsTtl); |
112 | } | 111 | } |
@@ -40,9 +40,9 @@ import org.thingsboard.server.dao.model.sql.EdgeInfoEntity; | @@ -40,9 +40,9 @@ import org.thingsboard.server.dao.model.sql.EdgeInfoEntity; | ||
40 | import org.thingsboard.server.dao.relation.RelationDao; | 40 | import org.thingsboard.server.dao.relation.RelationDao; |
41 | import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; | 41 | import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; |
42 | 42 | ||
43 | -import java.sql.CallableStatement; | 43 | +import java.sql.PreparedStatement; |
44 | +import java.sql.ResultSet; | ||
44 | import java.sql.SQLException; | 45 | import java.sql.SQLException; |
45 | -import java.sql.Types; | ||
46 | import java.util.ArrayList; | 46 | import java.util.ArrayList; |
47 | import java.util.Collections; | 47 | import java.util.Collections; |
48 | import java.util.List; | 48 | import java.util.List; |
@@ -198,17 +198,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple | @@ -198,17 +198,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple | ||
198 | } | 198 | } |
199 | 199 | ||
200 | @Override | 200 | @Override |
201 | - public long cleanupEvents(long ttl) { | 201 | + public void cleanupEvents(long ttl) { |
202 | try { | 202 | try { |
203 | - CallableStatement stmt = dataSource.getConnection().prepareCall("{call cleanup_edge_events_by_ttl(?,?,?)}"); | 203 | + log.info("Going to cleanup old edge events using ttl: {}s", ttl); |
204 | + PreparedStatement stmt = dataSource.getConnection().prepareStatement("call cleanup_edge_events_by_ttl(?,?)"); | ||
204 | stmt.setLong(1, ttl); | 205 | stmt.setLong(1, ttl); |
205 | - stmt.registerOutParameter(3, Types.BIGINT); | ||
206 | - stmt.executeUpdate(); | 206 | + stmt.setLong(2, 0); |
207 | + stmt.execute(); | ||
207 | printWarnings(stmt); | 208 | printWarnings(stmt); |
208 | - return stmt.getLong(3); | 209 | + ResultSet resultSet = stmt.getResultSet(); |
210 | + resultSet.next(); | ||
211 | + log.info("Total edge events removed by TTL: [{}]", resultSet.getLong(1)); | ||
209 | } catch (SQLException e) { | 212 | } catch (SQLException e) { |
210 | - log.error("SQLException occurred during TTL task execution ", e); | ||
211 | - return 0; | 213 | + log.error("SQLException occurred during edge events TTL task execution ", e); |
212 | } | 214 | } |
213 | } | 215 | } |
214 | 216 |
@@ -39,12 +39,9 @@ import org.thingsboard.server.dao.event.EventDao; | @@ -39,12 +39,9 @@ import org.thingsboard.server.dao.event.EventDao; | ||
39 | import org.thingsboard.server.dao.model.sql.EventEntity; | 39 | import org.thingsboard.server.dao.model.sql.EventEntity; |
40 | import org.thingsboard.server.dao.sql.JpaAbstractDao; | 40 | import org.thingsboard.server.dao.sql.JpaAbstractDao; |
41 | 41 | ||
42 | -import javax.sql.DataSource; | ||
43 | -import java.sql.CallableStatement; | 42 | +import java.sql.PreparedStatement; |
43 | +import java.sql.ResultSet; | ||
44 | import java.sql.SQLException; | 44 | import java.sql.SQLException; |
45 | -import java.sql.SQLWarning; | ||
46 | -import java.sql.Statement; | ||
47 | -import java.sql.Types; | ||
48 | import java.util.List; | 45 | import java.util.List; |
49 | import java.util.Objects; | 46 | import java.util.Objects; |
50 | import java.util.Optional; | 47 | import java.util.Optional; |
@@ -262,18 +259,20 @@ public class JpaBaseEventDao extends JpaAbstractDao<EventEntity, Event> implemen | @@ -262,18 +259,20 @@ public class JpaBaseEventDao extends JpaAbstractDao<EventEntity, Event> implemen | ||
262 | } | 259 | } |
263 | 260 | ||
264 | @Override | 261 | @Override |
265 | - public long cleanupEvents(long otherEventsTtl, long debugEventsTtl) { | 262 | + public void cleanupEvents(long otherEventsTtl, long debugEventsTtl) { |
266 | try { | 263 | try { |
267 | - CallableStatement stmt = dataSource.getConnection().prepareCall("{call cleanup_events_by_ttl(?,?,?)}"); | 264 | + log.info("Going to cleanup old events using debug events ttl: {}s and other events ttl: {}s", debugEventsTtl, otherEventsTtl); |
265 | + PreparedStatement stmt = dataSource.getConnection().prepareStatement("call cleanup_events_by_ttl(?,?,?)"); | ||
268 | stmt.setLong(1, otherEventsTtl); | 266 | stmt.setLong(1, otherEventsTtl); |
269 | stmt.setLong(2, debugEventsTtl); | 267 | stmt.setLong(2, debugEventsTtl); |
270 | - stmt.registerOutParameter(3, Types.BIGINT); | ||
271 | - stmt.executeUpdate(); | 268 | + stmt.setLong(3, 0); |
269 | + stmt.execute(); | ||
272 | printWarnings(stmt); | 270 | printWarnings(stmt); |
273 | - return stmt.getLong(3); | 271 | + ResultSet resultSet = stmt.getResultSet(); |
272 | + resultSet.next(); | ||
273 | + log.info("Total events removed by TTL: [{}]", resultSet.getLong(1)); | ||
274 | } catch (SQLException e) { | 274 | } catch (SQLException e) { |
275 | - log.error("SQLException occurred during TTL task execution ", e); | ||
276 | - return 0; | 275 | + log.error("SQLException occurred during events TTL task execution ", e); |
277 | } | 276 | } |
278 | } | 277 | } |
279 | 278 |
@@ -29,9 +29,9 @@ import org.thingsboard.server.dao.model.ModelConstants; | @@ -29,9 +29,9 @@ import org.thingsboard.server.dao.model.ModelConstants; | ||
29 | import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent; | 29 | import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent; |
30 | 30 | ||
31 | import javax.annotation.Nullable; | 31 | import javax.annotation.Nullable; |
32 | -import java.sql.CallableStatement; | 32 | +import java.sql.PreparedStatement; |
33 | +import java.sql.ResultSet; | ||
33 | import java.sql.SQLException; | 34 | import java.sql.SQLException; |
34 | -import java.sql.Types; | ||
35 | import java.util.List; | 35 | import java.util.List; |
36 | import java.util.Objects; | 36 | import java.util.Objects; |
37 | import java.util.concurrent.TimeUnit; | 37 | import java.util.concurrent.TimeUnit; |
@@ -69,15 +69,17 @@ public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseries | @@ -69,15 +69,17 @@ public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseries | ||
69 | public void cleanup(long systemTtl) { | 69 | public void cleanup(long systemTtl) { |
70 | try { | 70 | try { |
71 | log.info("Going to cleanup old timeseries data using ttl: {}s", systemTtl); | 71 | log.info("Going to cleanup old timeseries data using ttl: {}s", systemTtl); |
72 | - CallableStatement stmt = dataSource.getConnection().prepareCall("{call cleanup_timeseries_by_ttl(?,?,?)}"); | 72 | + PreparedStatement stmt = dataSource.getConnection().prepareStatement("call cleanup_timeseries_by_ttl(?,?,?)"); |
73 | stmt.setObject(1, ModelConstants.NULL_UUID); | 73 | stmt.setObject(1, ModelConstants.NULL_UUID); |
74 | stmt.setLong(2, systemTtl); | 74 | stmt.setLong(2, systemTtl); |
75 | - stmt.registerOutParameter(3, Types.BIGINT); | ||
76 | - stmt.executeUpdate(); | 75 | + stmt.setLong(3, 0); |
76 | + stmt.execute(); | ||
77 | printWarnings(stmt); | 77 | printWarnings(stmt); |
78 | - log.info("Total telemetry removed stats by TTL for entities: [{}]", stmt.getLong(3)); | 78 | + ResultSet resultSet = stmt.getResultSet(); |
79 | + resultSet.next(); | ||
80 | + log.info("Total telemetry removed stats by TTL for entities: [{}]", resultSet.getLong(1)); | ||
79 | } catch (SQLException e) { | 81 | } catch (SQLException e) { |
80 | - log.error("SQLException occurred during TTL task execution ", e); | 82 | + log.error("SQLException occurred during timeseries TTL task execution ", e); |
81 | } | 83 | } |
82 | } | 84 | } |
83 | 85 |
@@ -27,7 +27,6 @@ import org.springframework.stereotype.Component; | @@ -27,7 +27,6 @@ import org.springframework.stereotype.Component; | ||
27 | import org.thingsboard.server.common.data.id.EntityId; | 27 | import org.thingsboard.server.common.data.id.EntityId; |
28 | import org.thingsboard.server.common.data.id.TenantId; | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 29 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
30 | -import org.thingsboard.server.dao.model.ModelConstants; | ||
31 | import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity; | 30 | import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity; |
32 | import org.thingsboard.server.dao.sqlts.AbstractChunkedAggregationTimeseriesDao; | 31 | import org.thingsboard.server.dao.sqlts.AbstractChunkedAggregationTimeseriesDao; |
33 | import org.thingsboard.server.dao.sqlts.insert.psql.PsqlPartitioningRepository; | 32 | import org.thingsboard.server.dao.sqlts.insert.psql.PsqlPartitioningRepository; |
@@ -36,9 +35,9 @@ import org.thingsboard.server.dao.timeseries.SqlTsPartitionDate; | @@ -36,9 +35,9 @@ import org.thingsboard.server.dao.timeseries.SqlTsPartitionDate; | ||
36 | import org.thingsboard.server.dao.util.PsqlDao; | 35 | import org.thingsboard.server.dao.util.PsqlDao; |
37 | import org.thingsboard.server.dao.util.SqlTsDao; | 36 | import org.thingsboard.server.dao.util.SqlTsDao; |
38 | 37 | ||
39 | -import java.sql.CallableStatement; | 38 | +import java.sql.PreparedStatement; |
39 | +import java.sql.ResultSet; | ||
40 | import java.sql.SQLException; | 40 | import java.sql.SQLException; |
41 | -import java.sql.Types; | ||
42 | import java.time.Instant; | 41 | import java.time.Instant; |
43 | import java.time.LocalDateTime; | 42 | import java.time.LocalDateTime; |
44 | import java.time.ZoneOffset; | 43 | import java.time.ZoneOffset; |
@@ -107,13 +106,15 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa | @@ -107,13 +106,15 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa | ||
107 | private void cleanupPartitions(long systemTtl) { | 106 | private void cleanupPartitions(long systemTtl) { |
108 | try { | 107 | try { |
109 | log.info("Going to cleanup old timeseries data partitions using partition type: {} and ttl: {}s", partitioning, systemTtl); | 108 | log.info("Going to cleanup old timeseries data partitions using partition type: {} and ttl: {}s", partitioning, systemTtl); |
110 | - CallableStatement stmt = dataSource.getConnection().prepareCall("{call drop_partitions_by_max_ttl(?,?,?)}"); | ||
111 | - stmt.setObject(1, partitioning); | 109 | + PreparedStatement stmt = dataSource.getConnection().prepareStatement("call drop_partitions_by_max_ttl(?,?,?)"); |
110 | + stmt.setString(1, partitioning); | ||
112 | stmt.setLong(2, systemTtl); | 111 | stmt.setLong(2, systemTtl); |
113 | - stmt.registerOutParameter(3, Types.BIGINT); | ||
114 | - stmt.executeUpdate(); | 112 | + stmt.setLong(3, 0); |
113 | + stmt.execute(); | ||
115 | printWarnings(stmt); | 114 | printWarnings(stmt); |
116 | - log.info("Total partitions removed by TTL: [{}]", stmt.getLong(3)); | 115 | + ResultSet resultSet = stmt.getResultSet(); |
116 | + resultSet.next(); | ||
117 | + log.info("Total partitions removed by TTL: [{}]", resultSet.getLong(1)); | ||
117 | } catch (SQLException e) { | 118 | } catch (SQLException e) { |
118 | log.error("SQLException occurred during TTL task execution ", e); | 119 | log.error("SQLException occurred during TTL task execution ", e); |
119 | } | 120 | } |
@@ -38,17 +38,18 @@ CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar | @@ -38,17 +38,18 @@ CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar | ||
38 | LANGUAGE plpgsql AS | 38 | LANGUAGE plpgsql AS |
39 | $$ | 39 | $$ |
40 | DECLARE | 40 | DECLARE |
41 | - max_tenant_ttl bigint; | ||
42 | - max_customer_ttl bigint; | ||
43 | - max_ttl bigint; | ||
44 | - date timestamp; | ||
45 | - partition_by_max_ttl_date varchar; | ||
46 | - partition_month varchar; | ||
47 | - partition_day varchar; | ||
48 | - partition_year varchar; | ||
49 | - partition varchar; | ||
50 | - partition_to_delete varchar; | ||
51 | - | 41 | + max_tenant_ttl bigint; |
42 | + max_customer_ttl bigint; | ||
43 | + max_ttl bigint; | ||
44 | + date timestamp; | ||
45 | + partition_by_max_ttl_date varchar; | ||
46 | + partition_by_max_ttl_month varchar; | ||
47 | + partition_by_max_ttl_day varchar; | ||
48 | + partition_by_max_ttl_year varchar; | ||
49 | + partition varchar; | ||
50 | + partition_year integer; | ||
51 | + partition_month integer; | ||
52 | + partition_day integer; | ||
52 | 53 | ||
53 | BEGIN | 54 | BEGIN |
54 | SELECT max(attribute_kv.long_v) | 55 | SELECT max(attribute_kv.long_v) |
@@ -65,53 +66,138 @@ BEGIN | @@ -65,53 +66,138 @@ BEGIN | ||
65 | if max_ttl IS NOT NULL AND max_ttl > 0 THEN | 66 | if max_ttl IS NOT NULL AND max_ttl > 0 THEN |
66 | date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl); | 67 | date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl); |
67 | partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); | 68 | partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); |
69 | + RAISE NOTICE 'Date by max ttl: %', date; | ||
68 | RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; | 70 | RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; |
69 | IF partition_by_max_ttl_date IS NOT NULL THEN | 71 | IF partition_by_max_ttl_date IS NOT NULL THEN |
70 | CASE | 72 | CASE |
71 | WHEN partition_type = 'DAYS' THEN | 73 | WHEN partition_type = 'DAYS' THEN |
72 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | ||
73 | - partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
74 | - partition_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); | 74 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
75 | + partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
76 | + partition_by_max_ttl_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); | ||
75 | WHEN partition_type = 'MONTHS' THEN | 77 | WHEN partition_type = 'MONTHS' THEN |
76 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | ||
77 | - partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | 78 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
79 | + partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | ||
78 | ELSE | 80 | ELSE |
79 | - partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | 81 | + partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
80 | END CASE; | 82 | END CASE; |
81 | - FOR partition IN SELECT tablename | ||
82 | - FROM pg_tables | ||
83 | - WHERE schemaname = 'public' | ||
84 | - AND tablename like 'ts_kv_' || '%' | ||
85 | - AND tablename != 'ts_kv_latest' | ||
86 | - AND tablename != 'ts_kv_dictionary' | ||
87 | - AND tablename != 'ts_kv_indefinite' | ||
88 | - LOOP | ||
89 | - IF partition != partition_by_max_ttl_date THEN | ||
90 | - IF partition_year IS NOT NULL THEN | ||
91 | - IF SPLIT_PART(partition, '_', 3)::integer < partition_year::integer THEN | ||
92 | - partition_to_delete := partition; | ||
93 | - ELSE | ||
94 | - IF partition_month IS NOT NULL THEN | ||
95 | - IF SPLIT_PART(partition, '_', 4)::integer < partition_month::integer THEN | ||
96 | - partition_to_delete := partition; | 83 | + IF partition_by_max_ttl_year IS NULL THEN |
84 | + RAISE NOTICE 'Failed to remove partitions by max ttl date due to partition_by_max_ttl_year is null!'; | ||
85 | + ELSE | ||
86 | + IF partition_type = 'YEARS' THEN | ||
87 | + FOR partition IN SELECT tablename | ||
88 | + FROM pg_tables | ||
89 | + WHERE schemaname = 'public' | ||
90 | + AND tablename like 'ts_kv_' || '%' | ||
91 | + AND tablename != 'ts_kv_latest' | ||
92 | + AND tablename != 'ts_kv_dictionary' | ||
93 | + AND tablename != 'ts_kv_indefinite' | ||
94 | + AND tablename != partition_by_max_ttl_date | ||
95 | + LOOP | ||
96 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
97 | + IF partition_year < partition_by_max_ttl_year::integer THEN | ||
98 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
99 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
100 | + deleted := deleted + 1; | ||
101 | + END IF; | ||
102 | + END LOOP; | ||
103 | + ELSE | ||
104 | + IF partition_type = 'MONTHS' THEN | ||
105 | + IF partition_by_max_ttl_month IS NULL THEN | ||
106 | + RAISE NOTICE 'Failed to remove months partitions by max ttl date due to partition_by_max_ttl_month is null!'; | ||
107 | + ELSE | ||
108 | + FOR partition IN SELECT tablename | ||
109 | + FROM pg_tables | ||
110 | + WHERE schemaname = 'public' | ||
111 | + AND tablename like 'ts_kv_' || '%' | ||
112 | + AND tablename != 'ts_kv_latest' | ||
113 | + AND tablename != 'ts_kv_dictionary' | ||
114 | + AND tablename != 'ts_kv_indefinite' | ||
115 | + AND tablename != partition_by_max_ttl_date | ||
116 | + LOOP | ||
117 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
118 | + IF partition_year > partition_by_max_ttl_year::integer THEN | ||
119 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
120 | + CONTINUE; | ||
97 | ELSE | 121 | ELSE |
98 | - IF partition_day IS NOT NULL THEN | ||
99 | - IF SPLIT_PART(partition, '_', 5)::integer < partition_day::integer THEN | ||
100 | - partition_to_delete := partition; | 122 | + IF partition_year < partition_by_max_ttl_year::integer THEN |
123 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
124 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
125 | + deleted := deleted + 1; | ||
126 | + ELSE | ||
127 | + partition_month := SPLIT_PART(partition, '_', 4)::integer; | ||
128 | + IF partition_year = partition_by_max_ttl_year::integer THEN | ||
129 | + IF partition_month >= partition_by_max_ttl_month::integer THEN | ||
130 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
131 | + CONTINUE; | ||
132 | + ELSE | ||
133 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
134 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
135 | + deleted := deleted + 1; | ||
136 | + END IF; | ||
101 | END IF; | 137 | END IF; |
102 | END IF; | 138 | END IF; |
103 | END IF; | 139 | END IF; |
140 | + END LOOP; | ||
141 | + END IF; | ||
142 | + ELSE | ||
143 | + IF partition_type = 'DAYS' THEN | ||
144 | + IF partition_by_max_ttl_month IS NULL THEN | ||
145 | + RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_month is null!'; | ||
146 | + ELSE | ||
147 | + IF partition_by_max_ttl_day IS NULL THEN | ||
148 | + RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_day is null!'; | ||
149 | + ELSE | ||
150 | + FOR partition IN SELECT tablename | ||
151 | + FROM pg_tables | ||
152 | + WHERE schemaname = 'public' | ||
153 | + AND tablename like 'ts_kv_' || '%' | ||
154 | + AND tablename != 'ts_kv_latest' | ||
155 | + AND tablename != 'ts_kv_dictionary' | ||
156 | + AND tablename != 'ts_kv_indefinite' | ||
157 | + AND tablename != partition_by_max_ttl_date | ||
158 | + LOOP | ||
159 | + partition_year := SPLIT_PART(partition, '_', 3)::integer; | ||
160 | + IF partition_year > partition_by_max_ttl_year::integer THEN | ||
161 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
162 | + CONTINUE; | ||
163 | + ELSE | ||
164 | + IF partition_year < partition_by_max_ttl_year::integer THEN | ||
165 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
166 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
167 | + deleted := deleted + 1; | ||
168 | + ELSE | ||
169 | + partition_month := SPLIT_PART(partition, '_', 4)::integer; | ||
170 | + IF partition_month > partition_by_max_ttl_month::integer THEN | ||
171 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
172 | + CONTINUE; | ||
173 | + ELSE | ||
174 | + IF partition_month < partition_by_max_ttl_month::integer THEN | ||
175 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
176 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
177 | + deleted := deleted + 1; | ||
178 | + ELSE | ||
179 | + partition_day := SPLIT_PART(partition, '_', 5)::integer; | ||
180 | + IF partition_day >= partition_by_max_ttl_day::integer THEN | ||
181 | + RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; | ||
182 | + CONTINUE; | ||
183 | + ELSE | ||
184 | + IF partition_day < partition_by_max_ttl_day::integer THEN | ||
185 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition; | ||
186 | + EXECUTE format('DROP TABLE IF EXISTS %I', partition); | ||
187 | + deleted := deleted + 1; | ||
188 | + END IF; | ||
189 | + END IF; | ||
190 | + END IF; | ||
191 | + END IF; | ||
192 | + END IF; | ||
193 | + END IF; | ||
194 | + END LOOP; | ||
104 | END IF; | 195 | END IF; |
105 | END IF; | 196 | END IF; |
106 | END IF; | 197 | END IF; |
107 | - IF partition_to_delete IS NOT NULL THEN | ||
108 | - RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete; | ||
109 | - EXECUTE format('DROP TABLE IF EXISTS %I', partition_to_delete); | ||
110 | - partition_to_delete := NULL; | ||
111 | - deleted := deleted + 1; | ||
112 | - END IF; | ||
113 | END IF; | 198 | END IF; |
114 | - END LOOP; | 199 | + END IF; |
200 | + END IF; | ||
115 | END IF; | 201 | END IF; |
116 | END IF; | 202 | END IF; |
117 | END | 203 | END |
@@ -127,8 +213,6 @@ BEGIN | @@ -127,8 +213,6 @@ BEGIN | ||
127 | partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); | 213 | partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); |
128 | WHEN partition_type = 'YEARS' THEN | 214 | WHEN partition_type = 'YEARS' THEN |
129 | partition := 'ts_kv_' || to_char(date, 'yyyy'); | 215 | partition := 'ts_kv_' || to_char(date, 'yyyy'); |
130 | - WHEN partition_type = 'INDEFINITE' THEN | ||
131 | - partition := NULL; | ||
132 | ELSE | 216 | ELSE |
133 | partition := NULL; | 217 | partition := NULL; |
134 | END CASE; | 218 | END CASE; |