Showing
100 changed files
with
1421 additions
and
644 deletions
Too many changes to show.
To preserve performance only 100 of 145 files are displayed.
1 | +-- | |
2 | +-- Copyright © 2016-2020 The Thingsboard Authors | |
3 | +-- | |
4 | +-- Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +-- you may not use this file except in compliance with the License. | |
6 | +-- You may obtain a copy of the License at | |
7 | +-- | |
8 | +-- http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +-- | |
10 | +-- Unless required by applicable law or agreed to in writing, software | |
11 | +-- distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +-- See the License for the specific language governing permissions and | |
14 | +-- limitations under the License. | |
15 | +-- | |
16 | + | |
17 | +CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint) | |
18 | + LANGUAGE plpgsql AS | |
19 | +$$ | |
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 | + | |
32 | + | |
33 | +BEGIN | |
34 | + SELECT max(attribute_kv.long_v) | |
35 | + FROM tenant | |
36 | + INNER JOIN attribute_kv ON tenant.id = attribute_kv.entity_id | |
37 | + WHERE attribute_kv.attribute_key = 'TTL' | |
38 | + into max_tenant_ttl; | |
39 | + SELECT max(attribute_kv.long_v) | |
40 | + FROM customer | |
41 | + INNER JOIN attribute_kv ON customer.id = attribute_kv.entity_id | |
42 | + WHERE attribute_kv.attribute_key = 'TTL' | |
43 | + into max_customer_ttl; | |
44 | + max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl); | |
45 | + if max_ttl IS NOT NULL AND max_ttl > 0 THEN | |
46 | + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000)); | |
47 | + partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); | |
48 | + RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; | |
49 | + IF partition_by_max_ttl_date IS NOT NULL THEN | |
50 | + CASE | |
51 | + 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); | |
55 | + 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 | + ELSE | |
59 | + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | |
60 | + 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 | + LOOP | |
68 | + IF partition != partition_by_max_ttl_date THEN | |
69 | + IF partition_year IS NOT NULL THEN | |
70 | + IF SPLIT_PART(partition, '_', 3)::integer < partition_year::integer THEN | |
71 | + partition_to_delete := partition; | |
72 | + ELSE | |
73 | + IF partition_month IS NOT NULL THEN | |
74 | + IF SPLIT_PART(partition, '_', 4)::integer < partition_month::integer THEN | |
75 | + partition_to_delete := partition; | |
76 | + ELSE | |
77 | + IF partition_day IS NOT NULL THEN | |
78 | + IF SPLIT_PART(partition, '_', 5)::integer < partition_day::integer THEN | |
79 | + partition_to_delete := partition; | |
80 | + END IF; | |
81 | + END IF; | |
82 | + END IF; | |
83 | + END IF; | |
84 | + END IF; | |
85 | + END IF; | |
86 | + 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 %I', partition_to_delete); | |
90 | + deleted := deleted + 1; | |
91 | + END IF; | |
92 | + END LOOP; | |
93 | + END IF; | |
94 | + END IF; | |
95 | +END | |
96 | +$$; | |
97 | + | |
98 | +CREATE OR REPLACE FUNCTION get_partition_by_max_ttl_date(IN partition_type varchar, IN date timestamp, OUT partition varchar) AS | |
99 | +$$ | |
100 | +BEGIN | |
101 | + CASE | |
102 | + WHEN partition_type = 'DAYS' THEN | |
103 | + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM') || '_' || to_char(date, 'dd'); | |
104 | + WHEN partition_type = 'MONTHS' THEN | |
105 | + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); | |
106 | + WHEN partition_type = 'YEARS' THEN | |
107 | + partition := 'ts_kv_' || to_char(date, 'yyyy'); | |
108 | + WHEN partition_type = 'INDEFINITE' THEN | |
109 | + partition := NULL; | |
110 | + ELSE | |
111 | + partition := NULL; | |
112 | + END CASE; | |
113 | + IF partition IS NOT NULL THEN | |
114 | + IF NOT EXISTS(SELECT | |
115 | + FROM pg_tables | |
116 | + WHERE schemaname = 'public' | |
117 | + AND tablename = partition) THEN | |
118 | + partition := NULL; | |
119 | + RAISE NOTICE 'Failed to found partition by ttl'; | |
120 | + END IF; | |
121 | + END IF; | |
122 | +END; | |
123 | +$$ LANGUAGE plpgsql; | ... | ... |
... | ... | @@ -14,33 +14,9 @@ |
14 | 14 | -- limitations under the License. |
15 | 15 | -- |
16 | 16 | |
17 | --- select check_version(); | |
17 | +-- call create_partition_ts_kv_table(); | |
18 | 18 | |
19 | -CREATE OR REPLACE FUNCTION check_version() RETURNS boolean AS $$ | |
20 | -DECLARE | |
21 | - current_version integer; | |
22 | - valid_version boolean; | |
23 | -BEGIN | |
24 | - RAISE NOTICE 'Check the current installed PostgreSQL version...'; | |
25 | - SELECT current_setting('server_version_num') INTO current_version; | |
26 | - IF current_version < 100000 THEN | |
27 | - valid_version := FALSE; | |
28 | - ELSE | |
29 | - valid_version := TRUE; | |
30 | - END IF; | |
31 | - IF valid_version = FALSE THEN | |
32 | - RAISE NOTICE 'Postgres version should be at least more than 10!'; | |
33 | - ELSE | |
34 | - RAISE NOTICE 'PostgreSQL version is valid!'; | |
35 | - RAISE NOTICE 'Schema update started...'; | |
36 | - END IF; | |
37 | - RETURN valid_version; | |
38 | -END; | |
39 | -$$ LANGUAGE 'plpgsql'; | |
40 | - | |
41 | --- select create_partition_ts_kv_table(); | |
42 | - | |
43 | -CREATE OR REPLACE FUNCTION create_partition_ts_kv_table() RETURNS VOID AS $$ | |
19 | +CREATE OR REPLACE PROCEDURE create_partition_ts_kv_table() LANGUAGE plpgsql AS $$ | |
44 | 20 | |
45 | 21 | BEGIN |
46 | 22 | ALTER TABLE ts_kv |
... | ... | @@ -57,11 +33,11 @@ BEGIN |
57 | 33 | ALTER TABLE ts_kv |
58 | 34 | ALTER COLUMN key TYPE integer USING key::integer; |
59 | 35 | END; |
60 | -$$ LANGUAGE 'plpgsql'; | |
36 | +$$; | |
61 | 37 | |
62 | --- select create_new_ts_kv_latest_table(); | |
38 | +-- call create_new_ts_kv_latest_table(); | |
63 | 39 | |
64 | -CREATE OR REPLACE FUNCTION create_new_ts_kv_latest_table() RETURNS VOID AS $$ | |
40 | +CREATE OR REPLACE PROCEDURE create_new_ts_kv_latest_table() LANGUAGE plpgsql AS $$ | |
65 | 41 | |
66 | 42 | BEGIN |
67 | 43 | ALTER TABLE ts_kv_latest |
... | ... | @@ -81,13 +57,13 @@ BEGIN |
81 | 57 | ALTER TABLE ts_kv_latest |
82 | 58 | ADD CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key); |
83 | 59 | END; |
84 | -$$ LANGUAGE 'plpgsql'; | |
60 | +$$; | |
61 | + | |
85 | 62 | |
63 | +-- call create_partitions(); | |
86 | 64 | |
87 | --- select create_partitions(); | |
65 | +CREATE OR REPLACE PROCEDURE create_partitions() LANGUAGE plpgsql AS $$ | |
88 | 66 | |
89 | -CREATE OR REPLACE FUNCTION create_partitions() RETURNS VOID AS | |
90 | -$$ | |
91 | 67 | DECLARE |
92 | 68 | partition_date varchar; |
93 | 69 | from_ts bigint; |
... | ... | @@ -111,11 +87,11 @@ BEGIN |
111 | 87 | |
112 | 88 | CLOSE key_cursor; |
113 | 89 | END; |
114 | -$$ language 'plpgsql'; | |
90 | +$$; | |
115 | 91 | |
116 | --- select create_ts_kv_dictionary_table(); | |
92 | +-- call create_ts_kv_dictionary_table(); | |
117 | 93 | |
118 | -CREATE OR REPLACE FUNCTION create_ts_kv_dictionary_table() RETURNS VOID AS $$ | |
94 | +CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() LANGUAGE plpgsql AS $$ | |
119 | 95 | |
120 | 96 | BEGIN |
121 | 97 | CREATE TABLE IF NOT EXISTS ts_kv_dictionary |
... | ... | @@ -125,12 +101,12 @@ BEGIN |
125 | 101 | CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
126 | 102 | ); |
127 | 103 | END; |
128 | -$$ LANGUAGE 'plpgsql'; | |
104 | +$$; | |
105 | + | |
106 | +-- call insert_into_dictionary(); | |
129 | 107 | |
130 | --- select insert_into_dictionary(); | |
108 | +CREATE OR REPLACE PROCEDURE insert_into_dictionary() LANGUAGE plpgsql AS $$ | |
131 | 109 | |
132 | -CREATE OR REPLACE FUNCTION insert_into_dictionary() RETURNS VOID AS | |
133 | -$$ | |
134 | 110 | DECLARE |
135 | 111 | insert_record RECORD; |
136 | 112 | key_cursor CURSOR FOR SELECT DISTINCT key |
... | ... | @@ -150,28 +126,27 @@ BEGIN |
150 | 126 | END LOOP; |
151 | 127 | CLOSE key_cursor; |
152 | 128 | END; |
153 | -$$ language 'plpgsql'; | |
129 | +$$; | |
154 | 130 | |
155 | --- select insert_into_ts_kv(); | |
131 | +-- call insert_into_ts_kv(); | |
156 | 132 | |
157 | -CREATE OR REPLACE FUNCTION insert_into_ts_kv() RETURNS void AS | |
158 | -$$ | |
133 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$ | |
159 | 134 | DECLARE |
160 | 135 | insert_size CONSTANT integer := 10000; |
161 | 136 | insert_counter integer DEFAULT 0; |
162 | 137 | insert_record RECORD; |
163 | - insert_cursor CURSOR FOR SELECT CONCAT(first_part_uuid, '-', second_part_uuid, '-1', third_part_uuid, '-', fourth_part_uuid, '-', fifth_part_uuid)::uuid AS entity_id, | |
138 | + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
164 | 139 | ts_kv_records.key AS key, |
165 | 140 | ts_kv_records.ts AS ts, |
166 | 141 | ts_kv_records.bool_v AS bool_v, |
167 | 142 | ts_kv_records.str_v AS str_v, |
168 | 143 | ts_kv_records.long_v AS long_v, |
169 | 144 | ts_kv_records.dbl_v AS dbl_v |
170 | - FROM (SELECT SUBSTRING(entity_id, 8, 8) AS first_part_uuid, | |
171 | - SUBSTRING(entity_id, 4, 4) AS second_part_uuid, | |
172 | - SUBSTRING(entity_id, 1, 3) AS third_part_uuid, | |
173 | - SUBSTRING(entity_id, 16, 4) AS fourth_part_uuid, | |
174 | - SUBSTRING(entity_id, 20) AS fifth_part_uuid, | |
145 | + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
146 | + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
147 | + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
148 | + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
149 | + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
175 | 150 | key_id AS key, |
176 | 151 | ts, |
177 | 152 | bool_v, |
... | ... | @@ -198,28 +173,27 @@ BEGIN |
198 | 173 | END LOOP; |
199 | 174 | CLOSE insert_cursor; |
200 | 175 | END; |
201 | -$$ LANGUAGE 'plpgsql'; | |
176 | +$$; | |
202 | 177 | |
203 | --- select insert_into_ts_kv_latest(); | |
178 | +-- call insert_into_ts_kv_latest(); | |
204 | 179 | |
205 | -CREATE OR REPLACE FUNCTION insert_into_ts_kv_latest() RETURNS void AS | |
206 | -$$ | |
180 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest() LANGUAGE plpgsql AS $$ | |
207 | 181 | DECLARE |
208 | 182 | insert_size CONSTANT integer := 10000; |
209 | 183 | insert_counter integer DEFAULT 0; |
210 | 184 | insert_record RECORD; |
211 | - insert_cursor CURSOR FOR SELECT CONCAT(first_part_uuid, '-', second_part_uuid, '-1', third_part_uuid, '-', fourth_part_uuid, '-', fifth_part_uuid)::uuid AS entity_id, | |
185 | + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
212 | 186 | ts_kv_latest_records.key AS key, |
213 | 187 | ts_kv_latest_records.ts AS ts, |
214 | 188 | ts_kv_latest_records.bool_v AS bool_v, |
215 | 189 | ts_kv_latest_records.str_v AS str_v, |
216 | 190 | ts_kv_latest_records.long_v AS long_v, |
217 | 191 | ts_kv_latest_records.dbl_v AS dbl_v |
218 | - FROM (SELECT SUBSTRING(entity_id, 8, 8) AS first_part_uuid, | |
219 | - SUBSTRING(entity_id, 4, 4) AS second_part_uuid, | |
220 | - SUBSTRING(entity_id, 1, 3) AS third_part_uuid, | |
221 | - SUBSTRING(entity_id, 16, 4) AS fourth_part_uuid, | |
222 | - SUBSTRING(entity_id, 20) AS fifth_part_uuid, | |
192 | + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
193 | + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
194 | + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
195 | + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
196 | + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
223 | 197 | key_id AS key, |
224 | 198 | ts, |
225 | 199 | bool_v, |
... | ... | @@ -246,6 +220,6 @@ BEGIN |
246 | 220 | END LOOP; |
247 | 221 | CLOSE insert_cursor; |
248 | 222 | END; |
249 | -$$ LANGUAGE 'plpgsql'; | |
223 | +$$; | |
250 | 224 | |
251 | 225 | ... | ... |
... | ... | @@ -14,60 +14,32 @@ |
14 | 14 | -- limitations under the License. |
15 | 15 | -- |
16 | 16 | |
17 | --- select check_version(); | |
17 | +-- call create_new_ts_kv_table(); | |
18 | 18 | |
19 | -CREATE OR REPLACE FUNCTION check_version() RETURNS boolean AS $$ | |
20 | -DECLARE | |
21 | - current_version integer; | |
22 | - valid_version boolean; | |
23 | -BEGIN | |
24 | - RAISE NOTICE 'Check the current installed PostgreSQL version...'; | |
25 | - SELECT current_setting('server_version_num') INTO current_version; | |
26 | - IF current_version < 90600 THEN | |
27 | - valid_version := FALSE; | |
28 | - ELSE | |
29 | - valid_version := TRUE; | |
30 | - END IF; | |
31 | - IF valid_version = FALSE THEN | |
32 | - RAISE NOTICE 'Postgres version should be at least more than 9.6!'; | |
33 | - ELSE | |
34 | - RAISE NOTICE 'PostgreSQL version is valid!'; | |
35 | - RAISE NOTICE 'Schema update started...'; | |
36 | - END IF; | |
37 | - RETURN valid_version; | |
38 | -END; | |
39 | -$$ LANGUAGE 'plpgsql'; | |
40 | - | |
41 | --- select create_new_tenant_ts_kv_table(); | |
42 | - | |
43 | -CREATE OR REPLACE FUNCTION create_new_tenant_ts_kv_table() RETURNS VOID AS $$ | |
19 | +CREATE OR REPLACE PROCEDURE create_new_ts_kv_table() LANGUAGE plpgsql AS $$ | |
44 | 20 | |
45 | 21 | BEGIN |
46 | 22 | ALTER TABLE tenant_ts_kv |
47 | 23 | RENAME TO tenant_ts_kv_old; |
48 | - CREATE TABLE IF NOT EXISTS tenant_ts_kv | |
24 | + CREATE TABLE IF NOT EXISTS ts_kv | |
49 | 25 | ( |
50 | 26 | LIKE tenant_ts_kv_old |
51 | 27 | ); |
52 | - ALTER TABLE tenant_ts_kv | |
53 | - ALTER COLUMN tenant_id TYPE uuid USING tenant_id::uuid; | |
54 | - ALTER TABLE tenant_ts_kv | |
55 | - ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
56 | - ALTER TABLE tenant_ts_kv | |
57 | - ALTER COLUMN key TYPE integer USING key::integer; | |
58 | - ALTER TABLE tenant_ts_kv | |
59 | - ADD CONSTRAINT tenant_ts_kv_pkey PRIMARY KEY(tenant_id, entity_id, key, ts); | |
28 | + ALTER TABLE ts_kv ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
29 | + ALTER TABLE ts_kv ALTER COLUMN key TYPE integer USING key::integer; | |
30 | + ALTER INDEX ts_kv_pkey RENAME TO tenant_ts_kv_pkey_old; | |
60 | 31 | ALTER INDEX idx_tenant_ts_kv RENAME TO idx_tenant_ts_kv_old; |
61 | 32 | ALTER INDEX tenant_ts_kv_ts_idx RENAME TO tenant_ts_kv_ts_idx_old; |
62 | --- PERFORM create_hypertable('tenant_ts_kv', 'ts', chunk_time_interval => 86400000, if_not_exists => true); | |
63 | - CREATE INDEX IF NOT EXISTS idx_tenant_ts_kv ON tenant_ts_kv(tenant_id, entity_id, key, ts); | |
33 | + ALTER TABLE ts_kv ADD CONSTRAINT ts_kv_pkey PRIMARY KEY(entity_id, key, ts); | |
34 | +-- CREATE INDEX IF NOT EXISTS ts_kv_ts_idx ON ts_kv(ts DESC); | |
35 | + ALTER TABLE ts_kv DROP COLUMN IF EXISTS tenant_id; | |
64 | 36 | END; |
65 | -$$ LANGUAGE 'plpgsql'; | |
37 | +$$; | |
66 | 38 | |
67 | 39 | |
68 | --- select create_ts_kv_latest_table(); | |
40 | +-- call create_ts_kv_latest_table(); | |
69 | 41 | |
70 | -CREATE OR REPLACE FUNCTION create_ts_kv_latest_table() RETURNS VOID AS $$ | |
42 | +CREATE OR REPLACE PROCEDURE create_ts_kv_latest_table() LANGUAGE plpgsql AS $$ | |
71 | 43 | |
72 | 44 | BEGIN |
73 | 45 | CREATE TABLE IF NOT EXISTS ts_kv_latest |
... | ... | @@ -82,12 +54,12 @@ BEGIN |
82 | 54 | CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) |
83 | 55 | ); |
84 | 56 | END; |
85 | -$$ LANGUAGE 'plpgsql'; | |
57 | +$$; | |
86 | 58 | |
87 | 59 | |
88 | --- select create_ts_kv_dictionary_table(); | |
60 | +-- call create_ts_kv_dictionary_table(); | |
89 | 61 | |
90 | -CREATE OR REPLACE FUNCTION create_ts_kv_dictionary_table() RETURNS VOID AS $$ | |
62 | +CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() LANGUAGE plpgsql AS $$ | |
91 | 63 | |
92 | 64 | BEGIN |
93 | 65 | CREATE TABLE IF NOT EXISTS ts_kv_dictionary |
... | ... | @@ -97,12 +69,12 @@ BEGIN |
97 | 69 | CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
98 | 70 | ); |
99 | 71 | END; |
100 | -$$ LANGUAGE 'plpgsql'; | |
72 | +$$; | |
101 | 73 | |
102 | --- select insert_into_dictionary(); | |
74 | +-- call insert_into_dictionary(); | |
75 | + | |
76 | +CREATE OR REPLACE PROCEDURE insert_into_dictionary() LANGUAGE plpgsql AS $$ | |
103 | 77 | |
104 | -CREATE OR REPLACE FUNCTION insert_into_dictionary() RETURNS VOID AS | |
105 | -$$ | |
106 | 78 | DECLARE |
107 | 79 | insert_record RECORD; |
108 | 80 | key_cursor CURSOR FOR SELECT DISTINCT key |
... | ... | @@ -122,34 +94,28 @@ BEGIN |
122 | 94 | END LOOP; |
123 | 95 | CLOSE key_cursor; |
124 | 96 | END; |
125 | -$$ language 'plpgsql'; | |
97 | +$$; | |
98 | + | |
99 | +-- call insert_into_ts_kv(); | |
126 | 100 | |
127 | --- select insert_into_tenant_ts_kv(); | |
101 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$ | |
128 | 102 | |
129 | -CREATE OR REPLACE FUNCTION insert_into_tenant_ts_kv() RETURNS void AS | |
130 | -$$ | |
131 | 103 | DECLARE |
132 | 104 | insert_size CONSTANT integer := 10000; |
133 | 105 | insert_counter integer DEFAULT 0; |
134 | 106 | insert_record RECORD; |
135 | - insert_cursor CURSOR FOR SELECT CONCAT(tenant_id_first_part_uuid, '-', tenant_id_second_part_uuid, '-1', tenant_id_third_part_uuid, '-', tenant_id_fourth_part_uuid, '-', tenant_id_fifth_part_uuid)::uuid AS tenant_id, | |
136 | - CONCAT(entity_id_first_part_uuid, '-', entity_id_second_part_uuid, '-1', entity_id_third_part_uuid, '-', entity_id_fourth_part_uuid, '-', entity_id_fifth_part_uuid)::uuid AS entity_id, | |
137 | - tenant_ts_kv_records.key AS key, | |
138 | - tenant_ts_kv_records.ts AS ts, | |
139 | - tenant_ts_kv_records.bool_v AS bool_v, | |
140 | - tenant_ts_kv_records.str_v AS str_v, | |
141 | - tenant_ts_kv_records.long_v AS long_v, | |
142 | - tenant_ts_kv_records.dbl_v AS dbl_v | |
143 | - FROM (SELECT SUBSTRING(tenant_id, 8, 8) AS tenant_id_first_part_uuid, | |
144 | - SUBSTRING(tenant_id, 4, 4) AS tenant_id_second_part_uuid, | |
145 | - SUBSTRING(tenant_id, 1, 3) AS tenant_id_third_part_uuid, | |
146 | - SUBSTRING(tenant_id, 16, 4) AS tenant_id_fourth_part_uuid, | |
147 | - SUBSTRING(tenant_id, 20) AS tenant_id_fifth_part_uuid, | |
148 | - SUBSTRING(entity_id, 8, 8) AS entity_id_first_part_uuid, | |
149 | - SUBSTRING(entity_id, 4, 4) AS entity_id_second_part_uuid, | |
150 | - SUBSTRING(entity_id, 1, 3) AS entity_id_third_part_uuid, | |
151 | - SUBSTRING(entity_id, 16, 4) AS entity_id_fourth_part_uuid, | |
152 | - SUBSTRING(entity_id, 20) AS entity_id_fifth_part_uuid, | |
107 | + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
108 | + new_ts_kv_records.key AS key, | |
109 | + new_ts_kv_records.ts AS ts, | |
110 | + new_ts_kv_records.bool_v AS bool_v, | |
111 | + new_ts_kv_records.str_v AS str_v, | |
112 | + new_ts_kv_records.long_v AS long_v, | |
113 | + new_ts_kv_records.dbl_v AS dbl_v | |
114 | + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
115 | + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
116 | + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
117 | + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
118 | + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
153 | 119 | key_id AS key, |
154 | 120 | ts, |
155 | 121 | bool_v, |
... | ... | @@ -157,31 +123,31 @@ DECLARE |
157 | 123 | long_v, |
158 | 124 | dbl_v |
159 | 125 | FROM tenant_ts_kv_old |
160 | - INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS tenant_ts_kv_records; | |
126 | + INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS new_ts_kv_records; | |
161 | 127 | BEGIN |
162 | 128 | OPEN insert_cursor; |
163 | 129 | LOOP |
164 | 130 | insert_counter := insert_counter + 1; |
165 | 131 | FETCH insert_cursor INTO insert_record; |
166 | 132 | IF NOT FOUND THEN |
167 | - RAISE NOTICE '% records have been inserted into the new tenant_ts_kv table!',insert_counter - 1; | |
133 | + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter - 1; | |
168 | 134 | EXIT; |
169 | 135 | END IF; |
170 | - INSERT INTO tenant_ts_kv(tenant_id, entity_id, key, ts, bool_v, str_v, long_v, dbl_v) | |
171 | - VALUES (insert_record.tenant_id, insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, | |
136 | + INSERT INTO ts_kv(entity_id, key, ts, bool_v, str_v, long_v, dbl_v) | |
137 | + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, | |
172 | 138 | insert_record.long_v, insert_record.dbl_v); |
173 | 139 | IF MOD(insert_counter, insert_size) = 0 THEN |
174 | - RAISE NOTICE '% records have been inserted into the new tenant_ts_kv table!',insert_counter; | |
140 | + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter; | |
175 | 141 | END IF; |
176 | 142 | END LOOP; |
177 | 143 | CLOSE insert_cursor; |
178 | 144 | END; |
179 | -$$ LANGUAGE 'plpgsql'; | |
145 | +$$; | |
146 | + | |
147 | +-- call insert_into_ts_kv_latest(); | |
180 | 148 | |
181 | --- select insert_into_ts_kv_latest(); | |
149 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest() LANGUAGE plpgsql AS $$ | |
182 | 150 | |
183 | -CREATE OR REPLACE FUNCTION insert_into_ts_kv_latest() RETURNS void AS | |
184 | -$$ | |
185 | 151 | DECLARE |
186 | 152 | insert_size CONSTANT integer := 10000; |
187 | 153 | insert_counter integer DEFAULT 0; |
... | ... | @@ -191,7 +157,7 @@ DECLARE |
191 | 157 | latest_records.key AS key, |
192 | 158 | latest_records.entity_id AS entity_id, |
193 | 159 | latest_records.ts AS ts |
194 | - FROM (SELECT DISTINCT key AS key, entity_id AS entity_id, MAX(ts) AS ts FROM tenant_ts_kv GROUP BY key, entity_id) AS latest_records; | |
160 | + FROM (SELECT DISTINCT key AS key, entity_id AS entity_id, MAX(ts) AS ts FROM ts_kv GROUP BY key, entity_id) AS latest_records; | |
195 | 161 | BEGIN |
196 | 162 | OPEN insert_cursor; |
197 | 163 | LOOP |
... | ... | @@ -201,7 +167,7 @@ BEGIN |
201 | 167 | RAISE NOTICE '% records have been inserted into the ts_kv_latest table!',insert_counter - 1; |
202 | 168 | EXIT; |
203 | 169 | END IF; |
204 | - SELECT entity_id AS entity_id, key AS key, ts AS ts, bool_v AS bool_v, str_v AS str_v, long_v AS long_v, dbl_v AS dbl_v INTO insert_record FROM tenant_ts_kv WHERE entity_id = latest_record.entity_id AND key = latest_record.key AND ts = latest_record.ts; | |
170 | + SELECT entity_id AS entity_id, key AS key, ts AS ts, bool_v AS bool_v, str_v AS str_v, long_v AS long_v, dbl_v AS dbl_v INTO insert_record FROM ts_kv WHERE entity_id = latest_record.entity_id AND key = latest_record.key AND ts = latest_record.ts; | |
205 | 171 | INSERT INTO ts_kv_latest(entity_id, key, ts, bool_v, str_v, long_v, dbl_v) |
206 | 172 | VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, insert_record.long_v, insert_record.dbl_v); |
207 | 173 | IF MOD(insert_counter, insert_size) = 0 THEN |
... | ... | @@ -210,4 +176,4 @@ BEGIN |
210 | 176 | END LOOP; |
211 | 177 | CLOSE insert_cursor; |
212 | 178 | END; |
213 | -$$ LANGUAGE 'plpgsql'; | |
179 | +$$; | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2020 The Thingsboard Authors | |
3 | +-- | |
4 | +-- Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +-- you may not use this file except in compliance with the License. | |
6 | +-- You may obtain a copy of the License at | |
7 | +-- | |
8 | +-- http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +-- | |
10 | +-- Unless required by applicable law or agreed to in writing, software | |
11 | +-- distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +-- See the License for the specific language governing permissions and | |
14 | +-- limitations under the License. | |
15 | +-- | |
16 | + | |
17 | +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS | |
18 | +$$ | |
19 | +BEGIN | |
20 | + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || | |
21 | + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); | |
22 | +END; | |
23 | +$$ LANGUAGE plpgsql; | |
24 | + | |
25 | +CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
26 | + OUT deleted bigint) AS | |
27 | +$$ | |
28 | +BEGIN | |
29 | + EXECUTE format( | |
30 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(device.id) as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
31 | + tenant_id, customer_id, ttl) into deleted; | |
32 | +END; | |
33 | +$$ LANGUAGE plpgsql; | |
34 | + | |
35 | +CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
36 | + OUT deleted bigint) AS | |
37 | +$$ | |
38 | +BEGIN | |
39 | + EXECUTE format( | |
40 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(asset.id) as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
41 | + tenant_id, customer_id, ttl) into deleted; | |
42 | +END; | |
43 | +$$ LANGUAGE plpgsql; | |
44 | + | |
45 | +CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
46 | + OUT deleted bigint) AS | |
47 | +$$ | |
48 | +BEGIN | |
49 | + EXECUTE format( | |
50 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(customer.id) as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
51 | + tenant_id, customer_id, ttl) into deleted; | |
52 | +END; | |
53 | +$$ LANGUAGE plpgsql; | |
54 | + | |
55 | +CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid varchar(31), | |
56 | + IN system_ttl bigint, INOUT deleted bigint) | |
57 | + LANGUAGE plpgsql AS | |
58 | +$$ | |
59 | +DECLARE | |
60 | + tenant_cursor CURSOR FOR select tenant.id as tenant_id | |
61 | + from tenant; | |
62 | + tenant_id_record varchar; | |
63 | + customer_id_record varchar; | |
64 | + tenant_ttl bigint; | |
65 | + customer_ttl bigint; | |
66 | + deleted_for_entities bigint; | |
67 | + tenant_ttl_ts bigint; | |
68 | + customer_ttl_ts bigint; | |
69 | +BEGIN | |
70 | + OPEN tenant_cursor; | |
71 | + FETCH tenant_cursor INTO tenant_id_record; | |
72 | + WHILE FOUND | |
73 | + LOOP | |
74 | + EXECUTE format( | |
75 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
76 | + tenant_id_record, 'TTL') INTO tenant_ttl; | |
77 | + if tenant_ttl IS NULL THEN | |
78 | + tenant_ttl := system_ttl; | |
79 | + END IF; | |
80 | + IF tenant_ttl > 0 THEN | |
81 | + tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint; | |
82 | + deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
83 | + deleted := deleted + deleted_for_entities; | |
84 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record; | |
85 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
86 | + deleted := deleted + deleted_for_entities; | |
87 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record; | |
88 | + END IF; | |
89 | + FOR customer_id_record IN | |
90 | + SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record | |
91 | + LOOP | |
92 | + EXECUTE format( | |
93 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
94 | + customer_id_record, 'TTL') INTO customer_ttl; | |
95 | + IF customer_ttl IS NULL THEN | |
96 | + customer_ttl_ts := tenant_ttl_ts; | |
97 | + ELSE | |
98 | + IF customer_ttl > 0 THEN | |
99 | + customer_ttl_ts := | |
100 | + (EXTRACT(EPOCH FROM current_timestamp) * 1000 - | |
101 | + customer_ttl::bigint * 1000)::bigint; | |
102 | + END IF; | |
103 | + END IF; | |
104 | + IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN | |
105 | + deleted_for_entities := | |
106 | + delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record, | |
107 | + customer_ttl_ts); | |
108 | + deleted := deleted + deleted_for_entities; | |
109 | + RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record; | |
110 | + deleted_for_entities := | |
111 | + delete_device_records_from_ts_kv(tenant_id_record, customer_id_record, | |
112 | + customer_ttl_ts); | |
113 | + deleted := deleted + deleted_for_entities; | |
114 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
115 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, | |
116 | + customer_id_record, | |
117 | + customer_ttl_ts); | |
118 | + deleted := deleted + deleted_for_entities; | |
119 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
120 | + END IF; | |
121 | + END LOOP; | |
122 | + FETCH tenant_cursor INTO tenant_id_record; | |
123 | + END LOOP; | |
124 | +END | |
125 | +$$; | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; |
24 | 24 | import com.google.common.util.concurrent.FutureCallback; |
25 | 25 | import com.google.common.util.concurrent.Futures; |
26 | 26 | import com.google.common.util.concurrent.ListenableFuture; |
27 | +import com.google.common.util.concurrent.MoreExecutors; | |
27 | 28 | import com.typesafe.config.Config; |
28 | 29 | import com.typesafe.config.ConfigFactory; |
29 | 30 | import lombok.Getter; |
... | ... | @@ -474,7 +475,7 @@ public class ActorSystemContext { |
474 | 475 | public void onFailure(Throwable th) { |
475 | 476 | log.error("Could not save debug Event for Node", th); |
476 | 477 | } |
477 | - }); | |
478 | + }, MoreExecutors.directExecutor()); | |
478 | 479 | } catch (IOException ex) { |
479 | 480 | log.warn("Failed to persist rule node debug message", ex); |
480 | 481 | } |
... | ... | @@ -527,7 +528,7 @@ public class ActorSystemContext { |
527 | 528 | public void onFailure(Throwable th) { |
528 | 529 | log.error("Could not save debug Event for Rule Chain", th); |
529 | 530 | } |
530 | - }); | |
531 | + }, MoreExecutors.directExecutor()); | |
531 | 532 | } |
532 | 533 | |
533 | 534 | public static Exception toException(Throwable error) { | ... | ... |
... | ... | @@ -107,7 +107,6 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
107 | 107 | return filter; |
108 | 108 | } |
109 | 109 | |
110 | - @Bean | |
111 | 110 | protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { |
112 | 111 | List<String> pathsToSkip = new ArrayList(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); |
113 | 112 | pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, | ... | ... |
... | ... | @@ -120,7 +120,9 @@ public class AlarmController extends BaseController { |
120 | 120 | try { |
121 | 121 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
122 | 122 | Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); |
123 | - alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, System.currentTimeMillis()).get(); | |
123 | + long ackTs = System.currentTimeMillis(); | |
124 | + alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, ackTs).get(); | |
125 | + alarm.setAckTs(ackTs); | |
124 | 126 | logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null); |
125 | 127 | } catch (Exception e) { |
126 | 128 | throw handleException(e); |
... | ... | @@ -135,7 +137,9 @@ public class AlarmController extends BaseController { |
135 | 137 | try { |
136 | 138 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
137 | 139 | Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); |
138 | - alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, System.currentTimeMillis()).get(); | |
140 | + long clearTs = System.currentTimeMillis(); | |
141 | + alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, clearTs).get(); | |
142 | + alarm.setClearTs(clearTs); | |
139 | 143 | logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null); |
140 | 144 | } catch (Exception e) { |
141 | 145 | throw handleException(e); | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import org.springframework.http.HttpStatus; |
22 | 23 | import org.springframework.http.ResponseEntity; |
23 | 24 | import org.springframework.security.access.prepost.PreAuthorize; |
... | ... | @@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController; |
32 | 33 | import org.springframework.web.context.request.async.DeferredResult; |
33 | 34 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; |
34 | 35 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
36 | +import org.thingsboard.server.common.data.ClaimRequest; | |
35 | 37 | import org.thingsboard.server.common.data.Customer; |
36 | 38 | import org.thingsboard.server.common.data.DataConstants; |
37 | 39 | import org.thingsboard.server.common.data.Device; |
... | ... | @@ -46,7 +48,6 @@ import org.thingsboard.server.common.data.id.TenantId; |
46 | 48 | import org.thingsboard.server.common.data.page.TextPageData; |
47 | 49 | import org.thingsboard.server.common.data.page.TextPageLink; |
48 | 50 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
49 | -import org.thingsboard.server.common.data.ClaimRequest; | |
50 | 51 | import org.thingsboard.server.dao.device.claim.ClaimResponse; |
51 | 52 | import org.thingsboard.server.dao.device.claim.ClaimResult; |
52 | 53 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
... | ... | @@ -432,7 +433,7 @@ public class DeviceController extends BaseController { |
432 | 433 | public void onFailure(Throwable t) { |
433 | 434 | deferredResult.setErrorResult(t); |
434 | 435 | } |
435 | - }); | |
436 | + }, MoreExecutors.directExecutor()); | |
436 | 437 | return deferredResult; |
437 | 438 | } catch (Exception e) { |
438 | 439 | throw handleException(e); |
... | ... | @@ -469,7 +470,7 @@ public class DeviceController extends BaseController { |
469 | 470 | public void onFailure(Throwable t) { |
470 | 471 | deferredResult.setErrorResult(t); |
471 | 472 | } |
472 | - }); | |
473 | + }, MoreExecutors.directExecutor()); | |
473 | 474 | return deferredResult; |
474 | 475 | } catch (Exception e) { |
475 | 476 | throw handleException(e); | ... | ... |
... | ... | @@ -37,6 +37,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; |
37 | 37 | import org.thingsboard.server.service.security.permission.Operation; |
38 | 38 | |
39 | 39 | import java.util.List; |
40 | +import java.util.stream.Collectors; | |
40 | 41 | |
41 | 42 | |
42 | 43 | @RestController |
... | ... | @@ -167,7 +168,7 @@ public class EntityRelationController extends BaseController { |
167 | 168 | checkEntityId(entityId, Operation.READ); |
168 | 169 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
169 | 170 | try { |
170 | - return checkNotNull(relationService.findByFrom(getTenantId(), entityId, typeGroup)); | |
171 | + return checkNotNull(filterRelationsByReadPermission(relationService.findByFrom(getTenantId(), entityId, typeGroup))); | |
171 | 172 | } catch (Exception e) { |
172 | 173 | throw handleException(e); |
173 | 174 | } |
... | ... | @@ -185,7 +186,7 @@ public class EntityRelationController extends BaseController { |
185 | 186 | checkEntityId(entityId, Operation.READ); |
186 | 187 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
187 | 188 | try { |
188 | - return checkNotNull(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get()); | |
189 | + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get())); | |
189 | 190 | } catch (Exception e) { |
190 | 191 | throw handleException(e); |
191 | 192 | } |
... | ... | @@ -205,7 +206,7 @@ public class EntityRelationController extends BaseController { |
205 | 206 | checkEntityId(entityId, Operation.READ); |
206 | 207 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
207 | 208 | try { |
208 | - return checkNotNull(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup)); | |
209 | + return checkNotNull(filterRelationsByReadPermission(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup))); | |
209 | 210 | } catch (Exception e) { |
210 | 211 | throw handleException(e); |
211 | 212 | } |
... | ... | @@ -223,7 +224,7 @@ public class EntityRelationController extends BaseController { |
223 | 224 | checkEntityId(entityId, Operation.READ); |
224 | 225 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
225 | 226 | try { |
226 | - return checkNotNull(relationService.findByTo(getTenantId(), entityId, typeGroup)); | |
227 | + return checkNotNull(filterRelationsByReadPermission(relationService.findByTo(getTenantId(), entityId, typeGroup))); | |
227 | 228 | } catch (Exception e) { |
228 | 229 | throw handleException(e); |
229 | 230 | } |
... | ... | @@ -241,7 +242,7 @@ public class EntityRelationController extends BaseController { |
241 | 242 | checkEntityId(entityId, Operation.READ); |
242 | 243 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
243 | 244 | try { |
244 | - return checkNotNull(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get()); | |
245 | + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get())); | |
245 | 246 | } catch (Exception e) { |
246 | 247 | throw handleException(e); |
247 | 248 | } |
... | ... | @@ -261,7 +262,7 @@ public class EntityRelationController extends BaseController { |
261 | 262 | checkEntityId(entityId, Operation.READ); |
262 | 263 | RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); |
263 | 264 | try { |
264 | - return checkNotNull(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup)); | |
265 | + return checkNotNull(filterRelationsByReadPermission(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup))); | |
265 | 266 | } catch (Exception e) { |
266 | 267 | throw handleException(e); |
267 | 268 | } |
... | ... | @@ -276,7 +277,7 @@ public class EntityRelationController extends BaseController { |
276 | 277 | checkNotNull(query.getFilters()); |
277 | 278 | checkEntityId(query.getParameters().getEntityId(), Operation.READ); |
278 | 279 | try { |
279 | - return checkNotNull(relationService.findByQuery(getTenantId(), query).get()); | |
280 | + return checkNotNull(filterRelationsByReadPermission(relationService.findByQuery(getTenantId(), query).get())); | |
280 | 281 | } catch (Exception e) { |
281 | 282 | throw handleException(e); |
282 | 283 | } |
... | ... | @@ -291,12 +292,28 @@ public class EntityRelationController extends BaseController { |
291 | 292 | checkNotNull(query.getFilters()); |
292 | 293 | checkEntityId(query.getParameters().getEntityId(), Operation.READ); |
293 | 294 | try { |
294 | - return checkNotNull(relationService.findInfoByQuery(getTenantId(), query).get()); | |
295 | + return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByQuery(getTenantId(), query).get())); | |
295 | 296 | } catch (Exception e) { |
296 | 297 | throw handleException(e); |
297 | 298 | } |
298 | 299 | } |
299 | 300 | |
301 | + private <T extends EntityRelation> List<T> filterRelationsByReadPermission(List<T> relationsByQuery) { | |
302 | + return relationsByQuery.stream().filter(relationByQuery -> { | |
303 | + try { | |
304 | + checkEntityId(relationByQuery.getTo(), Operation.READ); | |
305 | + } catch (ThingsboardException e) { | |
306 | + return false; | |
307 | + } | |
308 | + try { | |
309 | + checkEntityId(relationByQuery.getFrom(), Operation.READ); | |
310 | + } catch (ThingsboardException e) { | |
311 | + return false; | |
312 | + } | |
313 | + return true; | |
314 | + }).collect(Collectors.toList()); | |
315 | + } | |
316 | + | |
300 | 317 | private RelationTypeGroup parseRelationTypeGroup(String strRelationTypeGroup, RelationTypeGroup defaultValue) { |
301 | 318 | RelationTypeGroup result = defaultValue; |
302 | 319 | if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length() > 0) { | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | 23 | import org.springframework.http.HttpStatus; |
23 | 24 | import org.springframework.security.access.prepost.PreAuthorize; |
... | ... | @@ -160,7 +161,7 @@ public class EntityViewController extends BaseController { |
160 | 161 | }); |
161 | 162 | } |
162 | 163 | return null; |
163 | - }); | |
164 | + }, MoreExecutors.directExecutor()); | |
164 | 165 | } else { |
165 | 166 | return Futures.immediateFuture(null); |
166 | 167 | } | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import com.google.common.base.Function; |
22 | 22 | import com.google.common.util.concurrent.FutureCallback; |
23 | 23 | import com.google.common.util.concurrent.Futures; |
24 | 24 | import com.google.common.util.concurrent.ListenableFuture; |
25 | +import com.google.common.util.concurrent.MoreExecutors; | |
25 | 26 | import com.google.gson.JsonElement; |
26 | 27 | import com.google.gson.JsonParseException; |
27 | 28 | import com.google.gson.JsonParser; |
... | ... | @@ -175,7 +176,7 @@ public class TelemetryController extends BaseController { |
175 | 176 | public DeferredResult<ResponseEntity> getTimeseriesKeys( |
176 | 177 | @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException { |
177 | 178 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, |
178 | - (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result))); | |
179 | + (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor())); | |
179 | 180 | } |
180 | 181 | |
181 | 182 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
... | ... | @@ -211,7 +212,7 @@ public class TelemetryController extends BaseController { |
211 | 212 | List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg)) |
212 | 213 | .collect(Collectors.toList()); |
213 | 214 | |
214 | - Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes)); | |
215 | + Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); | |
215 | 216 | }); |
216 | 217 | } |
217 | 218 | |
... | ... | @@ -461,7 +462,7 @@ public class TelemetryController extends BaseController { |
461 | 462 | } else { |
462 | 463 | future = tsService.findLatest(user.getTenantId(), entityId, toKeysList(keys)); |
463 | 464 | } |
464 | - Futures.addCallback(future, getTsKvListCallback(result, useStrictDataTypes)); | |
465 | + Futures.addCallback(future, getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); | |
465 | 466 | } |
466 | 467 | |
467 | 468 | private void getAttributeValuesCallback(@Nullable DeferredResult<ResponseEntity> result, SecurityUser user, EntityId entityId, String scope, String keys) { |
... | ... | @@ -469,9 +470,9 @@ public class TelemetryController extends BaseController { |
469 | 470 | FutureCallback<List<AttributeKvEntry>> callback = getAttributeValuesToResponseCallback(result, user, scope, entityId, keyList); |
470 | 471 | if (!StringUtils.isEmpty(scope)) { |
471 | 472 | if (keyList != null && !keyList.isEmpty()) { |
472 | - Futures.addCallback(attributesService.find(user.getTenantId(), entityId, scope, keyList), callback); | |
473 | + Futures.addCallback(attributesService.find(user.getTenantId(), entityId, scope, keyList), callback, MoreExecutors.directExecutor()); | |
473 | 474 | } else { |
474 | - Futures.addCallback(attributesService.findAll(user.getTenantId(), entityId, scope), callback); | |
475 | + Futures.addCallback(attributesService.findAll(user.getTenantId(), entityId, scope), callback, MoreExecutors.directExecutor()); | |
475 | 476 | } |
476 | 477 | } else { |
477 | 478 | List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>(); |
... | ... | @@ -485,12 +486,12 @@ public class TelemetryController extends BaseController { |
485 | 486 | |
486 | 487 | ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures); |
487 | 488 | |
488 | - Futures.addCallback(future, callback); | |
489 | + Futures.addCallback(future, callback, MoreExecutors.directExecutor()); | |
489 | 490 | } |
490 | 491 | } |
491 | 492 | |
492 | 493 | private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, TenantId tenantId, EntityId entityId, String scope) { |
493 | - Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), getAttributeKeysToResponseCallback(result)); | |
494 | + Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), getAttributeKeysToResponseCallback(result), MoreExecutors.directExecutor()); | |
494 | 495 | } |
495 | 496 | |
496 | 497 | private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, TenantId tenantId, EntityId entityId) { |
... | ... | @@ -501,7 +502,7 @@ public class TelemetryController extends BaseController { |
501 | 502 | |
502 | 503 | ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures); |
503 | 504 | |
504 | - Futures.addCallback(future, getAttributeKeysToResponseCallback(result)); | |
505 | + Futures.addCallback(future, getAttributeKeysToResponseCallback(result), MoreExecutors.directExecutor()); | |
505 | 506 | } |
506 | 507 | |
507 | 508 | private FutureCallback<List<TsKvEntry>> getTsKeysToResponseCallback(final DeferredResult<ResponseEntity> response) { | ... | ... |
... | ... | @@ -22,38 +22,18 @@ import org.springframework.beans.factory.annotation.Value; |
22 | 22 | import java.nio.charset.StandardCharsets; |
23 | 23 | import java.nio.file.Files; |
24 | 24 | import java.nio.file.Path; |
25 | -import java.sql.CallableStatement; | |
26 | 25 | import java.sql.Connection; |
26 | +import java.sql.ResultSet; | |
27 | 27 | import java.sql.SQLException; |
28 | 28 | import java.sql.SQLWarning; |
29 | -import java.sql.Types; | |
29 | +import java.sql.Statement; | |
30 | 30 | |
31 | 31 | @Slf4j |
32 | 32 | public abstract class AbstractSqlTsDatabaseUpgradeService { |
33 | 33 | |
34 | 34 | protected static final String CALL_REGEX = "call "; |
35 | - protected static final String CHECK_VERSION = "check_version()"; | |
36 | 35 | protected static final String DROP_TABLE = "DROP TABLE "; |
37 | - protected static final String DROP_FUNCTION_IF_EXISTS = "DROP FUNCTION IF EXISTS "; | |
38 | - | |
39 | - private static final String CALL_CHECK_VERSION = CALL_REGEX + CHECK_VERSION; | |
40 | - | |
41 | - | |
42 | - private static final String FUNCTION = "function: {}"; | |
43 | - private static final String DROP_STATEMENT = "drop statement: {}"; | |
44 | - private static final String QUERY = "query: {}"; | |
45 | - private static final String SUCCESSFULLY_EXECUTED = "Successfully executed "; | |
46 | - private static final String FAILED_TO_EXECUTE = "Failed to execute "; | |
47 | - private static final String FAILED_DUE_TO = " due to: {}"; | |
48 | - | |
49 | - protected static final String SUCCESSFULLY_EXECUTED_FUNCTION = SUCCESSFULLY_EXECUTED + FUNCTION; | |
50 | - protected static final String FAILED_TO_EXECUTE_FUNCTION_DUE_TO = FAILED_TO_EXECUTE + FUNCTION + FAILED_DUE_TO; | |
51 | - | |
52 | - protected static final String SUCCESSFULLY_EXECUTED_DROP_STATEMENT = SUCCESSFULLY_EXECUTED + DROP_STATEMENT; | |
53 | - protected static final String FAILED_TO_EXECUTE_DROP_STATEMENT = FAILED_TO_EXECUTE + DROP_STATEMENT + FAILED_DUE_TO; | |
54 | - | |
55 | - protected static final String SUCCESSFULLY_EXECUTED_QUERY = SUCCESSFULLY_EXECUTED + QUERY; | |
56 | - protected static final String FAILED_TO_EXECUTE_QUERY = FAILED_TO_EXECUTE + QUERY + FAILED_DUE_TO; | |
36 | + protected static final String DROP_PROCEDURE_IF_EXISTS = "DROP PROCEDURE IF EXISTS "; | |
57 | 37 | |
58 | 38 | @Value("${spring.datasource.url}") |
59 | 39 | protected String dbUrl; |
... | ... | @@ -67,7 +47,7 @@ public abstract class AbstractSqlTsDatabaseUpgradeService { |
67 | 47 | @Autowired |
68 | 48 | protected InstallScripts installScripts; |
69 | 49 | |
70 | - protected abstract void loadSql(Connection conn); | |
50 | + protected abstract void loadSql(Connection conn, String fileName); | |
71 | 51 | |
72 | 52 | protected void loadFunctions(Path sqlFile, Connection conn) throws Exception { |
73 | 53 | String sql = new String(Files.readAllBytes(sqlFile), StandardCharsets.UTF_8); |
... | ... | @@ -75,26 +55,46 @@ public abstract class AbstractSqlTsDatabaseUpgradeService { |
75 | 55 | } |
76 | 56 | |
77 | 57 | protected boolean checkVersion(Connection conn) { |
78 | - log.info("Check the current PostgreSQL version..."); | |
79 | 58 | boolean versionValid = false; |
80 | 59 | try { |
81 | - CallableStatement callableStatement = conn.prepareCall("{? = " + CALL_CHECK_VERSION + " }"); | |
82 | - callableStatement.registerOutParameter(1, Types.BOOLEAN); | |
83 | - callableStatement.execute(); | |
84 | - versionValid = callableStatement.getBoolean(1); | |
85 | - callableStatement.close(); | |
60 | + Statement statement = conn.createStatement(); | |
61 | + ResultSet resultSet = statement.executeQuery("SELECT current_setting('server_version_num')"); | |
62 | + resultSet.next(); | |
63 | + if(resultSet.getLong(1) > 110000) { | |
64 | + versionValid = true; | |
65 | + } | |
66 | + statement.close(); | |
86 | 67 | } catch (Exception e) { |
87 | 68 | log.info("Failed to check current PostgreSQL version due to: {}", e.getMessage()); |
88 | 69 | } |
89 | 70 | return versionValid; |
90 | 71 | } |
91 | 72 | |
92 | - protected void executeFunction(Connection conn, String query) { | |
93 | - log.info("{} ... ", query); | |
73 | + protected boolean isOldSchema(Connection conn, long fromVersion) { | |
74 | + boolean isOldSchema = true; | |
94 | 75 | try { |
95 | - CallableStatement callableStatement = conn.prepareCall("{" + query + "}"); | |
96 | - callableStatement.execute(); | |
97 | - SQLWarning warnings = callableStatement.getWarnings(); | |
76 | + Statement statement = conn.createStatement(); | |
77 | + statement.execute("CREATE TABLE IF NOT EXISTS tb_schema_settings ( schema_version bigint NOT NULL, CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version));"); | |
78 | + Thread.sleep(1000); | |
79 | + ResultSet resultSet = statement.executeQuery("SELECT schema_version FROM tb_schema_settings;"); | |
80 | + if (resultSet.next()) { | |
81 | + isOldSchema = resultSet.getLong(1) <= fromVersion; | |
82 | + } else { | |
83 | + resultSet.close(); | |
84 | + statement.execute("INSERT INTO tb_schema_settings (schema_version) VALUES (" + fromVersion + ")"); | |
85 | + } | |
86 | + statement.close(); | |
87 | + } catch (InterruptedException | SQLException e) { | |
88 | + log.info("Failed to check current PostgreSQL schema due to: {}", e.getMessage()); | |
89 | + } | |
90 | + return isOldSchema; | |
91 | + } | |
92 | + | |
93 | + protected void executeQuery(Connection conn, String query) { | |
94 | + try { | |
95 | + Statement statement = conn.createStatement(); | |
96 | + statement.execute(query); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
97 | + SQLWarning warnings = statement.getWarnings(); | |
98 | 98 | if (warnings != null) { |
99 | 99 | log.info("{}", warnings.getMessage()); |
100 | 100 | SQLWarning nextWarning = warnings.getNextWarning(); |
... | ... | @@ -103,31 +103,10 @@ public abstract class AbstractSqlTsDatabaseUpgradeService { |
103 | 103 | nextWarning = nextWarning.getNextWarning(); |
104 | 104 | } |
105 | 105 | } |
106 | - callableStatement.close(); | |
107 | - log.info(SUCCESSFULLY_EXECUTED_FUNCTION, query.replace(CALL_REGEX, "")); | |
108 | 106 | Thread.sleep(2000); |
109 | - } catch (Exception e) { | |
110 | - log.info(FAILED_TO_EXECUTE_FUNCTION_DUE_TO, query, e.getMessage()); | |
111 | - } | |
112 | - } | |
113 | - | |
114 | - protected void executeDropStatement(Connection conn, String query) { | |
115 | - try { | |
116 | - conn.createStatement().execute(query); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
117 | - log.info(SUCCESSFULLY_EXECUTED_DROP_STATEMENT, query); | |
118 | - Thread.sleep(5000); | |
119 | - } catch (InterruptedException | SQLException e) { | |
120 | - log.info(FAILED_TO_EXECUTE_DROP_STATEMENT, query, e.getMessage()); | |
121 | - } | |
122 | - } | |
123 | - | |
124 | - protected void executeQuery(Connection conn, String query) { | |
125 | - try { | |
126 | - conn.createStatement().execute(query); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
127 | - log.info(SUCCESSFULLY_EXECUTED_QUERY, query); | |
128 | - Thread.sleep(5000); | |
107 | + log.info("Successfully executed query: {}", query); | |
129 | 108 | } catch (InterruptedException | SQLException e) { |
130 | - log.info(FAILED_TO_EXECUTE_QUERY, query, e.getMessage()); | |
109 | + log.info("Failed to execute query: {} due to: {}", query, e.getMessage()); | |
131 | 110 | } |
132 | 111 | } |
133 | 112 | ... | ... |
... | ... | @@ -34,6 +34,8 @@ import java.sql.DriverManager; |
34 | 34 | public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeService implements DatabaseTsUpgradeService { |
35 | 35 | |
36 | 36 | private static final String LOAD_FUNCTIONS_SQL = "schema_update_psql_ts.sql"; |
37 | + private static final String LOAD_TTL_FUNCTIONS_SQL = "schema_update_ttl.sql"; | |
38 | + private static final String LOAD_DROP_PARTITIONS_FUNCTIONS_SQL = "schema_update_psql_drop_partitions.sql"; | |
37 | 39 | |
38 | 40 | private static final String TS_KV_OLD = "ts_kv_old;"; |
39 | 41 | private static final String TS_KV_LATEST_OLD = "ts_kv_latest_old;"; |
... | ... | @@ -57,52 +59,58 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
57 | 59 | private static final String DROP_TABLE_TS_KV_OLD = DROP_TABLE + TS_KV_OLD; |
58 | 60 | private static final String DROP_TABLE_TS_KV_LATEST_OLD = DROP_TABLE + TS_KV_LATEST_OLD; |
59 | 61 | |
60 | - private static final String DROP_FUNCTION_CHECK_VERSION = DROP_FUNCTION_IF_EXISTS + CHECK_VERSION; | |
61 | - private static final String DROP_FUNCTION_CREATE_PARTITION_TS_KV_TABLE = DROP_FUNCTION_IF_EXISTS + CREATE_PARTITION_TS_KV_TABLE; | |
62 | - private static final String DROP_FUNCTION_CREATE_NEW_TS_KV_LATEST_TABLE = DROP_FUNCTION_IF_EXISTS + CREATE_NEW_TS_KV_LATEST_TABLE; | |
63 | - private static final String DROP_FUNCTION_CREATE_PARTITIONS = DROP_FUNCTION_IF_EXISTS + CREATE_PARTITIONS; | |
64 | - private static final String DROP_FUNCTION_CREATE_TS_KV_DICTIONARY_TABLE = DROP_FUNCTION_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; | |
65 | - private static final String DROP_FUNCTION_INSERT_INTO_DICTIONARY = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_DICTIONARY; | |
66 | - private static final String DROP_FUNCTION_INSERT_INTO_TS_KV = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_TS_KV; | |
67 | - private static final String DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; | |
62 | + private static final String DROP_PROCEDURE_CREATE_PARTITION_TS_KV_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_PARTITION_TS_KV_TABLE; | |
63 | + private static final String DROP_PROCEDURE_CREATE_NEW_TS_KV_LATEST_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_NEW_TS_KV_LATEST_TABLE; | |
64 | + private static final String DROP_PROCEDURE_CREATE_PARTITIONS = DROP_PROCEDURE_IF_EXISTS + CREATE_PARTITIONS; | |
65 | + private static final String DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; | |
66 | + private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; | |
67 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; | |
68 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; | |
68 | 69 | |
69 | 70 | @Override |
70 | 71 | public void upgradeDatabase(String fromVersion) throws Exception { |
71 | 72 | switch (fromVersion) { |
72 | 73 | case "2.4.3": |
73 | 74 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
74 | - log.info("Updating timeseries schema ..."); | |
75 | - log.info("Load upgrade functions ..."); | |
76 | - loadSql(conn); | |
75 | + log.info("Check the current PostgreSQL version..."); | |
77 | 76 | boolean versionValid = checkVersion(conn); |
78 | 77 | if (!versionValid) { |
79 | - log.info("PostgreSQL version should be at least more than 10!"); | |
80 | - log.info("Please upgrade your PostgreSQL and restart the script!"); | |
78 | + throw new RuntimeException("PostgreSQL version should be at least more than 11, please upgrade your PostgreSQL and restart the script!"); | |
81 | 79 | } else { |
82 | 80 | log.info("PostgreSQL version is valid!"); |
83 | - log.info("Updating schema ..."); | |
84 | - executeFunction(conn, CALL_CREATE_PARTITION_TS_KV_TABLE); | |
85 | - executeFunction(conn, CALL_CREATE_PARTITIONS); | |
86 | - executeFunction(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); | |
87 | - executeFunction(conn, CALL_INSERT_INTO_DICTIONARY); | |
88 | - executeFunction(conn, CALL_INSERT_INTO_TS_KV); | |
89 | - executeFunction(conn, CALL_CREATE_NEW_TS_KV_LATEST_TABLE); | |
90 | - executeFunction(conn, CALL_INSERT_INTO_TS_KV_LATEST); | |
91 | - | |
92 | - executeDropStatement(conn, DROP_TABLE_TS_KV_OLD); | |
93 | - executeDropStatement(conn, DROP_TABLE_TS_KV_LATEST_OLD); | |
94 | - | |
95 | - executeDropStatement(conn, DROP_FUNCTION_CHECK_VERSION); | |
96 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_PARTITION_TS_KV_TABLE); | |
97 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_PARTITIONS); | |
98 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_TS_KV_DICTIONARY_TABLE); | |
99 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_DICTIONARY); | |
100 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TS_KV); | |
101 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_NEW_TS_KV_LATEST_TABLE); | |
102 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST); | |
103 | - | |
104 | - executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN json_v json;"); | |
105 | - executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN json_v json;"); | |
81 | + if (isOldSchema(conn, 2004003)) { | |
82 | + log.info("Load upgrade functions ..."); | |
83 | + loadSql(conn, LOAD_FUNCTIONS_SQL); | |
84 | + log.info("Updating timeseries schema ..."); | |
85 | + executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE); | |
86 | + executeQuery(conn, CALL_CREATE_PARTITIONS); | |
87 | + executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); | |
88 | + executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); | |
89 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV); | |
90 | + executeQuery(conn, CALL_CREATE_NEW_TS_KV_LATEST_TABLE); | |
91 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST); | |
92 | + | |
93 | + executeQuery(conn, DROP_TABLE_TS_KV_OLD); | |
94 | + executeQuery(conn, DROP_TABLE_TS_KV_LATEST_OLD); | |
95 | + | |
96 | + executeQuery(conn, DROP_PROCEDURE_CREATE_PARTITION_TS_KV_TABLE); | |
97 | + executeQuery(conn, DROP_PROCEDURE_CREATE_PARTITIONS); | |
98 | + executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE); | |
99 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_DICTIONARY); | |
100 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV); | |
101 | + executeQuery(conn, DROP_PROCEDURE_CREATE_NEW_TS_KV_LATEST_TABLE); | |
102 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); | |
103 | + | |
104 | + executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); | |
105 | + executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN IF NOT EXISTS json_v json;"); | |
106 | + } | |
107 | + | |
108 | + log.info("Load TTL functions ..."); | |
109 | + loadSql(conn, LOAD_TTL_FUNCTIONS_SQL); | |
110 | + log.info("Load Drop Partitions functions ..."); | |
111 | + loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL); | |
112 | + | |
113 | + executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000"); | |
106 | 114 | |
107 | 115 | log.info("schema timeseries updated!"); |
108 | 116 | } |
... | ... | @@ -113,11 +121,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
113 | 121 | } |
114 | 122 | } |
115 | 123 | |
116 | - protected void loadSql(Connection conn) { | |
117 | - Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", LOAD_FUNCTIONS_SQL); | |
124 | + @Override | |
125 | + protected void loadSql(Connection conn, String fileName) { | |
126 | + Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); | |
118 | 127 | try { |
119 | 128 | loadFunctions(schemaUpdateFile, conn); |
120 | - log.info("Upgrade functions successfully loaded!"); | |
129 | + log.info("Functions successfully loaded!"); | |
121 | 130 | } catch (Exception e) { |
122 | 131 | log.info("Failed to load PostgreSQL upgrade functions due to: {}", e.getMessage()); |
123 | 132 | } | ... | ... |
... | ... | @@ -45,13 +45,13 @@ public class TimescaleTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaS |
45 | 45 | private long chunkTimeInterval; |
46 | 46 | |
47 | 47 | public TimescaleTsDatabaseSchemaService() { |
48 | - super("schema-timescale.sql", "schema-timescale-idx.sql"); | |
48 | + super("schema-timescale.sql", null); | |
49 | 49 | } |
50 | 50 | |
51 | 51 | @Override |
52 | 52 | public void createDatabaseSchema() throws Exception { |
53 | 53 | super.createDatabaseSchema(); |
54 | - executeQuery("SELECT create_hypertable('tenant_ts_kv', 'ts', chunk_time_interval => " + chunkTimeInterval + ", if_not_exists => true);"); | |
54 | + executeQuery("SELECT create_hypertable('ts_kv', 'ts', chunk_time_interval => " + chunkTimeInterval + ", if_not_exists => true);"); | |
55 | 55 | } |
56 | 56 | |
57 | 57 | private void executeQuery(String query) { | ... | ... |
... | ... | @@ -39,31 +39,32 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
39 | 39 | private long chunkTimeInterval; |
40 | 40 | |
41 | 41 | private static final String LOAD_FUNCTIONS_SQL = "schema_update_timescale_ts.sql"; |
42 | + private static final String LOAD_TTL_FUNCTIONS_SQL = "schema_update_ttl.sql"; | |
42 | 43 | |
43 | 44 | private static final String TENANT_TS_KV_OLD_TABLE = "tenant_ts_kv_old;"; |
44 | 45 | |
45 | 46 | private static final String CREATE_TS_KV_LATEST_TABLE = "create_ts_kv_latest_table()"; |
46 | - private static final String CREATE_NEW_TENANT_TS_KV_TABLE = "create_new_tenant_ts_kv_table()"; | |
47 | + private static final String CREATE_NEW_TS_KV_TABLE = "create_new_ts_kv_table()"; | |
47 | 48 | private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()"; |
48 | 49 | private static final String INSERT_INTO_DICTIONARY = "insert_into_dictionary()"; |
49 | - private static final String INSERT_INTO_TENANT_TS_KV = "insert_into_tenant_ts_kv()"; | |
50 | + private static final String INSERT_INTO_TS_KV = "insert_into_ts_kv()"; | |
50 | 51 | private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest()"; |
51 | 52 | |
52 | 53 | private static final String CALL_CREATE_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_TS_KV_LATEST_TABLE; |
53 | - private static final String CALL_CREATE_NEW_TENANT_TS_KV_TABLE = CALL_REGEX + CREATE_NEW_TENANT_TS_KV_TABLE; | |
54 | + private static final String CALL_CREATE_NEW_TENANT_TS_KV_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_TABLE; | |
54 | 55 | private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE; |
55 | 56 | private static final String CALL_INSERT_INTO_DICTIONARY = CALL_REGEX + INSERT_INTO_DICTIONARY; |
56 | - private static final String CALL_INSERT_INTO_TS_KV = CALL_REGEX + INSERT_INTO_TENANT_TS_KV; | |
57 | + private static final String CALL_INSERT_INTO_TS_KV = CALL_REGEX + INSERT_INTO_TS_KV; | |
57 | 58 | private static final String CALL_INSERT_INTO_TS_KV_LATEST = CALL_REGEX + INSERT_INTO_TS_KV_LATEST; |
58 | 59 | |
59 | 60 | private static final String DROP_OLD_TENANT_TS_KV_TABLE = DROP_TABLE + TENANT_TS_KV_OLD_TABLE; |
60 | 61 | |
61 | - private static final String DROP_FUNCTION_CREATE_TS_KV_LATEST_TABLE = DROP_FUNCTION_IF_EXISTS + CREATE_TS_KV_LATEST_TABLE; | |
62 | - private static final String DROP_FUNCTION_CREATE_TENANT_TS_KV_TABLE_COPY = DROP_FUNCTION_IF_EXISTS + CREATE_NEW_TENANT_TS_KV_TABLE; | |
63 | - private static final String DROP_FUNCTION_CREATE_TS_KV_DICTIONARY_TABLE = DROP_FUNCTION_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; | |
64 | - private static final String DROP_FUNCTION_INSERT_INTO_DICTIONARY = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_DICTIONARY; | |
65 | - private static final String DROP_FUNCTION_INSERT_INTO_TENANT_TS_KV = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_TENANT_TS_KV; | |
66 | - private static final String DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST = DROP_FUNCTION_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; | |
62 | + private static final String DROP_PROCEDURE_CREATE_TS_KV_LATEST_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_LATEST_TABLE; | |
63 | + private static final String DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY = DROP_PROCEDURE_IF_EXISTS + CREATE_NEW_TS_KV_TABLE; | |
64 | + private static final String DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; | |
65 | + private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; | |
66 | + private static final String DROP_PROCEDURE_INSERT_INTO_TENANT_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; | |
67 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; | |
67 | 68 | |
68 | 69 | @Autowired |
69 | 70 | private InstallScripts installScripts; |
... | ... | @@ -73,41 +74,44 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
73 | 74 | switch (fromVersion) { |
74 | 75 | case "2.4.3": |
75 | 76 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
76 | - log.info("Updating timescale schema ..."); | |
77 | - log.info("Load upgrade functions ..."); | |
78 | - loadSql(conn); | |
77 | + log.info("Check the current PostgreSQL version..."); | |
79 | 78 | boolean versionValid = checkVersion(conn); |
80 | 79 | if (!versionValid) { |
81 | - log.info("PostgreSQL version should be at least more than 9.6!"); | |
82 | - log.info("Please upgrade your PostgreSQL and restart the script!"); | |
80 | + throw new RuntimeException("PostgreSQL version should be at least more than 11, please upgrade your PostgreSQL and restart the script!"); | |
83 | 81 | } else { |
84 | 82 | log.info("PostgreSQL version is valid!"); |
85 | - log.info("Updating schema ..."); | |
86 | - executeFunction(conn, CALL_CREATE_TS_KV_LATEST_TABLE); | |
87 | - executeFunction(conn, CALL_CREATE_NEW_TENANT_TS_KV_TABLE); | |
88 | - | |
89 | - executeQuery(conn, "SELECT create_hypertable('tenant_ts_kv', 'ts', chunk_time_interval => " + chunkTimeInterval + ", if_not_exists => true);"); | |
90 | - | |
91 | - executeFunction(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); | |
92 | - executeFunction(conn, CALL_INSERT_INTO_DICTIONARY); | |
93 | - executeFunction(conn, CALL_INSERT_INTO_TS_KV); | |
94 | - executeFunction(conn, CALL_INSERT_INTO_TS_KV_LATEST); | |
95 | - | |
96 | - //executeQuery(conn, "SELECT set_chunk_time_interval('tenant_ts_kv', " + chunkTimeInterval +");"); | |
97 | - | |
98 | - executeDropStatement(conn, DROP_OLD_TENANT_TS_KV_TABLE); | |
99 | - | |
100 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_TS_KV_LATEST_TABLE); | |
101 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_TENANT_TS_KV_TABLE_COPY); | |
102 | - executeDropStatement(conn, DROP_FUNCTION_CREATE_TS_KV_DICTIONARY_TABLE); | |
103 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_DICTIONARY); | |
104 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TENANT_TS_KV); | |
105 | - executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST); | |
106 | - | |
107 | - executeQuery(conn, "ALTER TABLE tenant_ts_kv ADD COLUMN json_v json;"); | |
108 | - executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN json_v json;"); | |
109 | - | |
110 | - log.info("schema timeseries updated!"); | |
83 | + if (isOldSchema(conn, 2004003)) { | |
84 | + log.info("Load upgrade functions ..."); | |
85 | + loadSql(conn, LOAD_FUNCTIONS_SQL); | |
86 | + log.info("Updating timescale schema ..."); | |
87 | + executeQuery(conn, CALL_CREATE_TS_KV_LATEST_TABLE); | |
88 | + executeQuery(conn, CALL_CREATE_NEW_TENANT_TS_KV_TABLE); | |
89 | + | |
90 | + executeQuery(conn, "SELECT create_hypertable('ts_kv', 'ts', chunk_time_interval => " + chunkTimeInterval + ", if_not_exists => true);"); | |
91 | + | |
92 | + executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); | |
93 | + executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); | |
94 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV); | |
95 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST); | |
96 | + | |
97 | + executeQuery(conn, DROP_OLD_TENANT_TS_KV_TABLE); | |
98 | + | |
99 | + executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_LATEST_TABLE); | |
100 | + executeQuery(conn, DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY); | |
101 | + executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE); | |
102 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_DICTIONARY); | |
103 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TENANT_TS_KV); | |
104 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); | |
105 | + | |
106 | + executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); | |
107 | + executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN IF NOT EXISTS json_v json;"); | |
108 | + } | |
109 | + | |
110 | + log.info("Load TTL functions ..."); | |
111 | + loadSql(conn, LOAD_TTL_FUNCTIONS_SQL); | |
112 | + | |
113 | + executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000"); | |
114 | + log.info("schema timescale updated!"); | |
111 | 115 | } |
112 | 116 | } |
113 | 117 | break; |
... | ... | @@ -116,13 +120,14 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
116 | 120 | } |
117 | 121 | } |
118 | 122 | |
119 | - protected void loadSql(Connection conn) { | |
120 | - Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", LOAD_FUNCTIONS_SQL); | |
123 | + @Override | |
124 | + protected void loadSql(Connection conn, String fileName) { | |
125 | + Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); | |
121 | 126 | try { |
122 | 127 | loadFunctions(schemaUpdateFile, conn); |
123 | - log.info("Upgrade functions successfully loaded!"); | |
128 | + log.info("Functions successfully loaded!"); | |
124 | 129 | } catch (Exception e) { |
125 | - log.info("Failed to load Timescale upgrade functions due to: {}", e.getMessage()); | |
130 | + log.info("Failed to load PostgreSQL upgrade functions due to: {}", e.getMessage()); | |
126 | 131 | } |
127 | 132 | } |
128 | 133 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.service.script; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import delight.nashornsandbox.NashornSandbox; |
22 | 23 | import delight.nashornsandbox.NashornSandboxes; |
23 | 24 | import jdk.nashorn.api.scripting.NashornScriptEngineFactory; |
... | ... | @@ -28,20 +29,17 @@ import org.springframework.beans.factory.annotation.Value; |
28 | 29 | import org.springframework.scheduling.annotation.Scheduled; |
29 | 30 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
30 | 31 | |
31 | -import javax.annotation.Nullable; | |
32 | 32 | import javax.annotation.PostConstruct; |
33 | 33 | import javax.annotation.PreDestroy; |
34 | 34 | import javax.script.Invocable; |
35 | 35 | import javax.script.ScriptEngine; |
36 | 36 | import javax.script.ScriptException; |
37 | 37 | import java.util.UUID; |
38 | -import java.util.concurrent.Callable; | |
39 | 38 | import java.util.concurrent.ExecutionException; |
40 | 39 | import java.util.concurrent.ExecutorService; |
41 | 40 | import java.util.concurrent.Executors; |
42 | 41 | import java.util.concurrent.ScheduledExecutorService; |
43 | 42 | import java.util.concurrent.TimeUnit; |
44 | -import java.util.concurrent.TimeoutException; | |
45 | 43 | import java.util.concurrent.atomic.AtomicInteger; |
46 | 44 | |
47 | 45 | @Slf4j |
... | ... | @@ -140,7 +138,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer |
140 | 138 | if (maxRequestsTimeout > 0) { |
141 | 139 | result = Futures.withTimeout(result, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); |
142 | 140 | } |
143 | - Futures.addCallback(result, evalCallback); | |
141 | + Futures.addCallback(result, evalCallback, MoreExecutors.directExecutor()); | |
144 | 142 | return result; |
145 | 143 | } |
146 | 144 | |
... | ... | @@ -163,7 +161,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer |
163 | 161 | if (maxRequestsTimeout > 0) { |
164 | 162 | result = Futures.withTimeout(result, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); |
165 | 163 | } |
166 | - Futures.addCallback(result, invokeCallback); | |
164 | + Futures.addCallback(result, invokeCallback, MoreExecutors.directExecutor()); | |
167 | 165 | return result; |
168 | 166 | } |
169 | 167 | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.service.script; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.Getter; |
22 | 23 | import lombok.extern.slf4j.Slf4j; |
23 | 24 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -158,7 +159,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
158 | 159 | } |
159 | 160 | kafkaFailedMsgs.incrementAndGet(); |
160 | 161 | } |
161 | - }); | |
162 | + }, MoreExecutors.directExecutor()); | |
162 | 163 | return Futures.transform(future, response -> { |
163 | 164 | JsInvokeProtos.JsCompileResponse compilationResult = response.getValue().getCompileResponse(); |
164 | 165 | UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB()); |
... | ... | @@ -170,7 +171,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
170 | 171 | log.debug("[{}] Failed to compile script due to [{}]: {}", compiledScriptId, compilationResult.getErrorCode().name(), compilationResult.getErrorDetails()); |
171 | 172 | throw new RuntimeException(compilationResult.getErrorDetails()); |
172 | 173 | } |
173 | - }); | |
174 | + }, MoreExecutors.directExecutor()); | |
174 | 175 | } |
175 | 176 | |
176 | 177 | @Override |
... | ... | @@ -209,7 +210,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
209 | 210 | } |
210 | 211 | kafkaFailedMsgs.incrementAndGet(); |
211 | 212 | } |
212 | - }); | |
213 | + }, MoreExecutors.directExecutor()); | |
213 | 214 | return Futures.transform(future, response -> { |
214 | 215 | JsInvokeProtos.JsInvokeResponse invokeResult = response.getValue().getInvokeResponse(); |
215 | 216 | if (invokeResult.getSuccess()) { |
... | ... | @@ -218,7 +219,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
218 | 219 | log.debug("[{}] Failed to compile script due to [{}]: {}", scriptId, invokeResult.getErrorCode().name(), invokeResult.getErrorDetails()); |
219 | 220 | throw new RuntimeException(invokeResult.getErrorDetails()); |
220 | 221 | } |
221 | - }); | |
222 | + }, MoreExecutors.directExecutor()); | |
222 | 223 | } |
223 | 224 | |
224 | 225 | @Override | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
21 | 21 | import com.google.common.collect.Sets; |
22 | 22 | import com.google.common.util.concurrent.Futures; |
23 | 23 | import com.google.common.util.concurrent.ListenableFuture; |
24 | +import com.google.common.util.concurrent.MoreExecutors; | |
24 | 25 | import lombok.extern.slf4j.Slf4j; |
25 | 26 | import org.apache.commons.lang3.StringUtils; |
26 | 27 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -121,7 +122,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S |
121 | 122 | } else { |
122 | 123 | return Futures.immediateFuture(unbindMsg(json, msg)); |
123 | 124 | } |
124 | - }); | |
125 | + }, MoreExecutors.directExecutor()); | |
125 | 126 | } |
126 | 127 | |
127 | 128 | @Override |
... | ... | @@ -174,7 +175,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S |
174 | 175 | } else { |
175 | 176 | return Futures.immediateFuture(json.asBoolean()); |
176 | 177 | } |
177 | - }); | |
178 | + }, MoreExecutors.directExecutor()); | |
178 | 179 | } |
179 | 180 | |
180 | 181 | @Override |
... | ... | @@ -232,7 +233,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S |
232 | 233 | return Futures.immediateFailedFuture(new ScriptException(e)); |
233 | 234 | } |
234 | 235 | } |
235 | - }); | |
236 | + }, MoreExecutors.directExecutor()); | |
236 | 237 | } |
237 | 238 | |
238 | 239 | public void destroy() { | ... | ... |
... | ... | @@ -272,7 +272,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
272 | 272 | log.warn("Failed to register device to the state service", t); |
273 | 273 | callback.onFailure(t); |
274 | 274 | } |
275 | - }); | |
275 | + }, MoreExecutors.directExecutor()); | |
276 | 276 | } else if (proto.getUpdated()) { |
277 | 277 | DeviceStateData stateData = getOrFetchDeviceStateData(device.getId()); |
278 | 278 | if (stateData != null) { |
... | ... | @@ -347,7 +347,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
347 | 347 | } |
348 | 348 | return null; |
349 | 349 | } |
350 | - }); | |
350 | + }, MoreExecutors.directExecutor()); | |
351 | 351 | fetchFutures.add(future); |
352 | 352 | } |
353 | 353 | } |
... | ... | @@ -440,10 +440,10 @@ public class DefaultDeviceStateService implements DeviceStateService { |
440 | 440 | private ListenableFuture<DeviceStateData> fetchDeviceState(Device device) { |
441 | 441 | if (persistToTelemetry) { |
442 | 442 | ListenableFuture<List<TsKvEntry>> tsData = tsService.findLatest(TenantId.SYS_TENANT_ID, device.getId(), PERSISTENT_ATTRIBUTES); |
443 | - return Futures.transform(tsData, extractDeviceStateData(device)); | |
443 | + return Futures.transform(tsData, extractDeviceStateData(device), MoreExecutors.directExecutor()); | |
444 | 444 | } else { |
445 | 445 | ListenableFuture<List<AttributeKvEntry>> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES); |
446 | - return Futures.transform(attrData, extractDeviceStateData(device)); | |
446 | + return Futures.transform(attrData, extractDeviceStateData(device), MoreExecutors.directExecutor()); | |
447 | 447 | } |
448 | 448 | } |
449 | 449 | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import com.google.common.base.Function; |
21 | 21 | import com.google.common.util.concurrent.FutureCallback; |
22 | 22 | import com.google.common.util.concurrent.Futures; |
23 | 23 | import com.google.common.util.concurrent.ListenableFuture; |
24 | +import com.google.common.util.concurrent.MoreExecutors; | |
24 | 25 | import lombok.extern.slf4j.Slf4j; |
25 | 26 | import org.springframework.beans.factory.annotation.Autowired; |
26 | 27 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -76,7 +77,10 @@ import java.util.List; |
76 | 77 | import java.util.Map; |
77 | 78 | import java.util.Optional; |
78 | 79 | import java.util.Set; |
79 | -import java.util.concurrent.*; | |
80 | +import java.util.concurrent.ConcurrentHashMap; | |
81 | +import java.util.concurrent.ConcurrentMap; | |
82 | +import java.util.concurrent.ExecutorService; | |
83 | +import java.util.concurrent.Executors; | |
80 | 84 | import java.util.function.Consumer; |
81 | 85 | import java.util.stream.Collectors; |
82 | 86 | |
... | ... | @@ -654,7 +658,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
654 | 658 | } |
655 | 659 | |
656 | 660 | ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures); |
657 | - Futures.addCallback(future, callback); | |
661 | + Futures.addCallback(future, callback, MoreExecutors.directExecutor()); | |
658 | 662 | } |
659 | 663 | |
660 | 664 | @Override |
... | ... | @@ -668,7 +672,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
668 | 672 | return new FutureCallback<ValidationResult>() { |
669 | 673 | @Override |
670 | 674 | public void onSuccess(@Nullable ValidationResult result) { |
671 | - Futures.addCallback(attributesService.find(tenantId, entityId, scope, keys), callback); | |
675 | + Futures.addCallback(attributesService.find(tenantId, entityId, scope, keys), callback, MoreExecutors.directExecutor()); | |
672 | 676 | } |
673 | 677 | |
674 | 678 | @Override |
... | ... | @@ -688,7 +692,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
688 | 692 | } |
689 | 693 | |
690 | 694 | ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures); |
691 | - Futures.addCallback(future, callback); | |
695 | + Futures.addCallback(future, callback, MoreExecutors.directExecutor()); | |
692 | 696 | } |
693 | 697 | |
694 | 698 | @Override |
... | ... | @@ -702,7 +706,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
702 | 706 | return new FutureCallback<ValidationResult>() { |
703 | 707 | @Override |
704 | 708 | public void onSuccess(@Nullable ValidationResult result) { |
705 | - Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), callback); | |
709 | + Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), callback, MoreExecutors.directExecutor()); | |
706 | 710 | } |
707 | 711 | |
708 | 712 | @Override | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; |
19 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 20 | import com.google.common.util.concurrent.Futures; |
21 | 21 | import com.google.common.util.concurrent.ListenableFuture; |
22 | +import com.google.common.util.concurrent.MoreExecutors; | |
22 | 23 | import lombok.extern.slf4j.Slf4j; |
23 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
24 | 25 | import org.springframework.stereotype.Service; |
... | ... | @@ -80,14 +81,14 @@ public class DefaultTransportApiService implements TransportApiService { |
80 | 81 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); |
81 | 82 | if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { |
82 | 83 | ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); |
83 | - return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders())); | |
84 | + return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
84 | 85 | } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { |
85 | 86 | ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); |
86 | - return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders())); | |
87 | + return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
87 | 88 | } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { |
88 | - return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders())); | |
89 | + return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
89 | 90 | } |
90 | - return Futures.transform(getEmptyTransportApiResponseFuture(), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders())); | |
91 | + return Futures.transform(getEmptyTransportApiResponseFuture(), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
91 | 92 | } |
92 | 93 | |
93 | 94 | private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { |
... | ... | @@ -147,7 +148,7 @@ public class DefaultTransportApiService implements TransportApiService { |
147 | 148 | log.warn("[{}] Failed to lookup device by id", deviceId, e); |
148 | 149 | return getEmptyTransportApiResponse(); |
149 | 150 | } |
150 | - }); | |
151 | + }, MoreExecutors.directExecutor()); | |
151 | 152 | } |
152 | 153 | |
153 | 154 | private DeviceInfoProto getDeviceInfoProto(Device device) throws JsonProcessingException { | ... | ... |
application/src/main/java/org/thingsboard/server/service/ttl/AbstractTimeseriesCleanUpService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.ttl; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.beans.factory.annotation.Value; | |
20 | +import org.springframework.scheduling.annotation.Scheduled; | |
21 | +import org.thingsboard.server.dao.util.PsqlTsAnyDao; | |
22 | + | |
23 | +import java.sql.Connection; | |
24 | +import java.sql.DriverManager; | |
25 | +import java.sql.ResultSet; | |
26 | +import java.sql.SQLException; | |
27 | +import java.sql.SQLWarning; | |
28 | +import java.sql.Statement; | |
29 | + | |
30 | +@PsqlTsAnyDao | |
31 | +@Slf4j | |
32 | +public abstract class AbstractTimeseriesCleanUpService { | |
33 | + | |
34 | + @Value("${sql.ttl.ts_key_value_ttl}") | |
35 | + protected long systemTtl; | |
36 | + | |
37 | + @Value("${sql.ttl.enabled}") | |
38 | + private boolean ttlTaskExecutionEnabled; | |
39 | + | |
40 | + @Value("${spring.datasource.url}") | |
41 | + private String dbUrl; | |
42 | + | |
43 | + @Value("${spring.datasource.username}") | |
44 | + private String dbUserName; | |
45 | + | |
46 | + @Value("${spring.datasource.password}") | |
47 | + private String dbPassword; | |
48 | + | |
49 | + @Scheduled(initialDelayString = "${sql.ttl.execution_interval_ms}", fixedDelayString = "${sql.ttl.execution_interval_ms}") | |
50 | + public void cleanUp() { | |
51 | + if (ttlTaskExecutionEnabled) { | |
52 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | |
53 | + doCleanUp(conn); | |
54 | + } catch (SQLException e) { | |
55 | + log.error("SQLException occurred during TTL task execution ", e); | |
56 | + } | |
57 | + } | |
58 | + } | |
59 | + | |
60 | + protected abstract void doCleanUp(Connection connection); | |
61 | + | |
62 | + protected long executeQuery(Connection conn, String query) { | |
63 | + long removed = 0L; | |
64 | + try { | |
65 | + Statement statement = conn.createStatement(); | |
66 | + ResultSet resultSet = statement.executeQuery(query); | |
67 | + getWarnings(statement); | |
68 | + resultSet.next(); | |
69 | + removed = resultSet.getLong(1); | |
70 | + log.debug("Successfully executed query: {}", query); | |
71 | + } catch (SQLException e) { | |
72 | + log.debug("Failed to execute query: {} due to: {}", query, e.getMessage()); | |
73 | + } | |
74 | + return removed; | |
75 | + } | |
76 | + | |
77 | + private void getWarnings(Statement statement) throws SQLException { | |
78 | + SQLWarning warnings = statement.getWarnings(); | |
79 | + if (warnings != null) { | |
80 | + log.debug("{}", warnings.getMessage()); | |
81 | + SQLWarning nextWarning = warnings.getNextWarning(); | |
82 | + while (nextWarning != null) { | |
83 | + log.debug("{}", nextWarning.getMessage()); | |
84 | + nextWarning = nextWarning.getNextWarning(); | |
85 | + } | |
86 | + } | |
87 | + } | |
88 | + | |
89 | +} | |
\ No newline at end of file | ... | ... |
application/src/main/java/org/thingsboard/server/service/ttl/PsqlTimeseriesCleanUpService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.ttl; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.beans.factory.annotation.Value; | |
20 | +import org.springframework.stereotype.Service; | |
21 | +import org.thingsboard.server.dao.model.ModelConstants; | |
22 | +import org.thingsboard.server.dao.util.PsqlTsDao; | |
23 | + | |
24 | +import java.sql.Connection; | |
25 | + | |
26 | +@PsqlTsDao | |
27 | +@Service | |
28 | +@Slf4j | |
29 | +public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { | |
30 | + | |
31 | + @Value("${sql.postgres.ts_key_value_partitioning}") | |
32 | + private String partitionType; | |
33 | + | |
34 | + @Override | |
35 | + protected void doCleanUp(Connection connection) { | |
36 | + long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);"); | |
37 | + log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved); | |
38 | + long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); | |
39 | + log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); | |
40 | + } | |
41 | +} | |
\ No newline at end of file | ... | ... |
application/src/main/java/org/thingsboard/server/service/ttl/TimescaleTimeseriesCleanUpService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.ttl; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.stereotype.Service; | |
20 | +import org.thingsboard.server.dao.model.ModelConstants; | |
21 | +import org.thingsboard.server.dao.util.TimescaleDBTsDao; | |
22 | + | |
23 | +import java.sql.Connection; | |
24 | + | |
25 | +@TimescaleDBTsDao | |
26 | +@Service | |
27 | +@Slf4j | |
28 | +public class TimescaleTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { | |
29 | + | |
30 | + @Override | |
31 | + protected void doCleanUp(Connection connection) { | |
32 | + long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); | |
33 | + log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); | |
34 | + } | |
35 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -202,6 +202,10 @@ sql: |
202 | 202 | timescale: |
203 | 203 | # Specify Interval size for new data chunks storage. |
204 | 204 | chunk_time_interval: "${SQL_TIMESCALE_CHUNK_TIME_INTERVAL:604800000}" |
205 | + ttl: | |
206 | + enabled: "${SQL_TTL_ENABLED:true}" | |
207 | + execution_interval_ms: "${SQL_TTL_EXECUTION_INTERVAL:86400000}" # Number of miliseconds | |
208 | + ts_key_value_ttl: "${SQL_TTL_TS_KEY_VALUE_TTL:0}" # Number of seconds | |
205 | 209 | |
206 | 210 | # Actor system parameters |
207 | 211 | actors: | ... | ... |
... | ... | @@ -2,8 +2,8 @@ |
2 | 2 | |
3 | 3 | set -e |
4 | 4 | |
5 | -chown -R ${pkg.name}: ${pkg.logFolder} | |
6 | -chown -R ${pkg.name}: ${pkg.installFolder} | |
5 | +chown -R ${pkg.user}: ${pkg.logFolder} | |
6 | +chown -R ${pkg.user}: ${pkg.installFolder} | |
7 | 7 | systemctl --no-reload enable ${pkg.name}.service >/dev/null 2>&1 || : |
8 | 8 | |
9 | 9 | exit 0 | ... | ... |
... | ... | @@ -2,21 +2,21 @@ |
2 | 2 | |
3 | 3 | set -e |
4 | 4 | |
5 | -if ! getent group ${pkg.name} >/dev/null; then | |
6 | - addgroup --system ${pkg.name} | |
5 | +if ! getent group ${pkg.user} >/dev/null; then | |
6 | + addgroup --system ${pkg.user} | |
7 | 7 | fi |
8 | 8 | |
9 | -if ! getent passwd ${pkg.name} >/dev/null; then | |
9 | +if ! getent passwd ${pkg.user} >/dev/null; then | |
10 | 10 | adduser --quiet \ |
11 | 11 | --system \ |
12 | - --ingroup ${pkg.name} \ | |
12 | + --ingroup ${pkg.user} \ | |
13 | 13 | --quiet \ |
14 | 14 | --disabled-login \ |
15 | 15 | --disabled-password \ |
16 | 16 | --home ${pkg.installFolder} \ |
17 | 17 | --no-create-home \ |
18 | 18 | -gecos "Thingsboard application" \ |
19 | - ${pkg.name} | |
19 | + ${pkg.user} | |
20 | 20 | fi |
21 | 21 | |
22 | 22 | exit 0 |
\ No newline at end of file | ... | ... |
1 | 1 | #!/bin/sh |
2 | 2 | |
3 | -getent group ${pkg.name} >/dev/null || groupadd -r ${pkg.name} | |
4 | -getent passwd ${pkg.name} >/dev/null || \ | |
5 | -useradd -d ${pkg.installFolder} -g ${pkg.name} -M -r ${pkg.name} -s /sbin/nologin \ | |
3 | +getent group ${pkg.user} >/dev/null || groupadd -r ${pkg.user} | |
4 | +getent passwd ${pkg.user} >/dev/null || \ | |
5 | +useradd -d ${pkg.installFolder} -g ${pkg.user} -M -r ${pkg.user} -s /sbin/nologin \ | |
6 | 6 | -c "Thingsboard application" | ... | ... |
... | ... | @@ -44,7 +44,7 @@ installDir=${pkg.installFolder}/data |
44 | 44 | |
45 | 45 | source "${CONF_FOLDER}/${configfile}" |
46 | 46 | |
47 | -run_user=${pkg.name} | |
47 | +run_user=${pkg.user} | |
48 | 48 | |
49 | 49 | su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ |
50 | 50 | -Dinstall.data_dir=${installDir} \ | ... | ... |
... | ... | @@ -43,7 +43,7 @@ installDir=${pkg.installFolder}/data |
43 | 43 | |
44 | 44 | source "${CONF_FOLDER}/${configfile}" |
45 | 45 | |
46 | -run_user=${pkg.name} | |
46 | +run_user=${pkg.user} | |
47 | 47 | |
48 | 48 | su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ |
49 | 49 | -Dinstall.data_dir=${installDir} \ | ... | ... |
... | ... | @@ -39,7 +39,7 @@ public interface AlarmService { |
39 | 39 | |
40 | 40 | ListenableFuture<Boolean> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs); |
41 | 41 | |
42 | - ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long ackTs); | |
42 | + ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); | |
43 | 43 | |
44 | 44 | ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId); |
45 | 45 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.util; | |
17 | + | |
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | |
19 | + | |
20 | +@ConditionalOnExpression("'${database.ts.type}'=='sql' && '${spring.jpa.database-platform}'=='org.hibernate.dialect.PostgreSQLDialect'") | |
21 | +public @interface PsqlTsDao { } | |
\ No newline at end of file | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.queue.common; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | |
22 | 23 | import java.util.concurrent.Executor; |
23 | 24 | import java.util.concurrent.ScheduledExecutorService; |
... | ... | @@ -59,7 +60,7 @@ public class AsyncCallbackTemplate { |
59 | 60 | if (executor != null) { |
60 | 61 | Futures.addCallback(future, callback, executor); |
61 | 62 | } else { |
62 | - Futures.addCallback(future, callback); | |
63 | + Futures.addCallback(future, callback, MoreExecutors.directExecutor()); | |
63 | 64 | } |
64 | 65 | } |
65 | 66 | ... | ... |
... | ... | @@ -18,19 +18,20 @@ package org.thingsboard.common.util; |
18 | 18 | import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | |
22 | 23 | import java.util.concurrent.Executor; |
23 | 24 | import java.util.function.Consumer; |
24 | 25 | |
25 | 26 | public class DonAsynchron { |
26 | 27 | |
27 | - public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess, | |
28 | - Consumer<Throwable> onFailure) { | |
28 | + public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess, | |
29 | + Consumer<Throwable> onFailure) { | |
29 | 30 | withCallback(future, onSuccess, onFailure, null); |
30 | 31 | } |
31 | 32 | |
32 | - public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess, | |
33 | - Consumer<Throwable> onFailure, Executor executor) { | |
33 | + public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess, | |
34 | + Consumer<Throwable> onFailure, Executor executor) { | |
34 | 35 | FutureCallback<T> callback = new FutureCallback<T>() { |
35 | 36 | @Override |
36 | 37 | public void onSuccess(T result) { |
... | ... | @@ -49,7 +50,7 @@ public class DonAsynchron { |
49 | 50 | if (executor != null) { |
50 | 51 | Futures.addCallback(future, callback, executor); |
51 | 52 | } else { |
52 | - Futures.addCallback(future, callback); | |
53 | + Futures.addCallback(future, callback, MoreExecutors.directExecutor()); | |
53 | 54 | } |
54 | 55 | } |
55 | 56 | } | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
20 | 20 | import com.google.common.base.Function; |
21 | 21 | import com.google.common.util.concurrent.Futures; |
22 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | +import com.google.common.util.concurrent.MoreExecutors; | |
23 | 24 | import lombok.extern.slf4j.Slf4j; |
24 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 26 | import org.springframework.stereotype.Service; |
... | ... | @@ -53,7 +54,6 @@ import javax.annotation.Nullable; |
53 | 54 | import javax.annotation.PostConstruct; |
54 | 55 | import javax.annotation.PreDestroy; |
55 | 56 | import java.util.ArrayList; |
56 | -import java.util.Collections; | |
57 | 57 | import java.util.Comparator; |
58 | 58 | import java.util.List; |
59 | 59 | import java.util.Set; |
... | ... | @@ -264,9 +264,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
264 | 264 | entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { |
265 | 265 | alarmInfo.setOriginatorName(originatorName); |
266 | 266 | return alarmInfo; |
267 | - } | |
268 | - ); | |
269 | - }); | |
267 | + }, MoreExecutors.directExecutor()); | |
268 | + }, MoreExecutors.directExecutor()); | |
270 | 269 | } |
271 | 270 | |
272 | 271 | @Override |
... | ... | @@ -283,11 +282,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
283 | 282 | } |
284 | 283 | alarmInfo.setOriginatorName(originatorName); |
285 | 284 | return alarmInfo; |
286 | - } | |
285 | + }, MoreExecutors.directExecutor() | |
287 | 286 | )); |
288 | 287 | } |
289 | 288 | return Futures.successfulAsList(alarmFutures); |
290 | - }); | |
289 | + }, MoreExecutors.directExecutor()); | |
291 | 290 | } |
292 | 291 | return Futures.transform(alarms, new Function<List<AlarmInfo>, TimePageData<AlarmInfo>>() { |
293 | 292 | @Nullable |
... | ... | @@ -295,7 +294,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
295 | 294 | public TimePageData<AlarmInfo> apply(@Nullable List<AlarmInfo> alarms) { |
296 | 295 | return new TimePageData<>(alarms, query.getPageLink()); |
297 | 296 | } |
298 | - }); | |
297 | + }, MoreExecutors.directExecutor()); | |
299 | 298 | } |
300 | 299 | |
301 | 300 | @Override | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.datastax.driver.core.querybuilder.QueryBuilder; |
20 | 20 | import com.datastax.driver.core.querybuilder.Select; |
21 | 21 | import com.google.common.util.concurrent.Futures; |
22 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | +import com.google.common.util.concurrent.MoreExecutors; | |
23 | 24 | import lombok.extern.slf4j.Slf4j; |
24 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 26 | import org.springframework.stereotype.Component; |
... | ... | @@ -82,10 +83,10 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al |
82 | 83 | @Override |
83 | 84 | public Boolean deleteAlarm(TenantId tenantId, Alarm alarm) { |
84 | 85 | Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, alarm.getId().getId())) |
85 | - .and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId())) | |
86 | - .and(eq(ALARM_ORIGINATOR_ID_PROPERTY, alarm.getOriginator().getId())) | |
87 | - .and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, alarm.getOriginator().getEntityType())) | |
88 | - .and(eq(ALARM_TYPE_PROPERTY, alarm.getType())); | |
86 | + .and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId())) | |
87 | + .and(eq(ALARM_ORIGINATOR_ID_PROPERTY, alarm.getOriginator().getId())) | |
88 | + .and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, alarm.getOriginator().getEntityType())) | |
89 | + .and(eq(ALARM_TYPE_PROPERTY, alarm.getType())); | |
89 | 90 | log.debug("Remove request: {}", delete.toString()); |
90 | 91 | return executeWrite(tenantId, delete).wasApplied(); |
91 | 92 | } |
... | ... | @@ -122,10 +123,10 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al |
122 | 123 | for (EntityRelation relation : input) { |
123 | 124 | alarmFutures.add(Futures.transform( |
124 | 125 | findAlarmByIdAsync(tenantId, relation.getTo().getId()), |
125 | - AlarmInfo::new)); | |
126 | + AlarmInfo::new, MoreExecutors.directExecutor())); | |
126 | 127 | } |
127 | 128 | return Futures.successfulAsList(alarmFutures); |
128 | - }); | |
129 | + }, MoreExecutors.directExecutor()); | |
129 | 130 | } |
130 | 131 | |
131 | 132 | @Override | ... | ... |
... | ... | @@ -16,9 +16,9 @@ |
16 | 16 | package org.thingsboard.server.dao.asset; |
17 | 17 | |
18 | 18 | |
19 | -import com.google.common.base.Function; | |
20 | 19 | import com.google.common.util.concurrent.Futures; |
21 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
22 | 22 | import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.hibernate.exception.ConstraintViolationException; |
24 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -29,7 +29,6 @@ import org.springframework.cache.annotation.Cacheable; |
29 | 29 | import org.springframework.stereotype.Service; |
30 | 30 | import org.springframework.util.StringUtils; |
31 | 31 | import org.thingsboard.server.common.data.Customer; |
32 | -import org.thingsboard.server.common.data.Device; | |
33 | 32 | import org.thingsboard.server.common.data.EntitySubtype; |
34 | 33 | import org.thingsboard.server.common.data.EntityType; |
35 | 34 | import org.thingsboard.server.common.data.EntityView; |
... | ... | @@ -62,7 +61,10 @@ import java.util.stream.Collectors; |
62 | 61 | import static org.thingsboard.server.common.data.CacheConstants.ASSET_CACHE; |
63 | 62 | import static org.thingsboard.server.dao.DaoUtil.toUUIDs; |
64 | 63 | import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
65 | -import static org.thingsboard.server.dao.service.Validator.*; | |
64 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
65 | +import static org.thingsboard.server.dao.service.Validator.validateIds; | |
66 | +import static org.thingsboard.server.dao.service.Validator.validatePageLink; | |
67 | +import static org.thingsboard.server.dao.service.Validator.validateString; | |
66 | 68 | |
67 | 69 | @Service |
68 | 70 | @Slf4j |
... | ... | @@ -258,9 +260,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ |
258 | 260 | } |
259 | 261 | } |
260 | 262 | return Futures.successfulAsList(futures); |
261 | - }); | |
263 | + }, MoreExecutors.directExecutor()); | |
262 | 264 | assets = Futures.transform(assets, assetList -> |
263 | - assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()) | |
265 | + assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()), MoreExecutors.directExecutor() | |
264 | 266 | ); |
265 | 267 | return assets; |
266 | 268 | } |
... | ... | @@ -274,7 +276,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ |
274 | 276 | assetTypes -> { |
275 | 277 | assetTypes.sort(Comparator.comparing(EntitySubtype::getType)); |
276 | 278 | return assetTypes; |
277 | - }); | |
279 | + }, MoreExecutors.directExecutor()); | |
278 | 280 | } |
279 | 281 | |
280 | 282 | private DataValidator<Asset> assetValidator = |
... | ... | @@ -335,18 +337,18 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ |
335 | 337 | }; |
336 | 338 | |
337 | 339 | private PaginatedRemover<TenantId, Asset> tenantAssetsRemover = |
338 | - new PaginatedRemover<TenantId, Asset>() { | |
340 | + new PaginatedRemover<TenantId, Asset>() { | |
339 | 341 | |
340 | - @Override | |
341 | - protected List<Asset> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
342 | - return assetDao.findAssetsByTenantId(id.getId(), pageLink); | |
343 | - } | |
342 | + @Override | |
343 | + protected List<Asset> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
344 | + return assetDao.findAssetsByTenantId(id.getId(), pageLink); | |
345 | + } | |
344 | 346 | |
345 | - @Override | |
346 | - protected void removeEntity(TenantId tenantId, Asset entity) { | |
347 | - deleteAsset(tenantId, new AssetId(entity.getId().getId())); | |
348 | - } | |
349 | - }; | |
347 | + @Override | |
348 | + protected void removeEntity(TenantId tenantId, Asset entity) { | |
349 | + deleteAsset(tenantId, new AssetId(entity.getId().getId())); | |
350 | + } | |
351 | + }; | |
350 | 352 | |
351 | 353 | private PaginatedRemover<CustomerId, Asset> customerAssetsUnasigner = new PaginatedRemover<CustomerId, Asset>() { |
352 | 354 | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import com.datastax.driver.mapping.Result; |
23 | 23 | import com.google.common.base.Function; |
24 | 24 | import com.google.common.util.concurrent.Futures; |
25 | 25 | import com.google.common.util.concurrent.ListenableFuture; |
26 | +import com.google.common.util.concurrent.MoreExecutors; | |
26 | 27 | import lombok.extern.slf4j.Slf4j; |
27 | 28 | import org.springframework.stereotype.Component; |
28 | 29 | import org.thingsboard.server.common.data.EntitySubtype; |
... | ... | @@ -185,7 +186,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit |
185 | 186 | return Collections.emptyList(); |
186 | 187 | } |
187 | 188 | } |
188 | - }); | |
189 | + }, MoreExecutors.directExecutor()); | |
189 | 190 | } |
190 | 191 | |
191 | 192 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.Futures; |
19 | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | +import com.google.common.util.concurrent.MoreExecutors; | |
20 | 21 | import lombok.extern.slf4j.Slf4j; |
21 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 23 | import org.springframework.stereotype.Component; |
... | ... | @@ -85,7 +86,7 @@ public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao<Da |
85 | 86 | dashboardFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); |
86 | 87 | } |
87 | 88 | return Futures.successfulAsList(dashboardFutures); |
88 | - }); | |
89 | + }, MoreExecutors.directExecutor()); | |
89 | 90 | } |
90 | 91 | |
91 | 92 | } | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.dashboard; |
18 | 18 | import com.google.common.base.Function; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | 23 | import org.apache.commons.lang3.StringUtils; |
23 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -64,7 +65,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
64 | 65 | |
65 | 66 | @Autowired |
66 | 67 | private TenantDao tenantDao; |
67 | - | |
68 | + | |
68 | 69 | @Autowired |
69 | 70 | private CustomerDao customerDao; |
70 | 71 | |
... | ... | @@ -102,7 +103,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
102 | 103 | dashboardValidator.validate(dashboard, DashboardInfo::getTenantId); |
103 | 104 | return dashboardDao.save(dashboard.getTenantId(), dashboard); |
104 | 105 | } |
105 | - | |
106 | + | |
106 | 107 | @Override |
107 | 108 | public Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, CustomerId customerId) { |
108 | 109 | Dashboard dashboard = findDashboardById(tenantId, dashboardId); |
... | ... | @@ -203,7 +204,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
203 | 204 | public TimePageData<DashboardInfo> apply(@Nullable List<DashboardInfo> dashboards) { |
204 | 205 | return new TimePageData<>(dashboards, pageLink); |
205 | 206 | } |
206 | - }); | |
207 | + }, MoreExecutors.directExecutor()); | |
207 | 208 | } |
208 | 209 | |
209 | 210 | @Override |
... | ... | @@ -244,24 +245,24 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
244 | 245 | } |
245 | 246 | } |
246 | 247 | } |
247 | - }; | |
248 | - | |
248 | + }; | |
249 | + | |
249 | 250 | private PaginatedRemover<TenantId, DashboardInfo> tenantDashboardsRemover = |
250 | 251 | new PaginatedRemover<TenantId, DashboardInfo>() { |
251 | - | |
252 | - @Override | |
253 | - protected List<DashboardInfo> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
254 | - return dashboardInfoDao.findDashboardsByTenantId(id.getId(), pageLink); | |
255 | - } | |
256 | 252 | |
257 | - @Override | |
258 | - protected void removeEntity(TenantId tenantId, DashboardInfo entity) { | |
259 | - deleteDashboard(tenantId, new DashboardId(entity.getUuidId())); | |
260 | - } | |
261 | - }; | |
262 | - | |
253 | + @Override | |
254 | + protected List<DashboardInfo> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
255 | + return dashboardInfoDao.findDashboardsByTenantId(id.getId(), pageLink); | |
256 | + } | |
257 | + | |
258 | + @Override | |
259 | + protected void removeEntity(TenantId tenantId, DashboardInfo entity) { | |
260 | + deleteDashboard(tenantId, new DashboardId(entity.getUuidId())); | |
261 | + } | |
262 | + }; | |
263 | + | |
263 | 264 | private class CustomerDashboardsUnassigner extends TimePaginatedRemover<Customer, DashboardInfo> { |
264 | - | |
265 | + | |
265 | 266 | private Customer customer; |
266 | 267 | |
267 | 268 | CustomerDashboardsUnassigner(Customer customer) { |
... | ... | @@ -282,7 +283,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
282 | 283 | protected void removeEntity(TenantId tenantId, DashboardInfo entity) { |
283 | 284 | unassignDashboardFromCustomer(customer.getTenantId(), new DashboardId(entity.getUuidId()), this.customer.getId()); |
284 | 285 | } |
285 | - | |
286 | + | |
286 | 287 | } |
287 | 288 | |
288 | 289 | private class CustomerDashboardsUpdater extends TimePaginatedRemover<Customer, DashboardInfo> { | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import com.datastax.driver.mapping.Result; |
23 | 23 | import com.google.common.base.Function; |
24 | 24 | import com.google.common.util.concurrent.Futures; |
25 | 25 | import com.google.common.util.concurrent.ListenableFuture; |
26 | +import com.google.common.util.concurrent.MoreExecutors; | |
26 | 27 | import lombok.extern.slf4j.Slf4j; |
27 | 28 | import org.springframework.stereotype.Component; |
28 | 29 | import org.thingsboard.server.common.data.Device; |
... | ... | @@ -178,14 +179,14 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt |
178 | 179 | if (result != null) { |
179 | 180 | List<EntitySubtype> entitySubtypes = new ArrayList<>(); |
180 | 181 | result.all().forEach((entitySubtypeEntity) -> |
181 | - entitySubtypes.add(entitySubtypeEntity.toEntitySubtype()) | |
182 | + entitySubtypes.add(entitySubtypeEntity.toEntitySubtype()) | |
182 | 183 | ); |
183 | 184 | return entitySubtypes; |
184 | 185 | } else { |
185 | 186 | return Collections.emptyList(); |
186 | 187 | } |
187 | 188 | } |
188 | - }); | |
189 | + }, MoreExecutors.directExecutor()); | |
189 | 190 | } |
190 | 191 | |
191 | 192 | } | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.device; |
18 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 24 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -97,9 +98,9 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { |
97 | 98 | } |
98 | 99 | log.warn("Failed to find claimingAllowed attribute for device or it is already claimed![{}]", device.getName()); |
99 | 100 | throw new IllegalArgumentException(); |
100 | - }); | |
101 | + }, MoreExecutors.directExecutor()); | |
101 | 102 | } |
102 | - }); | |
103 | + }, MoreExecutors.directExecutor()); | |
103 | 104 | } |
104 | 105 | |
105 | 106 | private ClaimDataInfo getClaimData(Cache cache, Device device) throws ExecutionException, InterruptedException { |
... | ... | @@ -138,9 +139,9 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { |
138 | 139 | if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
139 | 140 | device.setCustomerId(customerId); |
140 | 141 | Device savedDevice = deviceService.saveDevice(device); |
141 | - return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS)); | |
142 | + return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS), MoreExecutors.directExecutor()); | |
142 | 143 | } |
143 | - return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED)); | |
144 | + return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED), MoreExecutors.directExecutor()); | |
144 | 145 | } |
145 | 146 | } else { |
146 | 147 | log.warn("Failed to find the device's claiming message![{}]", device.getName()); | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.device; |
18 | 18 | import com.google.common.base.Function; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | 23 | import org.apache.commons.lang3.RandomStringUtils; |
23 | 24 | import org.hibernate.exception.ConstraintViolationException; |
... | ... | @@ -291,7 +292,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
291 | 292 | } |
292 | 293 | } |
293 | 294 | return Futures.successfulAsList(futures); |
294 | - }); | |
295 | + }, MoreExecutors.directExecutor()); | |
295 | 296 | |
296 | 297 | devices = Futures.transform(devices, new Function<List<Device>, List<Device>>() { |
297 | 298 | @Nullable |
... | ... | @@ -299,7 +300,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
299 | 300 | public List<Device> apply(@Nullable List<Device> deviceList) { |
300 | 301 | return deviceList == null ? Collections.emptyList() : deviceList.stream().filter(device -> query.getDeviceTypes().contains(device.getType())).collect(Collectors.toList()); |
301 | 302 | } |
302 | - }); | |
303 | + }, MoreExecutors.directExecutor()); | |
303 | 304 | |
304 | 305 | return devices; |
305 | 306 | } |
... | ... | @@ -313,7 +314,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
313 | 314 | deviceTypes -> { |
314 | 315 | deviceTypes.sort(Comparator.comparing(EntitySubtype::getType)); |
315 | 316 | return deviceTypes; |
316 | - }); | |
317 | + }, MoreExecutors.directExecutor()); | |
317 | 318 | } |
318 | 319 | |
319 | 320 | private DataValidator<Device> deviceValidator = |
... | ... | @@ -374,18 +375,18 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
374 | 375 | }; |
375 | 376 | |
376 | 377 | private PaginatedRemover<TenantId, Device> tenantDevicesRemover = |
377 | - new PaginatedRemover<TenantId, Device>() { | |
378 | + new PaginatedRemover<TenantId, Device>() { | |
378 | 379 | |
379 | - @Override | |
380 | - protected List<Device> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
381 | - return deviceDao.findDevicesByTenantId(id.getId(), pageLink); | |
382 | - } | |
380 | + @Override | |
381 | + protected List<Device> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { | |
382 | + return deviceDao.findDevicesByTenantId(id.getId(), pageLink); | |
383 | + } | |
383 | 384 | |
384 | - @Override | |
385 | - protected void removeEntity(TenantId tenantId, Device entity) { | |
386 | - deleteDevice(tenantId, new DeviceId(entity.getUuidId())); | |
387 | - } | |
388 | - }; | |
385 | + @Override | |
386 | + protected void removeEntity(TenantId tenantId, Device entity) { | |
387 | + deleteDevice(tenantId, new DeviceId(entity.getUuidId())); | |
388 | + } | |
389 | + }; | |
389 | 390 | |
390 | 391 | private PaginatedRemover<CustomerId, Device> customerDeviceUnasigner = new PaginatedRemover<CustomerId, Device>() { |
391 | 392 | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import com.datastax.driver.mapping.Result; |
23 | 23 | import com.google.common.base.Function; |
24 | 24 | import com.google.common.util.concurrent.Futures; |
25 | 25 | import com.google.common.util.concurrent.ListenableFuture; |
26 | +import com.google.common.util.concurrent.MoreExecutors; | |
26 | 27 | import lombok.extern.slf4j.Slf4j; |
27 | 28 | import org.springframework.stereotype.Component; |
28 | 29 | import org.thingsboard.server.common.data.EntitySubtype; |
... | ... | @@ -97,7 +98,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit |
97 | 98 | log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
98 | 99 | List<EntityViewEntity> entityViewEntities = |
99 | 100 | findPageWithTextSearch(new TenantId(tenantId), ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF, |
100 | - Collections.singletonList(eq(TENANT_ID_PROPERTY, tenantId)), pageLink); | |
101 | + Collections.singletonList(eq(TENANT_ID_PROPERTY, tenantId)), pageLink); | |
101 | 102 | log.trace("Found entity views [{}] by tenantId [{}] and pageLink [{}]", |
102 | 103 | entityViewEntities, tenantId, pageLink); |
103 | 104 | return DaoUtil.convertDataList(entityViewEntities); |
... | ... | @@ -181,6 +182,6 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit |
181 | 182 | return Collections.emptyList(); |
182 | 183 | } |
183 | 184 | } |
184 | - }); | |
185 | + }, MoreExecutors.directExecutor()); | |
185 | 186 | } |
186 | 187 | } | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import com.google.common.base.Function; |
19 | 19 | import com.google.common.util.concurrent.FutureCallback; |
20 | 20 | import com.google.common.util.concurrent.Futures; |
21 | 21 | import com.google.common.util.concurrent.ListenableFuture; |
22 | +import com.google.common.util.concurrent.MoreExecutors; | |
22 | 23 | import lombok.extern.slf4j.Slf4j; |
23 | 24 | import org.apache.commons.lang3.StringUtils; |
24 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -199,7 +200,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti |
199 | 200 | } |
200 | 201 | } |
201 | 202 | return Futures.successfulAsList(futures); |
202 | - }); | |
203 | + }, MoreExecutors.directExecutor()); | |
203 | 204 | |
204 | 205 | entityViews = Futures.transform(entityViews, new Function<List<EntityView>, List<EntityView>>() { |
205 | 206 | @Nullable |
... | ... | @@ -207,7 +208,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti |
207 | 208 | public List<EntityView> apply(@Nullable List<EntityView> entityViewList) { |
208 | 209 | return entityViewList == null ? Collections.emptyList() : entityViewList.stream().filter(entityView -> query.getEntityViewTypes().contains(entityView.getType())).collect(Collectors.toList()); |
209 | 210 | } |
210 | - }); | |
211 | + }, MoreExecutors.directExecutor()); | |
211 | 212 | |
212 | 213 | return entityViews; |
213 | 214 | } |
... | ... | @@ -246,7 +247,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti |
246 | 247 | public void onFailure(Throwable t) { |
247 | 248 | log.error("Error while finding entity views by tenantId and entityId", t); |
248 | 249 | } |
249 | - }); | |
250 | + }, MoreExecutors.directExecutor()); | |
250 | 251 | return entityViewsFuture; |
251 | 252 | } |
252 | 253 | } |
... | ... | @@ -279,7 +280,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti |
279 | 280 | entityViewTypes -> { |
280 | 281 | entityViewTypes.sort(Comparator.comparing(EntitySubtype::getType)); |
281 | 282 | return entityViewTypes; |
282 | - }); | |
283 | + }, MoreExecutors.directExecutor()); | |
283 | 284 | } |
284 | 285 | |
285 | 286 | private DataValidator<EntityView> entityViewValidator = | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import com.datastax.driver.core.querybuilder.Select; |
22 | 22 | import com.datastax.driver.core.utils.UUIDs; |
23 | 23 | import com.google.common.util.concurrent.Futures; |
24 | 24 | import com.google.common.util.concurrent.ListenableFuture; |
25 | +import com.google.common.util.concurrent.MoreExecutors; | |
25 | 26 | import lombok.extern.slf4j.Slf4j; |
26 | 27 | import org.apache.commons.lang3.StringUtils; |
27 | 28 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -45,10 +46,12 @@ import java.util.UUID; |
45 | 46 | import java.util.concurrent.ExecutionException; |
46 | 47 | |
47 | 48 | import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
48 | -import static com.datastax.driver.core.querybuilder.QueryBuilder.in; | |
49 | 49 | import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
50 | 50 | import static com.datastax.driver.core.querybuilder.QueryBuilder.ttl; |
51 | -import static org.thingsboard.server.dao.model.ModelConstants.*; | |
51 | +import static org.thingsboard.server.dao.model.ModelConstants.EVENT_BY_ID_VIEW_NAME; | |
52 | +import static org.thingsboard.server.dao.model.ModelConstants.EVENT_BY_TYPE_AND_ID_VIEW_NAME; | |
53 | +import static org.thingsboard.server.dao.model.ModelConstants.EVENT_COLUMN_FAMILY_NAME; | |
54 | +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | |
52 | 55 | |
53 | 56 | @Component |
54 | 57 | @Slf4j |
... | ... | @@ -96,7 +99,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE |
96 | 99 | event.setUid(event.getId().toString()); |
97 | 100 | } |
98 | 101 | ListenableFuture<Optional<Event>> optionalSave = saveAsync(event.getTenantId(), new EventEntity(event), false, eventsTtl); |
99 | - return Futures.transform(optionalSave, opt -> opt.orElse(null)); | |
102 | + return Futures.transform(optionalSave, opt -> opt.orElse(null), MoreExecutors.directExecutor()); | |
100 | 103 | } |
101 | 104 | |
102 | 105 | @Override |
... | ... | @@ -210,6 +213,6 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE |
210 | 213 | } else { |
211 | 214 | return Optional.empty(); |
212 | 215 | } |
213 | - }); | |
216 | + }, MoreExecutors.directExecutor()); | |
214 | 217 | } |
215 | 218 | } | ... | ... |
... | ... | @@ -36,6 +36,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.BOOLEAN_VALUE_COLU |
36 | 36 | import static org.thingsboard.server.dao.model.ModelConstants.DOUBLE_VALUE_COLUMN; |
37 | 37 | import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; |
38 | 38 | import static org.thingsboard.server.dao.model.ModelConstants.JSON_VALUE_COLUMN; |
39 | +import static org.thingsboard.server.dao.model.ModelConstants.KEY_COLUMN; | |
39 | 40 | import static org.thingsboard.server.dao.model.ModelConstants.LONG_VALUE_COLUMN; |
40 | 41 | import static org.thingsboard.server.dao.model.ModelConstants.STRING_VALUE_COLUMN; |
41 | 42 | import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; |
... | ... | @@ -54,6 +55,10 @@ public abstract class AbstractTsKvEntity implements ToData<TsKvEntry> { |
54 | 55 | protected UUID entityId; |
55 | 56 | |
56 | 57 | @Id |
58 | + @Column(name = KEY_COLUMN) | |
59 | + protected int key; | |
60 | + | |
61 | + @Id | |
57 | 62 | @Column(name = TS_COLUMN) |
58 | 63 | protected Long ts; |
59 | 64 | ... | ... |
... | ... | @@ -69,10 +69,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.KEY_COLUMN; |
69 | 69 | }) |
70 | 70 | public final class TsKvLatestEntity extends AbstractTsKvEntity { |
71 | 71 | |
72 | - @Id | |
73 | - @Column(name = KEY_COLUMN) | |
74 | - private int key; | |
75 | - | |
76 | 72 | @Override |
77 | 73 | public boolean isNotEmpty() { |
78 | 74 | return strValue != null || longValue != null || doubleValue != null || booleanValue != null || jsonValue != null; | ... | ... |
... | ... | @@ -18,25 +18,18 @@ package org.thingsboard.server.dao.model.sqlts.timescale.ts; |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.EqualsAndHashCode; |
20 | 20 | import org.springframework.util.StringUtils; |
21 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | |
22 | -import org.thingsboard.server.dao.model.ToData; | |
23 | 21 | import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity; |
24 | 22 | |
25 | -import javax.persistence.Column; | |
26 | 23 | import javax.persistence.ColumnResult; |
27 | 24 | import javax.persistence.ConstructorResult; |
28 | 25 | import javax.persistence.Entity; |
29 | -import javax.persistence.Id; | |
30 | 26 | import javax.persistence.IdClass; |
31 | 27 | import javax.persistence.NamedNativeQueries; |
32 | 28 | import javax.persistence.NamedNativeQuery; |
33 | 29 | import javax.persistence.SqlResultSetMapping; |
34 | 30 | import javax.persistence.SqlResultSetMappings; |
35 | 31 | import javax.persistence.Table; |
36 | -import java.util.UUID; | |
37 | 32 | |
38 | -import static org.thingsboard.server.dao.model.ModelConstants.KEY_COLUMN; | |
39 | -import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_COLUMN; | |
40 | 33 | import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.FIND_AVG; |
41 | 34 | import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.FIND_AVG_QUERY; |
42 | 35 | import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.FIND_COUNT; |
... | ... | @@ -52,7 +45,7 @@ import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.F |
52 | 45 | @Data |
53 | 46 | @EqualsAndHashCode(callSuper = true) |
54 | 47 | @Entity |
55 | -@Table(name = "tenant_ts_kv") | |
48 | +@Table(name = "ts_kv") | |
56 | 49 | @IdClass(TimescaleTsKvCompositeKey.class) |
57 | 50 | @SqlResultSetMappings({ |
58 | 51 | @SqlResultSetMapping( |
... | ... | @@ -116,15 +109,7 @@ import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.F |
116 | 109 | resultSetMapping = "timescaleCountMapping" |
117 | 110 | ) |
118 | 111 | }) |
119 | -public final class TimescaleTsKvEntity extends AbstractTsKvEntity implements ToData<TsKvEntry> { | |
120 | - | |
121 | - @Id | |
122 | - @Column(name = TENANT_ID_COLUMN, columnDefinition = "uuid") | |
123 | - private UUID tenantId; | |
124 | - | |
125 | - @Id | |
126 | - @Column(name = KEY_COLUMN) | |
127 | - private int key; | |
112 | +public final class TimescaleTsKvEntity extends AbstractTsKvEntity { | |
128 | 113 | |
129 | 114 | public TimescaleTsKvEntity() { |
130 | 115 | } | ... | ... |
... | ... | @@ -32,10 +32,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.KEY_COLUMN; |
32 | 32 | @IdClass(TsKvCompositeKey.class) |
33 | 33 | public final class TsKvEntity extends AbstractTsKvEntity { |
34 | 34 | |
35 | - @Id | |
36 | - @Column(name = KEY_COLUMN) | |
37 | - private int key; | |
38 | - | |
39 | 35 | public TsKvEntity() { |
40 | 36 | } |
41 | 37 | ... | ... |
... | ... | @@ -26,6 +26,7 @@ import com.datastax.driver.mapping.Result; |
26 | 26 | import com.google.common.base.Function; |
27 | 27 | import com.google.common.util.concurrent.Futures; |
28 | 28 | import com.google.common.util.concurrent.ListenableFuture; |
29 | +import com.google.common.util.concurrent.MoreExecutors; | |
29 | 30 | import lombok.extern.slf4j.Slf4j; |
30 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
31 | 32 | import org.thingsboard.server.dao.Dao; |
... | ... | @@ -86,7 +87,7 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte |
86 | 87 | return Collections.emptyList(); |
87 | 88 | } |
88 | 89 | } |
89 | - }); | |
90 | + }, MoreExecutors.directExecutor()); | |
90 | 91 | } |
91 | 92 | return Futures.immediateFuture(Collections.emptyList()); |
92 | 93 | } |
... | ... | @@ -120,7 +121,7 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte |
120 | 121 | return null; |
121 | 122 | } |
122 | 123 | } |
123 | - }); | |
124 | + }, MoreExecutors.directExecutor()); | |
124 | 125 | } |
125 | 126 | return Futures.immediateFuture(null); |
126 | 127 | } |
... | ... | @@ -191,5 +192,5 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte |
191 | 192 | List<E> entities = findListByStatement(tenantId, QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel())); |
192 | 193 | return DaoUtil.convertDataList(entities); |
193 | 194 | } |
194 | - | |
195 | + | |
195 | 196 | } | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import com.datastax.driver.core.Statement; |
22 | 22 | import com.google.common.util.concurrent.FutureCallback; |
23 | 23 | import com.google.common.util.concurrent.Futures; |
24 | 24 | import com.google.common.util.concurrent.ListenableFuture; |
25 | +import com.google.common.util.concurrent.MoreExecutors; | |
25 | 26 | import com.google.common.util.concurrent.Uninterruptibles; |
26 | 27 | import org.thingsboard.server.dao.exception.BufferLimitException; |
27 | 28 | import org.thingsboard.server.dao.util.AsyncRateLimiter; |
... | ... | @@ -44,9 +45,9 @@ public class RateLimitedResultSetFuture implements ResultSetFuture { |
44 | 45 | rateLimiter.release(); |
45 | 46 | } |
46 | 47 | return Futures.immediateFailedFuture(t); |
47 | - }); | |
48 | + }, MoreExecutors.directExecutor()); | |
48 | 49 | this.originalFuture = Futures.transform(rateLimitFuture, |
49 | - i -> executeAsyncWithRelease(rateLimiter, session, statement)); | |
50 | + i -> executeAsyncWithRelease(rateLimiter, session, statement), MoreExecutors.directExecutor()); | |
50 | 51 | |
51 | 52 | } |
52 | 53 | |
... | ... | @@ -145,7 +146,7 @@ public class RateLimitedResultSetFuture implements ResultSetFuture { |
145 | 146 | public void onFailure(Throwable t) { |
146 | 147 | rateLimiter.release(); |
147 | 148 | } |
148 | - }); | |
149 | + }, MoreExecutors.directExecutor()); | |
149 | 150 | return resultSetFuture; |
150 | 151 | } catch (RuntimeException re) { |
151 | 152 | rateLimiter.release(); | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sql.alarm; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.Futures; |
19 | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | +import com.google.common.util.concurrent.MoreExecutors; | |
20 | 21 | import lombok.extern.slf4j.Slf4j; |
21 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 23 | import org.springframework.data.domain.PageRequest; |
... | ... | @@ -108,9 +109,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A |
108 | 109 | for (EntityRelation relation : input) { |
109 | 110 | alarmFutures.add(Futures.transform( |
110 | 111 | findAlarmByIdAsync(tenantId, relation.getTo().getId()), |
111 | - AlarmInfo::new)); | |
112 | + AlarmInfo::new, MoreExecutors.directExecutor())); | |
112 | 113 | } |
113 | 114 | return Futures.successfulAsList(alarmFutures); |
114 | - }); | |
115 | + }, MoreExecutors.directExecutor()); | |
115 | 116 | } |
116 | 117 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sql.dashboard; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.Futures; |
19 | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | +import com.google.common.util.concurrent.MoreExecutors; | |
20 | 21 | import lombok.extern.slf4j.Slf4j; |
21 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 23 | import org.springframework.data.domain.PageRequest; |
... | ... | @@ -91,6 +92,6 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE |
91 | 92 | dashboardFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); |
92 | 93 | } |
93 | 94 | return Futures.successfulAsList(dashboardFutures); |
94 | - }); | |
95 | + }, MoreExecutors.directExecutor()); | |
95 | 96 | } |
96 | 97 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sqlts; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.Futures; |
19 | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | +import com.google.common.util.concurrent.MoreExecutors; | |
20 | 21 | import com.google.common.util.concurrent.SettableFuture; |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -95,7 +96,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
95 | 96 | |
96 | 97 | @Override |
97 | 98 | public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { |
98 | - return getRemoveLatestFuture(tenantId, entityId, query); | |
99 | + return getRemoveLatestFuture(entityId, query); | |
99 | 100 | } |
100 | 101 | |
101 | 102 | @Override |
... | ... | @@ -124,9 +125,9 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
124 | 125 | } |
125 | 126 | |
126 | 127 | @Override |
127 | - protected ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) { | |
128 | + protected ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query) { | |
128 | 129 | if (query.getAggregation() == Aggregation.NONE) { |
129 | - return findAllAsyncWithLimit(tenantId, entityId, query); | |
130 | + return findAllAsyncWithLimit(entityId, query); | |
130 | 131 | } else { |
131 | 132 | long stepTs = query.getStartTs(); |
132 | 133 | List<ListenableFuture<Optional<TsKvEntry>>> futures = new ArrayList<>(); |
... | ... | @@ -134,7 +135,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
134 | 135 | long startTs = stepTs; |
135 | 136 | long endTs = stepTs + query.getInterval(); |
136 | 137 | long ts = startTs + (endTs - startTs) / 2; |
137 | - futures.add(findAndAggregateAsync(tenantId, entityId, query.getKey(), startTs, endTs, ts, query.getAggregation())); | |
138 | + futures.add(findAndAggregateAsync(entityId, query.getKey(), startTs, endTs, ts, query.getAggregation())); | |
138 | 139 | stepTs = endTs; |
139 | 140 | } |
140 | 141 | return getTskvEntriesFuture(Futures.allAsList(futures)); |
... | ... | @@ -142,7 +143,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
142 | 143 | } |
143 | 144 | |
144 | 145 | @Override |
145 | - protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) { | |
146 | + protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) { | |
146 | 147 | Integer keyId = getOrSaveKeyId(query.getKey()); |
147 | 148 | List<TsKvEntity> tsKvEntities = tsKvRepository.findAllWithLimit( |
148 | 149 | entityId.getId(), |
... | ... | @@ -156,9 +157,9 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
156 | 157 | return Futures.immediateFuture(DaoUtil.convertDataList(tsKvEntities)); |
157 | 158 | } |
158 | 159 | |
159 | - protected ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, long ts, Aggregation aggregation) { | |
160 | + private ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(EntityId entityId, String key, long startTs, long endTs, long ts, Aggregation aggregation) { | |
160 | 161 | List<CompletableFuture<TsKvEntity>> entitiesFutures = new ArrayList<>(); |
161 | - switchAggregation(tenantId, entityId, key, startTs, endTs, aggregation, entitiesFutures); | |
162 | + switchAggregation(entityId, key, startTs, endTs, aggregation, entitiesFutures); | |
162 | 163 | return Futures.transform(setFutures(entitiesFutures), entity -> { |
163 | 164 | if (entity != null && entity.isNotEmpty()) { |
164 | 165 | entity.setEntityId(entityId.getId()); |
... | ... | @@ -168,32 +169,32 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
168 | 169 | } else { |
169 | 170 | return Optional.empty(); |
170 | 171 | } |
171 | - }); | |
172 | + }, MoreExecutors.directExecutor()); | |
172 | 173 | } |
173 | 174 | |
174 | - protected void switchAggregation(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, Aggregation aggregation, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
175 | + protected void switchAggregation(EntityId entityId, String key, long startTs, long endTs, Aggregation aggregation, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
175 | 176 | switch (aggregation) { |
176 | 177 | case AVG: |
177 | - findAvg(tenantId, entityId, key, startTs, endTs, entitiesFutures); | |
178 | + findAvg(entityId, key, startTs, endTs, entitiesFutures); | |
178 | 179 | break; |
179 | 180 | case MAX: |
180 | - findMax(tenantId, entityId, key, startTs, endTs, entitiesFutures); | |
181 | + findMax(entityId, key, startTs, endTs, entitiesFutures); | |
181 | 182 | break; |
182 | 183 | case MIN: |
183 | - findMin(tenantId, entityId, key, startTs, endTs, entitiesFutures); | |
184 | + findMin(entityId, key, startTs, endTs, entitiesFutures); | |
184 | 185 | break; |
185 | 186 | case SUM: |
186 | - findSum(tenantId, entityId, key, startTs, endTs, entitiesFutures); | |
187 | + findSum(entityId, key, startTs, endTs, entitiesFutures); | |
187 | 188 | break; |
188 | 189 | case COUNT: |
189 | - findCount(tenantId, entityId, key, startTs, endTs, entitiesFutures); | |
190 | + findCount(entityId, key, startTs, endTs, entitiesFutures); | |
190 | 191 | break; |
191 | 192 | default: |
192 | 193 | throw new IllegalArgumentException("Not supported aggregation type: " + aggregation); |
193 | 194 | } |
194 | 195 | } |
195 | 196 | |
196 | - protected void findCount(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
197 | + protected void findCount(EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
197 | 198 | Integer keyId = getOrSaveKeyId(key); |
198 | 199 | entitiesFutures.add(tsKvRepository.findCount( |
199 | 200 | entityId.getId(), |
... | ... | @@ -202,7 +203,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
202 | 203 | endTs)); |
203 | 204 | } |
204 | 205 | |
205 | - protected void findSum(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
206 | + protected void findSum(EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
206 | 207 | Integer keyId = getOrSaveKeyId(key); |
207 | 208 | entitiesFutures.add(tsKvRepository.findSum( |
208 | 209 | entityId.getId(), |
... | ... | @@ -211,7 +212,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
211 | 212 | endTs)); |
212 | 213 | } |
213 | 214 | |
214 | - protected void findMin(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
215 | + protected void findMin(EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
215 | 216 | Integer keyId = getOrSaveKeyId(key); |
216 | 217 | entitiesFutures.add(tsKvRepository.findStringMin( |
217 | 218 | entityId.getId(), |
... | ... | @@ -225,7 +226,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
225 | 226 | endTs)); |
226 | 227 | } |
227 | 228 | |
228 | - protected void findMax(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
229 | + protected void findMax(EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
229 | 230 | Integer keyId = getOrSaveKeyId(key); |
230 | 231 | entitiesFutures.add(tsKvRepository.findStringMax( |
231 | 232 | entityId.getId(), |
... | ... | @@ -239,7 +240,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq |
239 | 240 | endTs)); |
240 | 241 | } |
241 | 242 | |
242 | - protected void findAvg(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
243 | + protected void findAvg(EntityId entityId, String key, long startTs, long endTs, List<CompletableFuture<TsKvEntity>> entitiesFutures) { | |
243 | 244 | Integer keyId = getOrSaveKeyId(key); |
244 | 245 | entitiesFutures.add(tsKvRepository.findAvg( |
245 | 246 | entityId.getId(), | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.google.common.collect.Lists; |
20 | 20 | import com.google.common.util.concurrent.FutureCallback; |
21 | 21 | import com.google.common.util.concurrent.Futures; |
22 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | +import com.google.common.util.concurrent.MoreExecutors; | |
23 | 24 | import lombok.extern.slf4j.Slf4j; |
24 | 25 | import org.hibernate.exception.ConstraintViolationException; |
25 | 26 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -126,7 +127,7 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
126 | 127 | protected ListenableFuture<List<TsKvEntry>> processFindAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) { |
127 | 128 | List<ListenableFuture<List<TsKvEntry>>> futures = queries |
128 | 129 | .stream() |
129 | - .map(query -> findAllAsync(tenantId, entityId, query)) | |
130 | + .map(query -> findAllAsync(entityId, query)) | |
130 | 131 | .collect(Collectors.toList()); |
131 | 132 | return Futures.transform(Futures.allAsList(futures), new Function<List<List<TsKvEntry>>, List<TsKvEntry>>() { |
132 | 133 | @Nullable |
... | ... | @@ -143,9 +144,9 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
143 | 144 | }, service); |
144 | 145 | } |
145 | 146 | |
146 | - protected abstract ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query); | |
147 | + protected abstract ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query); | |
147 | 148 | |
148 | - protected abstract ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(TenantId tenantId, EntityId entityId, ReadTsKvQuery query); | |
149 | + protected abstract ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query); | |
149 | 150 | |
150 | 151 | protected ListenableFuture<List<TsKvEntry>> getTskvEntriesFuture(ListenableFuture<List<Optional<TsKvEntry>>> future) { |
151 | 152 | return Futures.transform(future, new Function<List<Optional<TsKvEntry>>, List<TsKvEntry>>() { |
... | ... | @@ -163,12 +164,12 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
163 | 164 | }, service); |
164 | 165 | } |
165 | 166 | |
166 | - protected ListenableFuture<List<TsKvEntry>> findNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { | |
167 | + protected ListenableFuture<List<TsKvEntry>> findNewLatestEntryFuture(EntityId entityId, DeleteTsKvQuery query) { | |
167 | 168 | long startTs = 0; |
168 | 169 | long endTs = query.getStartTs() - 1; |
169 | 170 | ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1, |
170 | 171 | Aggregation.NONE, DESC_ORDER); |
171 | - return findAllAsync(tenantId, entityId, findNewLatestQuery); | |
172 | + return findAllAsync(entityId, findNewLatestQuery); | |
172 | 173 | } |
173 | 174 | |
174 | 175 | protected ListenableFuture<TsKvEntry> getFindLatestFuture(EntityId entityId, String key) { |
... | ... | @@ -188,7 +189,7 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
188 | 189 | return Futures.immediateFuture(result); |
189 | 190 | } |
190 | 191 | |
191 | - protected ListenableFuture<Void> getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { | |
192 | + protected ListenableFuture<Void> getRemoveLatestFuture(EntityId entityId, DeleteTsKvQuery query) { | |
192 | 193 | ListenableFuture<TsKvEntry> latestFuture = getFindLatestFuture(entityId, query.getKey()); |
193 | 194 | |
194 | 195 | ListenableFuture<Boolean> booleanFuture = Futures.transform(latestFuture, tsKvEntry -> { |
... | ... | @@ -216,7 +217,7 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
216 | 217 | if (query.getRewriteLatestIfDeleted()) { |
217 | 218 | ListenableFuture<Void> savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { |
218 | 219 | if (isRemove) { |
219 | - return getNewLatestEntryFuture(tenantId, entityId, query); | |
220 | + return getNewLatestEntryFuture(entityId, query); | |
220 | 221 | } |
221 | 222 | return Futures.immediateFuture(null); |
222 | 223 | }, service); |
... | ... | @@ -235,7 +236,7 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
235 | 236 | public void onFailure(Throwable t) { |
236 | 237 | log.warn("[{}] Failed to process remove of the latest value", entityId, t); |
237 | 238 | } |
238 | - }); | |
239 | + }, MoreExecutors.directExecutor()); | |
239 | 240 | return resultFuture; |
240 | 241 | } |
241 | 242 | |
... | ... | @@ -295,8 +296,8 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx |
295 | 296 | return keyId; |
296 | 297 | } |
297 | 298 | |
298 | - private ListenableFuture<Void> getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { | |
299 | - ListenableFuture<List<TsKvEntry>> future = findNewLatestEntryFuture(tenantId, entityId, query); | |
299 | + private ListenableFuture<Void> getNewLatestEntryFuture(EntityId entityId, DeleteTsKvQuery query) { | |
300 | + ListenableFuture<List<TsKvEntry>> future = findNewLatestEntryFuture(entityId, query); | |
300 | 301 | return Futures.transformAsync(future, entryList -> { |
301 | 302 | if (entryList.size() == 1) { |
302 | 303 | return getSaveLatestFuture(entityId, entryList.get(0)); | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/timescale/TimescaleInsertTsRepository.java
... | ... | @@ -37,8 +37,8 @@ import java.util.List; |
37 | 37 | public class TimescaleInsertTsRepository extends AbstractInsertRepository implements InsertTsRepository<TimescaleTsKvEntity> { |
38 | 38 | |
39 | 39 | private static final String INSERT_OR_UPDATE = |
40 | - "INSERT INTO tenant_ts_kv (tenant_id, entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?, cast(? AS json)) " + | |
41 | - "ON CONFLICT (tenant_id, entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json);"; | |
40 | + "INSERT INTO ts_kv (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) VALUES(?, ?, ?, ?, ?, ?, ?, cast(? AS json)) " + | |
41 | + "ON CONFLICT (entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json);"; | |
42 | 42 | |
43 | 43 | @Override |
44 | 44 | public void saveOrUpdate(List<EntityContainer<TimescaleTsKvEntity>> entities) { |
... | ... | @@ -46,41 +46,40 @@ public class TimescaleInsertTsRepository extends AbstractInsertRepository implem |
46 | 46 | @Override |
47 | 47 | public void setValues(PreparedStatement ps, int i) throws SQLException { |
48 | 48 | TimescaleTsKvEntity tsKvEntity = entities.get(i).getEntity(); |
49 | - ps.setObject(1, tsKvEntity.getTenantId()); | |
50 | - ps.setObject(2, tsKvEntity.getEntityId()); | |
51 | - ps.setInt(3, tsKvEntity.getKey()); | |
52 | - ps.setLong(4, tsKvEntity.getTs()); | |
49 | + ps.setObject(1, tsKvEntity.getEntityId()); | |
50 | + ps.setInt(2, tsKvEntity.getKey()); | |
51 | + ps.setLong(3, tsKvEntity.getTs()); | |
53 | 52 | |
54 | 53 | if (tsKvEntity.getBooleanValue() != null) { |
55 | - ps.setBoolean(5, tsKvEntity.getBooleanValue()); | |
56 | - ps.setBoolean(10, tsKvEntity.getBooleanValue()); | |
54 | + ps.setBoolean(4, tsKvEntity.getBooleanValue()); | |
55 | + ps.setBoolean(9, tsKvEntity.getBooleanValue()); | |
57 | 56 | } else { |
58 | - ps.setNull(5, Types.BOOLEAN); | |
59 | - ps.setNull(10, Types.BOOLEAN); | |
57 | + ps.setNull(4, Types.BOOLEAN); | |
58 | + ps.setNull(9, Types.BOOLEAN); | |
60 | 59 | } |
61 | 60 | |
62 | - ps.setString(6, replaceNullChars(tsKvEntity.getStrValue())); | |
63 | - ps.setString(11, replaceNullChars(tsKvEntity.getStrValue())); | |
61 | + ps.setString(5, replaceNullChars(tsKvEntity.getStrValue())); | |
62 | + ps.setString(10, replaceNullChars(tsKvEntity.getStrValue())); | |
64 | 63 | |
65 | 64 | |
66 | 65 | if (tsKvEntity.getLongValue() != null) { |
67 | - ps.setLong(7, tsKvEntity.getLongValue()); | |
68 | - ps.setLong(12, tsKvEntity.getLongValue()); | |
66 | + ps.setLong(6, tsKvEntity.getLongValue()); | |
67 | + ps.setLong(11, tsKvEntity.getLongValue()); | |
69 | 68 | } else { |
70 | - ps.setNull(7, Types.BIGINT); | |
71 | - ps.setNull(12, Types.BIGINT); | |
69 | + ps.setNull(6, Types.BIGINT); | |
70 | + ps.setNull(11, Types.BIGINT); | |
72 | 71 | } |
73 | 72 | |
74 | 73 | if (tsKvEntity.getDoubleValue() != null) { |
75 | - ps.setDouble(8, tsKvEntity.getDoubleValue()); | |
76 | - ps.setDouble(13, tsKvEntity.getDoubleValue()); | |
74 | + ps.setDouble(7, tsKvEntity.getDoubleValue()); | |
75 | + ps.setDouble(12, tsKvEntity.getDoubleValue()); | |
77 | 76 | } else { |
78 | - ps.setNull(8, Types.DOUBLE); | |
79 | - ps.setNull(13, Types.DOUBLE); | |
77 | + ps.setNull(7, Types.DOUBLE); | |
78 | + ps.setNull(12, Types.DOUBLE); | |
80 | 79 | } |
81 | 80 | |
82 | - ps.setString(9, replaceNullChars(tsKvEntity.getJsonValue())); | |
83 | - ps.setString(14, replaceNullChars(tsKvEntity.getJsonValue())); | |
81 | + ps.setString(8, replaceNullChars(tsKvEntity.getJsonValue())); | |
82 | + ps.setString(13, replaceNullChars(tsKvEntity.getJsonValue())); | |
84 | 83 | } |
85 | 84 | |
86 | 85 | @Override | ... | ... |
... | ... | @@ -36,7 +36,7 @@ public class AggregationRepository { |
36 | 36 | public static final String FIND_SUM = "findSum"; |
37 | 37 | public static final String FIND_COUNT = "findCount"; |
38 | 38 | |
39 | - public static final String FROM_WHERE_CLAUSE = "FROM tenant_ts_kv tskv WHERE tskv.tenant_id = cast(:tenantId AS uuid) AND tskv.entity_id = cast(:entityId AS uuid) AND tskv.key= cast(:entityKey AS int) AND tskv.ts > :startTs AND tskv.ts <= :endTs GROUP BY tskv.tenant_id, tskv.entity_id, tskv.key, tsBucket ORDER BY tskv.tenant_id, tskv.entity_id, tskv.key, tsBucket"; | |
39 | + public static final String FROM_WHERE_CLAUSE = "FROM ts_kv tskv WHERE tskv.entity_id = cast(:entityId AS uuid) AND tskv.key= cast(:entityKey AS int) AND tskv.ts > :startTs AND tskv.ts <= :endTs GROUP BY tskv.entity_id, tskv.key, tsBucket ORDER BY tskv.entity_id, tskv.key, tsBucket"; | |
40 | 40 | |
41 | 41 | public static final String FIND_AVG_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, 'AVG' AS aggType "; |
42 | 42 | |
... | ... | @@ -52,43 +52,42 @@ public class AggregationRepository { |
52 | 52 | private EntityManager entityManager; |
53 | 53 | |
54 | 54 | @Async |
55 | - public CompletableFuture<List<TimescaleTsKvEntity>> findAvg(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
55 | + public CompletableFuture<List<TimescaleTsKvEntity>> findAvg(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
56 | 56 | @SuppressWarnings("unchecked") |
57 | - List<TimescaleTsKvEntity> resultList = getResultList(tenantId, entityId, entityKey, timeBucket, startTs, endTs, FIND_AVG); | |
57 | + List<TimescaleTsKvEntity> resultList = getResultList(entityId, entityKey, timeBucket, startTs, endTs, FIND_AVG); | |
58 | 58 | return CompletableFuture.supplyAsync(() -> resultList); |
59 | 59 | } |
60 | 60 | |
61 | 61 | @Async |
62 | - public CompletableFuture<List<TimescaleTsKvEntity>> findMax(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
62 | + public CompletableFuture<List<TimescaleTsKvEntity>> findMax(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
63 | 63 | @SuppressWarnings("unchecked") |
64 | - List<TimescaleTsKvEntity> resultList = getResultList(tenantId, entityId, entityKey, timeBucket, startTs, endTs, FIND_MAX); | |
64 | + List<TimescaleTsKvEntity> resultList = getResultList(entityId, entityKey, timeBucket, startTs, endTs, FIND_MAX); | |
65 | 65 | return CompletableFuture.supplyAsync(() -> resultList); |
66 | 66 | } |
67 | 67 | |
68 | 68 | @Async |
69 | - public CompletableFuture<List<TimescaleTsKvEntity>> findMin(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
69 | + public CompletableFuture<List<TimescaleTsKvEntity>> findMin(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
70 | 70 | @SuppressWarnings("unchecked") |
71 | - List<TimescaleTsKvEntity> resultList = getResultList(tenantId, entityId, entityKey, timeBucket, startTs, endTs, FIND_MIN); | |
71 | + List<TimescaleTsKvEntity> resultList = getResultList(entityId, entityKey, timeBucket, startTs, endTs, FIND_MIN); | |
72 | 72 | return CompletableFuture.supplyAsync(() -> resultList); |
73 | 73 | } |
74 | 74 | |
75 | 75 | @Async |
76 | - public CompletableFuture<List<TimescaleTsKvEntity>> findSum(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
76 | + public CompletableFuture<List<TimescaleTsKvEntity>> findSum(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
77 | 77 | @SuppressWarnings("unchecked") |
78 | - List<TimescaleTsKvEntity> resultList = getResultList(tenantId, entityId, entityKey, timeBucket, startTs, endTs, FIND_SUM); | |
78 | + List<TimescaleTsKvEntity> resultList = getResultList(entityId, entityKey, timeBucket, startTs, endTs, FIND_SUM); | |
79 | 79 | return CompletableFuture.supplyAsync(() -> resultList); |
80 | 80 | } |
81 | 81 | |
82 | 82 | @Async |
83 | - public CompletableFuture<List<TimescaleTsKvEntity>> findCount(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
83 | + public CompletableFuture<List<TimescaleTsKvEntity>> findCount(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs) { | |
84 | 84 | @SuppressWarnings("unchecked") |
85 | - List<TimescaleTsKvEntity> resultList = getResultList(tenantId, entityId, entityKey, timeBucket, startTs, endTs, FIND_COUNT); | |
85 | + List<TimescaleTsKvEntity> resultList = getResultList(entityId, entityKey, timeBucket, startTs, endTs, FIND_COUNT); | |
86 | 86 | return CompletableFuture.supplyAsync(() -> resultList); |
87 | 87 | } |
88 | 88 | |
89 | - private List getResultList(UUID tenantId, UUID entityId, int entityKey, long timeBucket, long startTs, long endTs, String query) { | |
89 | + private List getResultList(UUID entityId, int entityKey, long timeBucket, long startTs, long endTs, String query) { | |
90 | 90 | return entityManager.createNamedQuery(query) |
91 | - .setParameter("tenantId", tenantId) | |
92 | 91 | .setParameter("entityId", entityId) |
93 | 92 | .setParameter("entityKey", entityKey) |
94 | 93 | .setParameter("timeBucket", timeBucket) | ... | ... |
... | ... | @@ -88,24 +88,23 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
88 | 88 | } |
89 | 89 | |
90 | 90 | @Override |
91 | - protected ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) { | |
91 | + protected ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query) { | |
92 | 92 | if (query.getAggregation() == Aggregation.NONE) { |
93 | - return findAllAsyncWithLimit(tenantId, entityId, query); | |
93 | + return findAllAsyncWithLimit(entityId, query); | |
94 | 94 | } else { |
95 | 95 | long startTs = query.getStartTs(); |
96 | 96 | long endTs = query.getEndTs(); |
97 | 97 | long timeBucket = query.getInterval(); |
98 | - ListenableFuture<List<Optional<TsKvEntry>>> future = findAllAndAggregateAsync(tenantId, entityId, query.getKey(), startTs, endTs, timeBucket, query.getAggregation()); | |
98 | + ListenableFuture<List<Optional<TsKvEntry>>> future = findAllAndAggregateAsync(entityId, query.getKey(), startTs, endTs, timeBucket, query.getAggregation()); | |
99 | 99 | return getTskvEntriesFuture(future); |
100 | 100 | } |
101 | 101 | } |
102 | 102 | |
103 | 103 | @Override |
104 | - protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) { | |
104 | + protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) { | |
105 | 105 | String strKey = query.getKey(); |
106 | 106 | Integer keyId = getOrSaveKeyId(strKey); |
107 | 107 | List<TimescaleTsKvEntity> timescaleTsKvEntities = tsKvRepository.findAllWithLimit( |
108 | - tenantId.getId(), | |
109 | 108 | entityId.getId(), |
110 | 109 | keyId, |
111 | 110 | query.getStartTs(), |
... | ... | @@ -117,8 +116,8 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
117 | 116 | return Futures.immediateFuture(DaoUtil.convertDataList(timescaleTsKvEntities)); |
118 | 117 | } |
119 | 118 | |
120 | - private ListenableFuture<List<Optional<TsKvEntry>>> findAllAndAggregateAsync(TenantId tenantId, EntityId entityId, String key, long startTs, long endTs, long timeBucket, Aggregation aggregation) { | |
121 | - CompletableFuture<List<TimescaleTsKvEntity>> listCompletableFuture = switchAggregation(key, startTs, endTs, timeBucket, aggregation, entityId.getId(), tenantId.getId()); | |
119 | + private ListenableFuture<List<Optional<TsKvEntry>>> findAllAndAggregateAsync(EntityId entityId, String key, long startTs, long endTs, long timeBucket, Aggregation aggregation) { | |
120 | + CompletableFuture<List<TimescaleTsKvEntity>> listCompletableFuture = switchAggregation(key, startTs, endTs, timeBucket, aggregation, entityId.getId()); | |
122 | 121 | SettableFuture<List<TimescaleTsKvEntity>> listenableFuture = SettableFuture.create(); |
123 | 122 | listCompletableFuture.whenComplete((timescaleTsKvEntities, throwable) -> { |
124 | 123 | if (throwable != null) { |
... | ... | @@ -133,7 +132,6 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
133 | 132 | timescaleTsKvEntities.forEach(entity -> { |
134 | 133 | if (entity != null && entity.isNotEmpty()) { |
135 | 134 | entity.setEntityId(entityId.getId()); |
136 | - entity.setTenantId(tenantId.getId()); | |
137 | 135 | entity.setStrKey(key); |
138 | 136 | result.add(Optional.of(DaoUtil.getData(entity))); |
139 | 137 | } else { |
... | ... | @@ -167,7 +165,6 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
167 | 165 | String strKey = tsKvEntry.getKey(); |
168 | 166 | Integer keyId = getOrSaveKeyId(strKey); |
169 | 167 | TimescaleTsKvEntity entity = new TimescaleTsKvEntity(); |
170 | - entity.setTenantId(tenantId.getId()); | |
171 | 168 | entity.setEntityId(entityId.getId()); |
172 | 169 | entity.setTs(tsKvEntry.getTs()); |
173 | 170 | entity.setKey(keyId); |
... | ... | @@ -197,7 +194,6 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
197 | 194 | Integer keyId = getOrSaveKeyId(strKey); |
198 | 195 | return service.submit(() -> { |
199 | 196 | tsKvRepository.delete( |
200 | - tenantId.getId(), | |
201 | 197 | entityId.getId(), |
202 | 198 | keyId, |
203 | 199 | query.getStartTs(), |
... | ... | @@ -208,7 +204,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
208 | 204 | |
209 | 205 | @Override |
210 | 206 | public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { |
211 | - return getRemoveLatestFuture(tenantId, entityId, query); | |
207 | + return getRemoveLatestFuture(entityId, query); | |
212 | 208 | } |
213 | 209 | |
214 | 210 | @Override |
... | ... | @@ -216,27 +212,26 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
216 | 212 | return service.submit(() -> null); |
217 | 213 | } |
218 | 214 | |
219 | - private CompletableFuture<List<TimescaleTsKvEntity>> switchAggregation(String key, long startTs, long endTs, long timeBucket, Aggregation aggregation, UUID entityId, UUID tenantId) { | |
215 | + private CompletableFuture<List<TimescaleTsKvEntity>> switchAggregation(String key, long startTs, long endTs, long timeBucket, Aggregation aggregation, UUID entityId) { | |
220 | 216 | switch (aggregation) { |
221 | 217 | case AVG: |
222 | - return findAvg(key, startTs, endTs, timeBucket, entityId, tenantId); | |
218 | + return findAvg(key, startTs, endTs, timeBucket, entityId); | |
223 | 219 | case MAX: |
224 | - return findMax(key, startTs, endTs, timeBucket, entityId, tenantId); | |
220 | + return findMax(key, startTs, endTs, timeBucket, entityId); | |
225 | 221 | case MIN: |
226 | - return findMin(key, startTs, endTs, timeBucket, entityId, tenantId); | |
222 | + return findMin(key, startTs, endTs, timeBucket, entityId); | |
227 | 223 | case SUM: |
228 | - return findSum(key, startTs, endTs, timeBucket, entityId, tenantId); | |
224 | + return findSum(key, startTs, endTs, timeBucket, entityId); | |
229 | 225 | case COUNT: |
230 | - return findCount(key, startTs, endTs, timeBucket, entityId, tenantId); | |
226 | + return findCount(key, startTs, endTs, timeBucket, entityId); | |
231 | 227 | default: |
232 | 228 | throw new IllegalArgumentException("Not supported aggregation type: " + aggregation); |
233 | 229 | } |
234 | 230 | } |
235 | 231 | |
236 | - private CompletableFuture<List<TimescaleTsKvEntity>> findCount(String key, long startTs, long endTs, long timeBucket, UUID entityId, UUID tenantId) { | |
232 | + private CompletableFuture<List<TimescaleTsKvEntity>> findCount(String key, long startTs, long endTs, long timeBucket, UUID entityId) { | |
237 | 233 | Integer keyId = getOrSaveKeyId(key); |
238 | 234 | return aggregationRepository.findCount( |
239 | - tenantId, | |
240 | 235 | entityId, |
241 | 236 | keyId, |
242 | 237 | timeBucket, |
... | ... | @@ -244,10 +239,9 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
244 | 239 | endTs); |
245 | 240 | } |
246 | 241 | |
247 | - private CompletableFuture<List<TimescaleTsKvEntity>> findSum(String key, long startTs, long endTs, long timeBucket, UUID entityId, UUID tenantId) { | |
242 | + private CompletableFuture<List<TimescaleTsKvEntity>> findSum(String key, long startTs, long endTs, long timeBucket, UUID entityId) { | |
248 | 243 | Integer keyId = getOrSaveKeyId(key); |
249 | 244 | return aggregationRepository.findSum( |
250 | - tenantId, | |
251 | 245 | entityId, |
252 | 246 | keyId, |
253 | 247 | timeBucket, |
... | ... | @@ -255,10 +249,9 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
255 | 249 | endTs); |
256 | 250 | } |
257 | 251 | |
258 | - private CompletableFuture<List<TimescaleTsKvEntity>> findMin(String key, long startTs, long endTs, long timeBucket, UUID entityId, UUID tenantId) { | |
252 | + private CompletableFuture<List<TimescaleTsKvEntity>> findMin(String key, long startTs, long endTs, long timeBucket, UUID entityId) { | |
259 | 253 | Integer keyId = getOrSaveKeyId(key); |
260 | 254 | return aggregationRepository.findMin( |
261 | - tenantId, | |
262 | 255 | entityId, |
263 | 256 | keyId, |
264 | 257 | timeBucket, |
... | ... | @@ -266,10 +259,9 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
266 | 259 | endTs); |
267 | 260 | } |
268 | 261 | |
269 | - private CompletableFuture<List<TimescaleTsKvEntity>> findMax(String key, long startTs, long endTs, long timeBucket, UUID entityId, UUID tenantId) { | |
262 | + private CompletableFuture<List<TimescaleTsKvEntity>> findMax(String key, long startTs, long endTs, long timeBucket, UUID entityId) { | |
270 | 263 | Integer keyId = getOrSaveKeyId(key); |
271 | 264 | return aggregationRepository.findMax( |
272 | - tenantId, | |
273 | 265 | entityId, |
274 | 266 | keyId, |
275 | 267 | timeBucket, |
... | ... | @@ -277,10 +269,9 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements |
277 | 269 | endTs); |
278 | 270 | } |
279 | 271 | |
280 | - private CompletableFuture<List<TimescaleTsKvEntity>> findAvg(String key, long startTs, long endTs, long timeBucket, UUID entityId, UUID tenantId) { | |
272 | + private CompletableFuture<List<TimescaleTsKvEntity>> findAvg(String key, long startTs, long endTs, long timeBucket, UUID entityId) { | |
281 | 273 | Integer keyId = getOrSaveKeyId(key); |
282 | 274 | return aggregationRepository.findAvg( |
283 | - tenantId, | |
284 | 275 | entityId, |
285 | 276 | keyId, |
286 | 277 | timeBucket, | ... | ... |
... | ... | @@ -31,12 +31,10 @@ import java.util.UUID; |
31 | 31 | @TimescaleDBTsDao |
32 | 32 | public interface TsKvTimescaleRepository extends CrudRepository<TimescaleTsKvEntity, TimescaleTsKvCompositeKey> { |
33 | 33 | |
34 | - @Query("SELECT tskv FROM TimescaleTsKvEntity tskv WHERE tskv.tenantId = :tenantId " + | |
35 | - "AND tskv.entityId = :entityId " + | |
34 | + @Query("SELECT tskv FROM TimescaleTsKvEntity tskv WHERE tskv.entityId = :entityId " + | |
36 | 35 | "AND tskv.key = :entityKey " + |
37 | 36 | "AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
38 | 37 | List<TimescaleTsKvEntity> findAllWithLimit( |
39 | - @Param("tenantId") UUID tenantId, | |
40 | 38 | @Param("entityId") UUID entityId, |
41 | 39 | @Param("entityKey") int key, |
42 | 40 | @Param("startTs") long startTs, |
... | ... | @@ -44,12 +42,10 @@ public interface TsKvTimescaleRepository extends CrudRepository<TimescaleTsKvEnt |
44 | 42 | |
45 | 43 | @Transactional |
46 | 44 | @Modifying |
47 | - @Query("DELETE FROM TimescaleTsKvEntity tskv WHERE tskv.tenantId = :tenantId " + | |
48 | - "AND tskv.entityId = :entityId " + | |
45 | + @Query("DELETE FROM TimescaleTsKvEntity tskv WHERE tskv.entityId = :entityId " + | |
49 | 46 | "AND tskv.key = :entityKey " + |
50 | 47 | "AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
51 | - void delete(@Param("tenantId") UUID tenantId, | |
52 | - @Param("entityId") UUID entityId, | |
48 | + void delete(@Param("entityId") UUID entityId, | |
53 | 49 | @Param("entityKey") int key, |
54 | 50 | @Param("startTs") long startTs, |
55 | 51 | @Param("endTs") long endTs); | ... | ... |
dao/src/main/resources/sql/schema-timescale-idx.sql
deleted
100644 → 0
1 | --- | |
2 | --- Copyright © 2016-2020 The Thingsboard Authors | |
3 | --- | |
4 | --- Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | --- you may not use this file except in compliance with the License. | |
6 | --- You may obtain a copy of the License at | |
7 | --- | |
8 | --- http://www.apache.org/licenses/LICENSE-2.0 | |
9 | --- | |
10 | --- Unless required by applicable law or agreed to in writing, software | |
11 | --- distributed under the License is distributed on an "AS IS" BASIS, | |
12 | --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | --- See the License for the specific language governing permissions and | |
14 | --- limitations under the License. | |
15 | --- | |
16 | - | |
17 | -CREATE INDEX IF NOT EXISTS idx_tenant_ts_kv ON tenant_ts_kv(tenant_id, entity_id, key, ts); | |
\ No newline at end of file |
... | ... | @@ -16,8 +16,7 @@ |
16 | 16 | |
17 | 17 | CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; |
18 | 18 | |
19 | -CREATE TABLE IF NOT EXISTS tenant_ts_kv ( | |
20 | - tenant_id uuid NOT NULL, | |
19 | +CREATE TABLE IF NOT EXISTS ts_kv ( | |
21 | 20 | entity_id uuid NOT NULL, |
22 | 21 | key int NOT NULL, |
23 | 22 | ts bigint NOT NULL, |
... | ... | @@ -26,7 +25,7 @@ CREATE TABLE IF NOT EXISTS tenant_ts_kv ( |
26 | 25 | long_v bigint, |
27 | 26 | dbl_v double precision, |
28 | 27 | json_v json, |
29 | - CONSTRAINT tenant_ts_kv_pkey PRIMARY KEY (tenant_id, entity_id, key, ts) | |
28 | + CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts) | |
30 | 29 | ); |
31 | 30 | |
32 | 31 | CREATE TABLE IF NOT EXISTS ts_kv_dictionary ( |
... | ... | @@ -45,4 +44,122 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest ( |
45 | 44 | dbl_v double precision, |
46 | 45 | json_v json, |
47 | 46 | CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) |
48 | -); | |
\ No newline at end of file | ||
47 | +); | |
48 | + | |
49 | +CREATE TABLE IF NOT EXISTS tb_schema_settings | |
50 | +( | |
51 | + schema_version bigint NOT NULL, | |
52 | + CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) | |
53 | +); | |
54 | + | |
55 | +INSERT INTO tb_schema_settings (schema_version) VALUES (2005000); | |
56 | + | |
57 | +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS | |
58 | +$$ | |
59 | +BEGIN | |
60 | + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || | |
61 | + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); | |
62 | +END; | |
63 | +$$ LANGUAGE plpgsql; | |
64 | + | |
65 | +CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
66 | + OUT deleted bigint) AS | |
67 | +$$ | |
68 | +BEGIN | |
69 | + EXECUTE format( | |
70 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(device.id) as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
71 | + tenant_id, customer_id, ttl) into deleted; | |
72 | +END; | |
73 | +$$ LANGUAGE plpgsql; | |
74 | + | |
75 | +CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
76 | + OUT deleted bigint) AS | |
77 | +$$ | |
78 | +BEGIN | |
79 | + EXECUTE format( | |
80 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(asset.id) as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
81 | + tenant_id, customer_id, ttl) into deleted; | |
82 | +END; | |
83 | +$$ LANGUAGE plpgsql; | |
84 | + | |
85 | +CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
86 | + OUT deleted bigint) AS | |
87 | +$$ | |
88 | +BEGIN | |
89 | + EXECUTE format( | |
90 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(customer.id) as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
91 | + tenant_id, customer_id, ttl) into deleted; | |
92 | +END; | |
93 | +$$ LANGUAGE plpgsql; | |
94 | + | |
95 | +CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid varchar(31), | |
96 | + IN system_ttl bigint, INOUT deleted bigint) | |
97 | + LANGUAGE plpgsql AS | |
98 | +$$ | |
99 | +DECLARE | |
100 | + tenant_cursor CURSOR FOR select tenant.id as tenant_id | |
101 | + from tenant; | |
102 | + tenant_id_record varchar; | |
103 | + customer_id_record varchar; | |
104 | + tenant_ttl bigint; | |
105 | + customer_ttl bigint; | |
106 | + deleted_for_entities bigint; | |
107 | + tenant_ttl_ts bigint; | |
108 | + customer_ttl_ts bigint; | |
109 | +BEGIN | |
110 | + OPEN tenant_cursor; | |
111 | + FETCH tenant_cursor INTO tenant_id_record; | |
112 | + WHILE FOUND | |
113 | + LOOP | |
114 | + EXECUTE format( | |
115 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
116 | + tenant_id_record, 'TTL') INTO tenant_ttl; | |
117 | + if tenant_ttl IS NULL THEN | |
118 | + tenant_ttl := system_ttl; | |
119 | + END IF; | |
120 | + IF tenant_ttl > 0 THEN | |
121 | + tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint; | |
122 | + deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
123 | + deleted := deleted + deleted_for_entities; | |
124 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record; | |
125 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
126 | + deleted := deleted + deleted_for_entities; | |
127 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record; | |
128 | + END IF; | |
129 | + FOR customer_id_record IN | |
130 | + SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record | |
131 | + LOOP | |
132 | + EXECUTE format( | |
133 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
134 | + customer_id_record, 'TTL') INTO customer_ttl; | |
135 | + IF customer_ttl IS NULL THEN | |
136 | + customer_ttl_ts := tenant_ttl_ts; | |
137 | + ELSE | |
138 | + IF customer_ttl > 0 THEN | |
139 | + customer_ttl_ts := | |
140 | + (EXTRACT(EPOCH FROM current_timestamp) * 1000 - | |
141 | + customer_ttl::bigint * 1000)::bigint; | |
142 | + END IF; | |
143 | + END IF; | |
144 | + IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN | |
145 | + deleted_for_entities := | |
146 | + delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record, | |
147 | + customer_ttl_ts); | |
148 | + deleted := deleted + deleted_for_entities; | |
149 | + RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record; | |
150 | + deleted_for_entities := | |
151 | + delete_device_records_from_ts_kv(tenant_id_record, customer_id_record, | |
152 | + customer_ttl_ts); | |
153 | + deleted := deleted + deleted_for_entities; | |
154 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
155 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, | |
156 | + customer_id_record, | |
157 | + customer_ttl_ts); | |
158 | + deleted := deleted + deleted_for_entities; | |
159 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
160 | + END IF; | |
161 | + END LOOP; | |
162 | + FETCH tenant_cursor INTO tenant_id_record; | |
163 | + END LOOP; | |
164 | +END | |
165 | +$$; | ... | ... |
... | ... | @@ -14,31 +14,260 @@ |
14 | 14 | -- limitations under the License. |
15 | 15 | -- |
16 | 16 | |
17 | -CREATE TABLE IF NOT EXISTS ts_kv ( | |
18 | - entity_id uuid NOT NULL, | |
19 | - key int NOT NULL, | |
20 | - ts bigint NOT NULL, | |
21 | - bool_v boolean, | |
22 | - str_v varchar(10000000), | |
23 | - long_v bigint, | |
24 | - dbl_v double precision, | |
25 | - json_v json | |
17 | +CREATE TABLE IF NOT EXISTS ts_kv | |
18 | +( | |
19 | + entity_id uuid NOT NULL, | |
20 | + key int NOT NULL, | |
21 | + ts bigint NOT NULL, | |
22 | + bool_v boolean, | |
23 | + str_v varchar(10000000), | |
24 | + long_v bigint, | |
25 | + dbl_v double precision, | |
26 | + json_v json | |
26 | 27 | ) PARTITION BY RANGE (ts); |
27 | 28 | |
28 | -CREATE TABLE IF NOT EXISTS ts_kv_latest ( | |
29 | - entity_id uuid NOT NULL, | |
30 | - key int NOT NULL, | |
31 | - ts bigint NOT NULL, | |
32 | - bool_v boolean, | |
33 | - str_v varchar(10000000), | |
34 | - long_v bigint, | |
35 | - dbl_v double precision, | |
36 | - json_v json, | |
29 | +CREATE TABLE IF NOT EXISTS ts_kv_latest | |
30 | +( | |
31 | + entity_id uuid NOT NULL, | |
32 | + key int NOT NULL, | |
33 | + ts bigint NOT NULL, | |
34 | + bool_v boolean, | |
35 | + str_v varchar(10000000), | |
36 | + long_v bigint, | |
37 | + dbl_v double precision, | |
38 | + json_v json, | |
37 | 39 | CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) |
38 | 40 | ); |
39 | 41 | |
40 | -CREATE TABLE IF NOT EXISTS ts_kv_dictionary ( | |
41 | - key varchar(255) NOT NULL, | |
42 | +CREATE TABLE IF NOT EXISTS ts_kv_dictionary | |
43 | +( | |
44 | + key varchar(255) NOT NULL, | |
42 | 45 | key_id serial UNIQUE, |
43 | 46 | CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
44 | -); | |
\ No newline at end of file | ||
47 | +); | |
48 | + | |
49 | +CREATE TABLE IF NOT EXISTS tb_schema_settings | |
50 | +( | |
51 | + schema_version bigint NOT NULL, | |
52 | + CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) | |
53 | +); | |
54 | + | |
55 | +INSERT INTO tb_schema_settings (schema_version) VALUES (2005000); | |
56 | + | |
57 | +CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint) | |
58 | + LANGUAGE plpgsql AS | |
59 | +$$ | |
60 | +DECLARE | |
61 | + max_tenant_ttl bigint; | |
62 | + max_customer_ttl bigint; | |
63 | + max_ttl bigint; | |
64 | + date timestamp; | |
65 | + partition_by_max_ttl_date varchar; | |
66 | + partition_month varchar; | |
67 | + partition_day varchar; | |
68 | + partition_year varchar; | |
69 | + partition varchar; | |
70 | + partition_to_delete varchar; | |
71 | + | |
72 | + | |
73 | +BEGIN | |
74 | + SELECT max(attribute_kv.long_v) | |
75 | + FROM tenant | |
76 | + INNER JOIN attribute_kv ON tenant.id = attribute_kv.entity_id | |
77 | + WHERE attribute_kv.attribute_key = 'TTL' | |
78 | + into max_tenant_ttl; | |
79 | + SELECT max(attribute_kv.long_v) | |
80 | + FROM customer | |
81 | + INNER JOIN attribute_kv ON customer.id = attribute_kv.entity_id | |
82 | + WHERE attribute_kv.attribute_key = 'TTL' | |
83 | + into max_customer_ttl; | |
84 | + max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl); | |
85 | + if max_ttl IS NOT NULL AND max_ttl > 0 THEN | |
86 | + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000)); | |
87 | + partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); | |
88 | + RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; | |
89 | + IF partition_by_max_ttl_date IS NOT NULL THEN | |
90 | + CASE | |
91 | + WHEN partition_type = 'DAYS' THEN | |
92 | + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | |
93 | + partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | |
94 | + partition_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); | |
95 | + WHEN partition_type = 'MONTHS' THEN | |
96 | + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | |
97 | + partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); | |
98 | + ELSE | |
99 | + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); | |
100 | + END CASE; | |
101 | + FOR partition IN SELECT tablename | |
102 | + FROM pg_tables | |
103 | + WHERE schemaname = 'public' | |
104 | + AND tablename like 'ts_kv_' || '%' | |
105 | + AND tablename != 'ts_kv_latest' | |
106 | + AND tablename != 'ts_kv_dictionary' | |
107 | + LOOP | |
108 | + IF partition != partition_by_max_ttl_date THEN | |
109 | + IF partition_year IS NOT NULL THEN | |
110 | + IF SPLIT_PART(partition, '_', 3)::integer < partition_year::integer THEN | |
111 | + partition_to_delete := partition; | |
112 | + ELSE | |
113 | + IF partition_month IS NOT NULL THEN | |
114 | + IF SPLIT_PART(partition, '_', 4)::integer < partition_month::integer THEN | |
115 | + partition_to_delete := partition; | |
116 | + ELSE | |
117 | + IF partition_day IS NOT NULL THEN | |
118 | + IF SPLIT_PART(partition, '_', 5)::integer < partition_day::integer THEN | |
119 | + partition_to_delete := partition; | |
120 | + END IF; | |
121 | + END IF; | |
122 | + END IF; | |
123 | + END IF; | |
124 | + END IF; | |
125 | + END IF; | |
126 | + END IF; | |
127 | + IF partition_to_delete IS NOT NULL THEN | |
128 | + RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete; | |
129 | + EXECUTE format('DROP TABLE %I', partition_to_delete); | |
130 | + deleted := deleted + 1; | |
131 | + END IF; | |
132 | + END LOOP; | |
133 | + END IF; | |
134 | + END IF; | |
135 | +END | |
136 | +$$; | |
137 | + | |
138 | +CREATE OR REPLACE FUNCTION get_partition_by_max_ttl_date(IN partition_type varchar, IN date timestamp, OUT partition varchar) AS | |
139 | +$$ | |
140 | +BEGIN | |
141 | + CASE | |
142 | + WHEN partition_type = 'DAYS' THEN | |
143 | + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM') || '_' || to_char(date, 'dd'); | |
144 | + WHEN partition_type = 'MONTHS' THEN | |
145 | + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); | |
146 | + WHEN partition_type = 'YEARS' THEN | |
147 | + partition := 'ts_kv_' || to_char(date, 'yyyy'); | |
148 | + WHEN partition_type = 'INDEFINITE' THEN | |
149 | + partition := NULL; | |
150 | + ELSE | |
151 | + partition := NULL; | |
152 | + END CASE; | |
153 | + IF partition IS NOT NULL THEN | |
154 | + IF NOT EXISTS(SELECT | |
155 | + FROM pg_tables | |
156 | + WHERE schemaname = 'public' | |
157 | + AND tablename = partition) THEN | |
158 | + partition := NULL; | |
159 | + RAISE NOTICE 'Failed to found partition by ttl'; | |
160 | + END IF; | |
161 | + END IF; | |
162 | +END; | |
163 | +$$ LANGUAGE plpgsql; | |
164 | + | |
165 | +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS | |
166 | +$$ | |
167 | +BEGIN | |
168 | + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || | |
169 | + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); | |
170 | +END; | |
171 | +$$ LANGUAGE plpgsql; | |
172 | + | |
173 | +CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
174 | + OUT deleted bigint) AS | |
175 | +$$ | |
176 | +BEGIN | |
177 | + EXECUTE format( | |
178 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(device.id) as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
179 | + tenant_id, customer_id, ttl) into deleted; | |
180 | +END; | |
181 | +$$ LANGUAGE plpgsql; | |
182 | + | |
183 | +CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
184 | + OUT deleted bigint) AS | |
185 | +$$ | |
186 | +BEGIN | |
187 | + EXECUTE format( | |
188 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(asset.id) as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
189 | + tenant_id, customer_id, ttl) into deleted; | |
190 | +END; | |
191 | +$$ LANGUAGE plpgsql; | |
192 | + | |
193 | +CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint, | |
194 | + OUT deleted bigint) AS | |
195 | +$$ | |
196 | +BEGIN | |
197 | + EXECUTE format( | |
198 | + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(customer.id) as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', | |
199 | + tenant_id, customer_id, ttl) into deleted; | |
200 | +END; | |
201 | +$$ LANGUAGE plpgsql; | |
202 | + | |
203 | +CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid varchar(31), | |
204 | + IN system_ttl bigint, INOUT deleted bigint) | |
205 | + LANGUAGE plpgsql AS | |
206 | +$$ | |
207 | +DECLARE | |
208 | + tenant_cursor CURSOR FOR select tenant.id as tenant_id | |
209 | + from tenant; | |
210 | + tenant_id_record varchar; | |
211 | + customer_id_record varchar; | |
212 | + tenant_ttl bigint; | |
213 | + customer_ttl bigint; | |
214 | + deleted_for_entities bigint; | |
215 | + tenant_ttl_ts bigint; | |
216 | + customer_ttl_ts bigint; | |
217 | +BEGIN | |
218 | + OPEN tenant_cursor; | |
219 | + FETCH tenant_cursor INTO tenant_id_record; | |
220 | + WHILE FOUND | |
221 | + LOOP | |
222 | + EXECUTE format( | |
223 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
224 | + tenant_id_record, 'TTL') INTO tenant_ttl; | |
225 | + if tenant_ttl IS NULL THEN | |
226 | + tenant_ttl := system_ttl; | |
227 | + END IF; | |
228 | + IF tenant_ttl > 0 THEN | |
229 | + tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint; | |
230 | + deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
231 | + deleted := deleted + deleted_for_entities; | |
232 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record; | |
233 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); | |
234 | + deleted := deleted + deleted_for_entities; | |
235 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record; | |
236 | + END IF; | |
237 | + FOR customer_id_record IN | |
238 | + SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record | |
239 | + LOOP | |
240 | + EXECUTE format( | |
241 | + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', | |
242 | + customer_id_record, 'TTL') INTO customer_ttl; | |
243 | + IF customer_ttl IS NULL THEN | |
244 | + customer_ttl_ts := tenant_ttl_ts; | |
245 | + ELSE | |
246 | + IF customer_ttl > 0 THEN | |
247 | + customer_ttl_ts := | |
248 | + (EXTRACT(EPOCH FROM current_timestamp) * 1000 - | |
249 | + customer_ttl::bigint * 1000)::bigint; | |
250 | + END IF; | |
251 | + END IF; | |
252 | + IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN | |
253 | + deleted_for_entities := | |
254 | + delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record, | |
255 | + customer_ttl_ts); | |
256 | + deleted := deleted + deleted_for_entities; | |
257 | + RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record; | |
258 | + deleted_for_entities := | |
259 | + delete_device_records_from_ts_kv(tenant_id_record, customer_id_record, | |
260 | + customer_ttl_ts); | |
261 | + deleted := deleted + deleted_for_entities; | |
262 | + RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
263 | + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, | |
264 | + customer_id_record, | |
265 | + customer_ttl_ts); | |
266 | + deleted := deleted + deleted_for_entities; | |
267 | + RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; | |
268 | + END IF; | |
269 | + END LOOP; | |
270 | + FETCH tenant_cursor INTO tenant_id_record; | |
271 | + END LOOP; | |
272 | +END | |
273 | +$$; | ... | ... |
... | ... | @@ -44,7 +44,7 @@ public class SqlDaoServiceTestSuite { |
44 | 44 | |
45 | 45 | // @ClassRule |
46 | 46 | // public static CustomSqlUnit sqlUnit = new CustomSqlUnit( |
47 | -// Arrays.asList("sql/schema-timescale.sql", "sql/schema-timescale-idx.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), | |
47 | +// Arrays.asList("sql/schema-timescale.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), | |
48 | 48 | // "sql/timescale/drop-all-tables.sql", |
49 | 49 | // "sql-test.properties" |
50 | 50 | // ); | ... | ... |
... | ... | @@ -119,7 +119,7 @@ public class RateLimitedResultSetFutureTest { |
119 | 119 | |
120 | 120 | resultSetFuture = new RateLimitedResultSetFuture(session, rateLimiter, statement); |
121 | 121 | |
122 | - ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one); | |
122 | + ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one, MoreExecutors.directExecutor()); | |
123 | 123 | Row actualRow = transform.get(); |
124 | 124 | |
125 | 125 | assertSame(row, actualRow); |
... | ... | @@ -132,7 +132,7 @@ public class RateLimitedResultSetFutureTest { |
132 | 132 | when(rateLimiter.acquireAsync()).thenReturn(Futures.immediateFuture(null)); |
133 | 133 | when(session.executeAsync(statement)).thenThrow(new UnsupportedFeatureException(ProtocolVersion.V3, "hjg")); |
134 | 134 | resultSetFuture = new RateLimitedResultSetFuture(session, rateLimiter, statement); |
135 | - ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one); | |
135 | + ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one, MoreExecutors.directExecutor()); | |
136 | 136 | try { |
137 | 137 | transform.get(); |
138 | 138 | fail(); |
... | ... | @@ -156,7 +156,7 @@ public class RateLimitedResultSetFutureTest { |
156 | 156 | |
157 | 157 | when(realFuture.get()).thenThrow(new ExecutionException("Fail", new TimeoutException("timeout"))); |
158 | 158 | resultSetFuture = new RateLimitedResultSetFuture(session, rateLimiter, statement); |
159 | - ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one); | |
159 | + ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one, MoreExecutors.directExecutor()); | |
160 | 160 | try { |
161 | 161 | transform.get(); |
162 | 162 | fail(); |
... | ... | @@ -177,7 +177,7 @@ public class RateLimitedResultSetFutureTest { |
177 | 177 | when(rateLimiter.acquireAsync()).thenReturn(future); |
178 | 178 | resultSetFuture = new RateLimitedResultSetFuture(session, rateLimiter, statement); |
179 | 179 | |
180 | - ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one); | |
180 | + ListenableFuture<Row> transform = Futures.transform(resultSetFuture, ResultSet::one, MoreExecutors.directExecutor()); | |
181 | 181 | // TimeUnit.MILLISECONDS.sleep(200); |
182 | 182 | future.cancel(false); |
183 | 183 | latch.countDown(); | ... | ... |
... | ... | @@ -12,7 +12,7 @@ DROP TABLE IF EXISTS event; |
12 | 12 | DROP TABLE IF EXISTS relation; |
13 | 13 | DROP TABLE IF EXISTS tb_user; |
14 | 14 | DROP TABLE IF EXISTS tenant; |
15 | -DROP TABLE IF EXISTS tenant_ts_kv; | |
15 | +DROP TABLE IF EXISTS ts_kv; | |
16 | 16 | DROP TABLE IF EXISTS ts_kv_latest; |
17 | 17 | DROP TABLE IF EXISTS user_credentials; |
18 | 18 | DROP TABLE IF EXISTS widget_type; | ... | ... |
... | ... | @@ -17,6 +17,13 @@ In order to set database type change the value of `DATABASE` variable in `.env` |
17 | 17 | |
18 | 18 | **NOTE**: According to the database type corresponding docker service will be deployed (see `docker-compose.postgres.yml`, `docker-compose.cassandra.yml` for details). |
19 | 19 | |
20 | +Execute the following command to create log folders for the services and chown of these folders to the docker container users. | |
21 | +To be able to change user, **chown** command is used, which requires sudo permissions (script will request password for a sudo access): | |
22 | + | |
23 | +` | |
24 | +$ ./docker-create-log-folders.sh | |
25 | +` | |
26 | + | |
20 | 27 | Execute the following command to run installation: |
21 | 28 | |
22 | 29 | ` | ... | ... |
docker/docker-create-log-folders.sh
0 → 100755
1 | +#!/bin/bash | |
2 | +# | |
3 | +# Copyright © 2016-2020 The Thingsboard Authors | |
4 | +# | |
5 | +# Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | +# you may not use this file except in compliance with the License. | |
7 | +# You may obtain a copy of the License at | |
8 | +# | |
9 | +# http://www.apache.org/licenses/LICENSE-2.0 | |
10 | +# | |
11 | +# Unless required by applicable law or agreed to in writing, software | |
12 | +# distributed under the License is distributed on an "AS IS" BASIS, | |
13 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | +# See the License for the specific language governing permissions and | |
15 | +# limitations under the License. | |
16 | +# | |
17 | + | |
18 | +mkdir -p tb-node/log/ && sudo chown -R 799:799 tb-node/log/ | |
19 | + | |
20 | +mkdir -p tb-transports/coap/log && sudo chown -R 799:799 tb-transports/coap/log | |
21 | + | |
22 | +mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log | |
23 | + | |
24 | +mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log | |
\ No newline at end of file | ... | ... |
... | ... | @@ -39,5 +39,5 @@ spec: |
39 | 39 | volumeMounts: |
40 | 40 | - mountPath: /config |
41 | 41 | name: tb-node-config |
42 | - command: ['sh', '-c', 'while [ ! -f /install-finished ]; do sleep 2; done;'] | |
42 | + command: ['sh', '-c', 'while [ ! -f /tmp/install-finished ]; do sleep 2; done;'] | |
43 | 43 | restartPolicy: Never | ... | ... |
... | ... | @@ -15,4 +15,6 @@ |
15 | 15 | # limitations under the License. |
16 | 16 | # |
17 | 17 | |
18 | -kubectl -n thingsboard delete svc,sts,deploy,pv,pvc,cm,po,ing --all | |
18 | +kubectl -n thingsboard delete svc,sts,deploy,cm,po,ing --all | |
19 | + | |
20 | +kubectl -n thingsboard get pvc --no-headers=true | awk '//{print $1}' | xargs kubectl -n thingsboard delete --ignore-not-found=true pvc | |
\ No newline at end of file | ... | ... |
... | ... | @@ -22,7 +22,7 @@ function installTb() { |
22 | 22 | kubectl apply -f tb-node-configmap.yml |
23 | 23 | kubectl apply -f database-setup.yml && |
24 | 24 | kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && |
25 | - kubectl exec tb-db-setup -- sh -c 'export INSTALL_TB=true; export LOAD_DEMO='"$loadDemo"'; start-tb-node.sh; touch /install-finished;' | |
25 | + kubectl exec tb-db-setup -- sh -c 'export INSTALL_TB=true; export LOAD_DEMO='"$loadDemo"'; start-tb-node.sh; touch /tmp/install-finished;' | |
26 | 26 | |
27 | 27 | kubectl delete pod tb-db-setup |
28 | 28 | ... | ... |
... | ... | @@ -38,6 +38,6 @@ fi |
38 | 38 | |
39 | 39 | kubectl apply -f database-setup.yml && |
40 | 40 | kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && |
41 | -kubectl exec tb-db-setup -- sh -c 'export UPGRADE_TB=true; export FROM_VERSION='"$fromVersion"'; start-tb-node.sh; touch /install-finished;' | |
41 | +kubectl exec tb-db-setup -- sh -c 'export UPGRADE_TB=true; export FROM_VERSION='"$fromVersion"'; start-tb-node.sh; touch /tmp/install-finished;' | |
42 | 42 | |
43 | 43 | kubectl delete pod tb-db-setup | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | # limitations under the License. |
15 | 15 | # |
16 | 16 | |
17 | -FROM debian:stretch | |
17 | +FROM thingsboard/base | |
18 | 18 | |
19 | 19 | COPY start-js-executor.sh ${pkg.name}.deb /tmp/ |
20 | 20 | |
... | ... | @@ -25,4 +25,6 @@ RUN dpkg -i /tmp/${pkg.name}.deb |
25 | 25 | |
26 | 26 | RUN update-rc.d ${pkg.name} disable |
27 | 27 | |
28 | +USER ${pkg.user} | |
29 | + | |
28 | 30 | CMD ["start-js-executor.sh"] | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../..</main.dir> |
37 | 37 | <pkg.name>tb-js-executor</pkg.name> |
38 | 38 | <docker.name>tb-js-executor</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | <pkg.linux.dist>${project.build.directory}/package/linux</pkg.linux.dist> | ... | ... |
... | ... | @@ -18,12 +18,14 @@ |
18 | 18 | CONF_FOLDER="/config" |
19 | 19 | jarfile=${pkg.installFolder}/bin/${pkg.name}.jar |
20 | 20 | configfile=${pkg.name}.conf |
21 | -run_user=${pkg.name} | |
21 | +run_user=${pkg.user} | |
22 | 22 | |
23 | 23 | source "${CONF_FOLDER}/${configfile}" |
24 | 24 | |
25 | 25 | export LOADER_PATH=/config,${LOADER_PATH} |
26 | 26 | |
27 | +cd ${pkg.installFolder}/bin | |
28 | + | |
27 | 29 | if [ "$INSTALL_TB" == "true" ]; then |
28 | 30 | |
29 | 31 | if [ "$LOAD_DEMO" == "true" ]; then | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../..</main.dir> |
37 | 37 | <pkg.name>thingsboard</pkg.name> |
38 | 38 | <docker.name>tb-node</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | </properties> | ... | ... |
... | ... | @@ -38,7 +38,6 @@ |
38 | 38 | <tb.docker.name>tb</tb.docker.name> |
39 | 39 | <tb-postgres.docker.name>tb-postgres</tb-postgres.docker.name> |
40 | 40 | <tb-cassandra.docker.name>tb-cassandra</tb-cassandra.docker.name> |
41 | - <pkg.user>thingsboard</pkg.user> | |
42 | 41 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
43 | 42 | <pkg.upgradeVersion>2.4.2</pkg.upgradeVersion> |
44 | 43 | </properties> | ... | ... |
... | ... | @@ -25,6 +25,8 @@ export LOADER_PATH=/config,${LOADER_PATH} |
25 | 25 | |
26 | 26 | echo "Starting '${project.name}' ..." |
27 | 27 | |
28 | +cd ${pkg.installFolder}/bin | |
29 | + | |
28 | 30 | exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.coap.ThingsboardCoapTransportApplication \ |
29 | 31 | -Dspring.jpa.hibernate.ddl-auto=none \ |
30 | 32 | -Dlogging.config=/config/logback.xml \ | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../../..</main.dir> |
37 | 37 | <pkg.name>tb-coap-transport</pkg.name> |
38 | 38 | <docker.name>tb-coap-transport</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.logFolder>/var/log/${pkg.name}</pkg.logFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | </properties> | ... | ... |
... | ... | @@ -25,6 +25,8 @@ export LOADER_PATH=/config,${LOADER_PATH} |
25 | 25 | |
26 | 26 | echo "Starting '${project.name}' ..." |
27 | 27 | |
28 | +cd ${pkg.installFolder}/bin | |
29 | + | |
28 | 30 | exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.http.ThingsboardHttpTransportApplication \ |
29 | 31 | -Dspring.jpa.hibernate.ddl-auto=none \ |
30 | 32 | -Dlogging.config=/config/logback.xml \ | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../../..</main.dir> |
37 | 37 | <pkg.name>tb-http-transport</pkg.name> |
38 | 38 | <docker.name>tb-http-transport</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.logFolder>/var/log/${pkg.name}</pkg.logFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | </properties> | ... | ... |
... | ... | @@ -25,6 +25,8 @@ export LOADER_PATH=/config,${LOADER_PATH} |
25 | 25 | |
26 | 26 | echo "Starting '${project.name}' ..." |
27 | 27 | |
28 | +cd ${pkg.installFolder}/bin | |
29 | + | |
28 | 30 | exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.mqtt.ThingsboardMqttTransportApplication \ |
29 | 31 | -Dspring.jpa.hibernate.ddl-auto=none \ |
30 | 32 | -Dlogging.config=/config/logback.xml \ | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../../..</main.dir> |
37 | 37 | <pkg.name>tb-mqtt-transport</pkg.name> |
38 | 38 | <docker.name>tb-mqtt-transport</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.logFolder>/var/log/${pkg.name}</pkg.logFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | </properties> | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | # limitations under the License. |
15 | 15 | # |
16 | 16 | |
17 | -FROM debian:stretch | |
17 | +FROM thingsboard/base | |
18 | 18 | |
19 | 19 | COPY start-web-ui.sh ${pkg.name}.deb /tmp/ |
20 | 20 | |
... | ... | @@ -25,4 +25,6 @@ RUN dpkg -i /tmp/${pkg.name}.deb |
25 | 25 | |
26 | 26 | RUN update-rc.d ${pkg.name} disable |
27 | 27 | |
28 | +USER ${pkg.user} | |
29 | + | |
28 | 30 | CMD ["start-web-ui.sh"] | ... | ... |
... | ... | @@ -36,7 +36,6 @@ |
36 | 36 | <main.dir>${basedir}/../..</main.dir> |
37 | 37 | <pkg.name>tb-web-ui</pkg.name> |
38 | 38 | <docker.name>tb-web-ui</docker.name> |
39 | - <pkg.user>thingsboard</pkg.user> | |
40 | 39 | <pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder> |
41 | 40 | <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> |
42 | 41 | <pkg.linux.dist>${project.build.directory}/package/linux</pkg.linux.dist> | ... | ... |
... | ... | @@ -407,8 +407,12 @@ final class MqttClientImpl implements MqttClient { |
407 | 407 | } |
408 | 408 | |
409 | 409 | private MqttMessageIdVariableHeader getNewMessageId() { |
410 | - this.nextMessageId.compareAndSet(0xffff, 1); | |
411 | - return MqttMessageIdVariableHeader.from(this.nextMessageId.getAndIncrement()); | |
410 | + int messageId; | |
411 | + synchronized (this.nextMessageId) { | |
412 | + this.nextMessageId.compareAndSet(0xffff, 1); | |
413 | + messageId = this.nextMessageId.getAndIncrement(); | |
414 | + } | |
415 | + return MqttMessageIdVariableHeader.from(messageId); | |
412 | 416 | } |
413 | 417 | |
414 | 418 | private Future<Void> createSubscription(String topic, MqttHandler handler, boolean once, MqttQoS qos) { | ... | ... |
... | ... | @@ -29,6 +29,7 @@ |
29 | 29 | |
30 | 30 | <properties> |
31 | 31 | <main.dir>${basedir}</main.dir> |
32 | + <pkg.user>thingsboard</pkg.user> | |
32 | 33 | <spring-boot.version>2.1.3.RELEASE</spring-boot.version> |
33 | 34 | <spring.version>5.1.5.RELEASE</spring.version> |
34 | 35 | <spring-security.version>5.1.4.RELEASE</spring-security.version> |
... | ... | @@ -44,7 +45,7 @@ |
44 | 45 | <cassandra.version>3.6.0</cassandra.version> |
45 | 46 | <cassandra-unit.version>3.5.0.1</cassandra-unit.version> |
46 | 47 | <takari-cpsuite.version>1.2.7</takari-cpsuite.version> |
47 | - <guava.version>21.0</guava.version> | |
48 | + <guava.version>28.2-jre</guava.version> | |
48 | 49 | <caffeine.version>2.6.1</caffeine.version> |
49 | 50 | <commons-lang3.version>3.4</commons-lang3.version> |
50 | 51 | <commons-validator.version>1.6</commons-validator.version> |
... | ... | @@ -63,7 +64,7 @@ |
63 | 64 | <mail.version>1.4.3</mail.version> |
64 | 65 | <curator.version>4.2.0</curator.version> |
65 | 66 | <zookeeper.version>3.5.5</zookeeper.version> |
66 | - <protobuf.version>3.9.1</protobuf.version> | |
67 | + <protobuf.version>3.11.4</protobuf.version> | |
67 | 68 | <grpc.version>1.22.1</grpc.version> |
68 | 69 | <lombok.version>1.16.18</lombok.version> |
69 | 70 | <paho.client.version>1.1.0</paho.client.version> | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.google.common.cache.CacheLoader; |
20 | 20 | import com.google.common.cache.LoadingCache; |
21 | 21 | import com.google.common.util.concurrent.Futures; |
22 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | +import com.google.common.util.concurrent.MoreExecutors; | |
23 | 24 | import lombok.AllArgsConstructor; |
24 | 25 | import lombok.Data; |
25 | 26 | import lombok.NoArgsConstructor; |
... | ... | @@ -54,9 +55,9 @@ import java.util.List; |
54 | 55 | import java.util.Optional; |
55 | 56 | import java.util.concurrent.TimeUnit; |
56 | 57 | |
58 | +import static org.thingsboard.common.util.DonAsynchron.withCallback; | |
57 | 59 | import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; |
58 | 60 | import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; |
59 | -import static org.thingsboard.common.util.DonAsynchron.withCallback; | |
60 | 61 | |
61 | 62 | @Slf4j |
62 | 63 | public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationActionNodeConfiguration> implements TbNode { |
... | ... | @@ -86,7 +87,7 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA |
86 | 87 | } |
87 | 88 | |
88 | 89 | protected ListenableFuture<RelationContainer> processEntityRelationAction(TbContext ctx, TbMsg msg) { |
89 | - return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer)); | |
90 | + return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer), MoreExecutors.directExecutor()); | |
90 | 91 | } |
91 | 92 | |
92 | 93 | protected abstract boolean createEntityIfNotExists(); | ... | ... |
... | ... | @@ -18,12 +18,13 @@ package org.thingsboard.rule.engine.action; |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
22 | -import org.thingsboard.rule.engine.api.util.TbNodeUtils; | |
23 | 23 | import org.thingsboard.rule.engine.api.RuleNode; |
24 | 24 | import org.thingsboard.rule.engine.api.TbContext; |
25 | 25 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
26 | 26 | import org.thingsboard.rule.engine.api.TbNodeException; |
27 | +import org.thingsboard.rule.engine.api.util.TbNodeUtils; | |
27 | 28 | import org.thingsboard.server.common.data.alarm.Alarm; |
28 | 29 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
29 | 30 | import org.thingsboard.server.common.data.plugin.ComponentType; |
... | ... | @@ -80,8 +81,8 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig |
80 | 81 | } |
81 | 82 | alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); |
82 | 83 | return Futures.immediateFuture(new AlarmResult(false, false, true, alarm)); |
83 | - }); | |
84 | - }); | |
84 | + }, MoreExecutors.directExecutor()); | |
85 | + }, MoreExecutors.directExecutor()); | |
85 | 86 | }, ctx.getDbCallbackExecutor()); |
86 | 87 | } |
87 | 88 | } | ... | ... |