28 changed files with 306 additions and 1745 deletions
@ -1,38 +0,0 @@ |
|||||
-- |
|
||||
-- Copyright © 2016-2022 The Thingsboard Authors |
|
||||
-- |
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
-- you may not use this file except in compliance with the License. |
|
||||
-- You may obtain a copy of the License at |
|
||||
-- |
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
-- |
|
||||
-- Unless required by applicable law or agreed to in writing, software |
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
-- See the License for the specific language governing permissions and |
|
||||
-- limitations under the License. |
|
||||
-- |
|
||||
|
|
||||
-- This file describes PostgreSQL-specific indexes that not supported by hsql |
|
||||
-- It is not a stand-alone file! Run schema-entities-idx.sql before! |
|
||||
-- Note: Hibernate DESC order translates to native SQL "ORDER BY .. DESC NULLS LAST" |
|
||||
-- While creating index PostgreSQL transforms short notation (ts DESC) to the full (DESC NULLS FIRST) |
|
||||
-- That difference between NULLS LAST and NULLS FIRST prevents to hit index while querying latest by ts |
|
||||
-- That why we need to define DESC index explicitly as (ts DESC NULLS LAST) |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_event_ts |
|
||||
ON public.event |
|
||||
(ts DESC NULLS LAST) |
|
||||
WITH (FILLFACTOR=95); |
|
||||
|
|
||||
COMMENT ON INDEX public.idx_event_ts |
|
||||
IS 'This index helps to delete events by TTL using timestamp'; |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_event_tenant_entity_type_entity_event_type_created_time_des |
|
||||
ON public.event |
|
||||
(tenant_id ASC, entity_type ASC, entity_id ASC, event_type ASC, created_time DESC NULLS LAST) |
|
||||
WITH (FILLFACTOR=95); |
|
||||
|
|
||||
COMMENT ON INDEX public.idx_event_tenant_entity_type_entity_event_type_created_time_des |
|
||||
IS 'This index helps to open latest events on UI fast'; |
|
||||
@ -1,53 +0,0 @@ |
|||||
-- |
|
||||
-- Copyright © 2016-2022 The Thingsboard Authors |
|
||||
-- |
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
-- you may not use this file except in compliance with the License. |
|
||||
-- You may obtain a copy of the License at |
|
||||
-- |
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
-- |
|
||||
-- Unless required by applicable law or agreed to in writing, software |
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
-- See the License for the specific language governing permissions and |
|
||||
-- limitations under the License. |
|
||||
-- |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_originator_alarm_type ON alarm(originator_id, type, start_ts DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_originator_created_time ON alarm(originator_id, created_time DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_created_time ON alarm(tenant_id, created_time DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_alarm_type_created_time ON alarm(tenant_id, type, created_time DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_entity_alarm_alarm_id ON entity_alarm(alarm_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_device_customer_id ON device(tenant_id, customer_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_device_customer_id_and_type ON device(tenant_id, customer_id, type); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_device_type ON device(tenant_id, type); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_device_device_profile_id ON device(tenant_id, device_profile_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_customer_id ON asset(tenant_id, customer_id); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_customer_id_and_type ON asset(tenant_id, customer_id, type); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time); |
|
||||
|
|
||||
CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); |
|
||||
@ -1,695 +0,0 @@ |
|||||
-- |
|
||||
-- Copyright © 2016-2022 The Thingsboard Authors |
|
||||
-- |
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
-- you may not use this file except in compliance with the License. |
|
||||
-- You may obtain a copy of the License at |
|
||||
-- |
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
-- |
|
||||
-- Unless required by applicable law or agreed to in writing, software |
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
-- See the License for the specific language governing permissions and |
|
||||
-- limitations under the License. |
|
||||
-- |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS tb_schema_settings |
|
||||
( |
|
||||
schema_version bigint NOT NULL, |
|
||||
CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) |
|
||||
); |
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE insert_tb_schema_settings() |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
IF (SELECT COUNT(*) FROM tb_schema_settings) = 0 THEN |
|
||||
INSERT INTO tb_schema_settings (schema_version) VALUES (3003000); |
|
||||
END IF; |
|
||||
END; |
|
||||
$$; |
|
||||
|
|
||||
call insert_tb_schema_settings(); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS admin_settings ( |
|
||||
id uuid NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
json_value varchar, |
|
||||
key varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS alarm ( |
|
||||
id uuid NOT NULL CONSTRAINT alarm_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
ack_ts bigint, |
|
||||
clear_ts bigint, |
|
||||
additional_info varchar, |
|
||||
end_ts bigint, |
|
||||
originator_id uuid, |
|
||||
originator_type integer, |
|
||||
propagate boolean, |
|
||||
severity varchar(255), |
|
||||
start_ts bigint, |
|
||||
status varchar(255), |
|
||||
tenant_id uuid, |
|
||||
customer_id uuid, |
|
||||
propagate_relation_types varchar, |
|
||||
type varchar(255), |
|
||||
propagate_to_owner boolean, |
|
||||
propagate_to_tenant boolean |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS entity_alarm ( |
|
||||
tenant_id uuid NOT NULL, |
|
||||
entity_type varchar(32), |
|
||||
entity_id uuid NOT NULL, |
|
||||
created_time bigint NOT NULL, |
|
||||
alarm_type varchar(255) NOT NULL, |
|
||||
customer_id uuid, |
|
||||
alarm_id uuid, |
|
||||
CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), |
|
||||
CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS asset ( |
|
||||
id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
customer_id uuid, |
|
||||
name varchar(255), |
|
||||
label varchar(255), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid, |
|
||||
type varchar(255), |
|
||||
CONSTRAINT asset_name_unq_key UNIQUE (tenant_id, name) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS audit_log ( |
|
||||
id uuid NOT NULL CONSTRAINT audit_log_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
tenant_id uuid, |
|
||||
customer_id uuid, |
|
||||
entity_id uuid, |
|
||||
entity_type varchar(255), |
|
||||
entity_name varchar(255), |
|
||||
user_id uuid, |
|
||||
user_name varchar(255), |
|
||||
action_type varchar(255), |
|
||||
action_data varchar(1000000), |
|
||||
action_status varchar(255), |
|
||||
action_failure_details varchar(1000000) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS attribute_kv ( |
|
||||
entity_type varchar(255), |
|
||||
entity_id uuid, |
|
||||
attribute_type varchar(255), |
|
||||
attribute_key varchar(255), |
|
||||
bool_v boolean, |
|
||||
str_v varchar(10000000), |
|
||||
long_v bigint, |
|
||||
dbl_v double precision, |
|
||||
json_v json, |
|
||||
last_update_ts bigint, |
|
||||
CONSTRAINT attribute_kv_pkey PRIMARY KEY (entity_type, entity_id, attribute_type, attribute_key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS component_descriptor ( |
|
||||
id uuid NOT NULL CONSTRAINT component_descriptor_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
actions varchar(255), |
|
||||
clazz varchar UNIQUE, |
|
||||
configuration_descriptor varchar, |
|
||||
name varchar(255), |
|
||||
scope varchar(255), |
|
||||
search_text varchar(255), |
|
||||
type varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS customer ( |
|
||||
id uuid NOT NULL CONSTRAINT customer_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
address varchar, |
|
||||
address2 varchar, |
|
||||
city varchar(255), |
|
||||
country varchar(255), |
|
||||
email varchar(255), |
|
||||
phone varchar(255), |
|
||||
search_text varchar(255), |
|
||||
state varchar(255), |
|
||||
tenant_id uuid, |
|
||||
title varchar(255), |
|
||||
zip varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS dashboard ( |
|
||||
id uuid NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
configuration varchar, |
|
||||
assigned_customers varchar(1000000), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid, |
|
||||
title varchar(255), |
|
||||
mobile_hide boolean DEFAULT false, |
|
||||
mobile_order int, |
|
||||
image varchar(1000000) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS rule_chain ( |
|
||||
id uuid NOT NULL CONSTRAINT rule_chain_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
configuration varchar(10000000), |
|
||||
name varchar(255), |
|
||||
type varchar(255), |
|
||||
first_rule_node_id uuid, |
|
||||
root boolean, |
|
||||
debug_mode boolean, |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS rule_node ( |
|
||||
id uuid NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
rule_chain_id uuid, |
|
||||
additional_info varchar, |
|
||||
configuration varchar(10000000), |
|
||||
type varchar(255), |
|
||||
name varchar(255), |
|
||||
debug_mode boolean, |
|
||||
search_text varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS rule_node_state ( |
|
||||
id uuid NOT NULL CONSTRAINT rule_node_state_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
rule_node_id uuid NOT NULL, |
|
||||
entity_type varchar(32) NOT NULL, |
|
||||
entity_id uuid NOT NULL, |
|
||||
state_data varchar(16384) NOT NULL, |
|
||||
CONSTRAINT rule_node_state_unq_key UNIQUE (rule_node_id, entity_id), |
|
||||
CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ota_package ( |
|
||||
id uuid NOT NULL CONSTRAINT ota_package_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
tenant_id uuid NOT NULL, |
|
||||
device_profile_id uuid , |
|
||||
type varchar(32) NOT NULL, |
|
||||
title varchar(255) NOT NULL, |
|
||||
version varchar(255) NOT NULL, |
|
||||
tag varchar(255), |
|
||||
url varchar(255), |
|
||||
file_name varchar(255), |
|
||||
content_type varchar(255), |
|
||||
checksum_algorithm varchar(32), |
|
||||
checksum varchar(1020), |
|
||||
data oid, |
|
||||
data_size bigint, |
|
||||
additional_info varchar, |
|
||||
search_text varchar(255), |
|
||||
CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS device_profile ( |
|
||||
id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
name varchar(255), |
|
||||
type varchar(255), |
|
||||
image varchar(1000000), |
|
||||
transport_type varchar(255), |
|
||||
provision_type varchar(255), |
|
||||
profile_data jsonb, |
|
||||
description varchar, |
|
||||
search_text varchar(255), |
|
||||
is_default boolean, |
|
||||
tenant_id uuid, |
|
||||
firmware_id uuid, |
|
||||
software_id uuid, |
|
||||
default_rule_chain_id uuid, |
|
||||
default_dashboard_id uuid, |
|
||||
default_queue_name varchar(255), |
|
||||
provision_device_key varchar, |
|
||||
CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), |
|
||||
CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), |
|
||||
CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), |
|
||||
CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id), |
|
||||
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES ota_package(id), |
|
||||
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id) |
|
||||
); |
|
||||
|
|
||||
ALTER TABLE ota_package |
|
||||
ADD CONSTRAINT fk_device_profile_ota_package |
|
||||
FOREIGN KEY (device_profile_id) REFERENCES device_profile (id) |
|
||||
ON DELETE CASCADE; |
|
||||
|
|
||||
-- We will use one-to-many relation in the first release and extend this feature in case of user requests |
|
||||
-- CREATE TABLE IF NOT EXISTS device_profile_firmware ( |
|
||||
-- device_profile_id uuid NOT NULL, |
|
||||
-- firmware_id uuid NOT NULL, |
|
||||
-- CONSTRAINT device_profile_firmware_unq_key UNIQUE (device_profile_id, firmware_id), |
|
||||
-- CONSTRAINT fk_device_profile_firmware_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE, |
|
||||
-- CONSTRAINT fk_device_profile_firmware_firmware FOREIGN KEY (firmware_id) REFERENCES firmware(id) ON DELETE CASCADE, |
|
||||
-- ); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS device ( |
|
||||
id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
customer_id uuid, |
|
||||
device_profile_id uuid NOT NULL, |
|
||||
device_data jsonb, |
|
||||
type varchar(255), |
|
||||
name varchar(255), |
|
||||
label varchar(255), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid, |
|
||||
firmware_id uuid, |
|
||||
software_id uuid, |
|
||||
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), |
|
||||
CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id), |
|
||||
CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES ota_package(id), |
|
||||
CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES ota_package(id) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS device_credentials ( |
|
||||
id uuid NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
credentials_id varchar, |
|
||||
credentials_type varchar(255), |
|
||||
credentials_value varchar, |
|
||||
device_id uuid, |
|
||||
CONSTRAINT device_credentials_id_unq_key UNIQUE (credentials_id), |
|
||||
CONSTRAINT device_credentials_device_id_unq_key UNIQUE (device_id) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS event ( |
|
||||
id uuid NOT NULL CONSTRAINT event_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
body varchar(10000000), |
|
||||
entity_id uuid, |
|
||||
entity_type varchar(255), |
|
||||
event_type varchar(255), |
|
||||
event_uid varchar(255), |
|
||||
tenant_id uuid, |
|
||||
ts bigint NOT NULL, |
|
||||
CONSTRAINT event_unq_key UNIQUE (tenant_id, entity_type, entity_id, event_type, event_uid) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS relation ( |
|
||||
from_id uuid, |
|
||||
from_type varchar(255), |
|
||||
to_id uuid, |
|
||||
to_type varchar(255), |
|
||||
relation_type_group varchar(255), |
|
||||
relation_type varchar(255), |
|
||||
additional_info varchar, |
|
||||
CONSTRAINT relation_pkey PRIMARY KEY (from_id, from_type, relation_type_group, relation_type, to_id, to_type) |
|
||||
); |
|
||||
-- ) PARTITION BY LIST (relation_type_group); |
|
||||
-- |
|
||||
-- CREATE TABLE other_relations PARTITION OF relation DEFAULT; |
|
||||
-- CREATE TABLE common_relations PARTITION OF relation FOR VALUES IN ('COMMON'); |
|
||||
-- CREATE TABLE alarm_relations PARTITION OF relation FOR VALUES IN ('ALARM'); |
|
||||
-- CREATE TABLE dashboard_relations PARTITION OF relation FOR VALUES IN ('DASHBOARD'); |
|
||||
-- CREATE TABLE rule_relations PARTITION OF relation FOR VALUES IN ('RULE_CHAIN', 'RULE_NODE'); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS tb_user ( |
|
||||
id uuid NOT NULL CONSTRAINT tb_user_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
authority varchar(255), |
|
||||
customer_id uuid, |
|
||||
email varchar(255) UNIQUE, |
|
||||
first_name varchar(255), |
|
||||
last_name varchar(255), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS tenant_profile ( |
|
||||
id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
name varchar(255), |
|
||||
profile_data jsonb, |
|
||||
description varchar, |
|
||||
search_text varchar(255), |
|
||||
is_default boolean, |
|
||||
isolated_tb_core boolean, |
|
||||
isolated_tb_rule_engine boolean, |
|
||||
CONSTRAINT tenant_profile_name_unq_key UNIQUE (name) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS tenant ( |
|
||||
id uuid NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
tenant_profile_id uuid NOT NULL, |
|
||||
address varchar, |
|
||||
address2 varchar, |
|
||||
city varchar(255), |
|
||||
country varchar(255), |
|
||||
email varchar(255), |
|
||||
phone varchar(255), |
|
||||
region varchar(255), |
|
||||
search_text varchar(255), |
|
||||
state varchar(255), |
|
||||
title varchar(255), |
|
||||
zip varchar(255), |
|
||||
CONSTRAINT fk_tenant_profile FOREIGN KEY (tenant_profile_id) REFERENCES tenant_profile(id) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS user_credentials ( |
|
||||
id uuid NOT NULL CONSTRAINT user_credentials_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
activate_token varchar(255) UNIQUE, |
|
||||
enabled boolean, |
|
||||
password varchar(255), |
|
||||
reset_token varchar(255) UNIQUE, |
|
||||
user_id uuid UNIQUE |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS widget_type ( |
|
||||
id uuid NOT NULL CONSTRAINT widget_type_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
alias varchar(255), |
|
||||
bundle_alias varchar(255), |
|
||||
descriptor varchar(1000000), |
|
||||
name varchar(255), |
|
||||
tenant_id uuid, |
|
||||
image varchar(1000000), |
|
||||
description varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS widgets_bundle ( |
|
||||
id uuid NOT NULL CONSTRAINT widgets_bundle_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
alias varchar(255), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid, |
|
||||
title varchar(255), |
|
||||
image varchar(1000000), |
|
||||
description varchar(255) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS entity_view ( |
|
||||
id uuid NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
entity_id uuid, |
|
||||
entity_type varchar(255), |
|
||||
tenant_id uuid, |
|
||||
customer_id uuid, |
|
||||
type varchar(255), |
|
||||
name varchar(255), |
|
||||
keys varchar(10000000), |
|
||||
start_ts bigint, |
|
||||
end_ts bigint, |
|
||||
search_text varchar(255), |
|
||||
additional_info varchar |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv_latest |
|
||||
( |
|
||||
entity_id uuid NOT NULL, |
|
||||
key int NOT NULL, |
|
||||
ts bigint NOT NULL, |
|
||||
bool_v boolean, |
|
||||
str_v varchar(10000000), |
|
||||
long_v bigint, |
|
||||
dbl_v double precision, |
|
||||
json_v json, |
|
||||
CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv_dictionary |
|
||||
( |
|
||||
key varchar(255) NOT NULL, |
|
||||
key_id serial UNIQUE, |
|
||||
CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS oauth2_params ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_params_pkey PRIMARY KEY, |
|
||||
enabled boolean, |
|
||||
tenant_id uuid, |
|
||||
created_time bigint NOT NULL |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS oauth2_registration ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_registration_pkey PRIMARY KEY, |
|
||||
oauth2_params_id uuid NOT NULL, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
client_id varchar(255), |
|
||||
client_secret varchar(2048), |
|
||||
authorization_uri varchar(255), |
|
||||
token_uri varchar(255), |
|
||||
scope varchar(255), |
|
||||
platforms varchar(255), |
|
||||
user_info_uri varchar(255), |
|
||||
user_name_attribute_name varchar(255), |
|
||||
jwk_set_uri varchar(255), |
|
||||
client_authentication_method varchar(255), |
|
||||
login_button_label varchar(255), |
|
||||
login_button_icon varchar(255), |
|
||||
allow_user_creation boolean, |
|
||||
activate_user boolean, |
|
||||
type varchar(31), |
|
||||
basic_email_attribute_key varchar(31), |
|
||||
basic_first_name_attribute_key varchar(31), |
|
||||
basic_last_name_attribute_key varchar(31), |
|
||||
basic_tenant_name_strategy varchar(31), |
|
||||
basic_tenant_name_pattern varchar(255), |
|
||||
basic_customer_name_pattern varchar(255), |
|
||||
basic_default_dashboard_name varchar(255), |
|
||||
basic_always_full_screen boolean, |
|
||||
custom_url varchar(255), |
|
||||
custom_username varchar(255), |
|
||||
custom_password varchar(255), |
|
||||
custom_send_token boolean, |
|
||||
CONSTRAINT fk_registration_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS oauth2_domain ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_domain_pkey PRIMARY KEY, |
|
||||
oauth2_params_id uuid NOT NULL, |
|
||||
created_time bigint NOT NULL, |
|
||||
domain_name varchar(255), |
|
||||
domain_scheme varchar(31), |
|
||||
CONSTRAINT fk_domain_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE, |
|
||||
CONSTRAINT oauth2_domain_unq_key UNIQUE (oauth2_params_id, domain_name, domain_scheme) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS oauth2_mobile ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_mobile_pkey PRIMARY KEY, |
|
||||
oauth2_params_id uuid NOT NULL, |
|
||||
created_time bigint NOT NULL, |
|
||||
pkg_name varchar(255), |
|
||||
app_secret varchar(2048), |
|
||||
CONSTRAINT fk_mobile_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE, |
|
||||
CONSTRAINT oauth2_mobile_unq_key UNIQUE (oauth2_params_id, pkg_name) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS oauth2_client_registration_template ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_client_registration_template_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
provider_id varchar(255), |
|
||||
authorization_uri varchar(255), |
|
||||
token_uri varchar(255), |
|
||||
scope varchar(255), |
|
||||
user_info_uri varchar(255), |
|
||||
user_name_attribute_name varchar(255), |
|
||||
jwk_set_uri varchar(255), |
|
||||
client_authentication_method varchar(255), |
|
||||
type varchar(31), |
|
||||
basic_email_attribute_key varchar(31), |
|
||||
basic_first_name_attribute_key varchar(31), |
|
||||
basic_last_name_attribute_key varchar(31), |
|
||||
basic_tenant_name_strategy varchar(31), |
|
||||
basic_tenant_name_pattern varchar(255), |
|
||||
basic_customer_name_pattern varchar(255), |
|
||||
basic_default_dashboard_name varchar(255), |
|
||||
basic_always_full_screen boolean, |
|
||||
comment varchar, |
|
||||
login_button_icon varchar(255), |
|
||||
login_button_label varchar(255), |
|
||||
help_link varchar(255), |
|
||||
CONSTRAINT oauth2_template_provider_id_unq_key UNIQUE (provider_id) |
|
||||
); |
|
||||
|
|
||||
-- Deprecated |
|
||||
CREATE TABLE IF NOT EXISTS oauth2_client_registration_info ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_client_registration_info_pkey PRIMARY KEY, |
|
||||
enabled boolean, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
client_id varchar(255), |
|
||||
client_secret varchar(255), |
|
||||
authorization_uri varchar(255), |
|
||||
token_uri varchar(255), |
|
||||
scope varchar(255), |
|
||||
user_info_uri varchar(255), |
|
||||
user_name_attribute_name varchar(255), |
|
||||
jwk_set_uri varchar(255), |
|
||||
client_authentication_method varchar(255), |
|
||||
login_button_label varchar(255), |
|
||||
login_button_icon varchar(255), |
|
||||
allow_user_creation boolean, |
|
||||
activate_user boolean, |
|
||||
type varchar(31), |
|
||||
basic_email_attribute_key varchar(31), |
|
||||
basic_first_name_attribute_key varchar(31), |
|
||||
basic_last_name_attribute_key varchar(31), |
|
||||
basic_tenant_name_strategy varchar(31), |
|
||||
basic_tenant_name_pattern varchar(255), |
|
||||
basic_customer_name_pattern varchar(255), |
|
||||
basic_default_dashboard_name varchar(255), |
|
||||
basic_always_full_screen boolean, |
|
||||
custom_url varchar(255), |
|
||||
custom_username varchar(255), |
|
||||
custom_password varchar(255), |
|
||||
custom_send_token boolean |
|
||||
); |
|
||||
|
|
||||
-- Deprecated |
|
||||
CREATE TABLE IF NOT EXISTS oauth2_client_registration ( |
|
||||
id uuid NOT NULL CONSTRAINT oauth2_client_registration_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
domain_name varchar(255), |
|
||||
domain_scheme varchar(31), |
|
||||
client_registration_info_id uuid |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS api_usage_state ( |
|
||||
id uuid NOT NULL CONSTRAINT usage_record_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
tenant_id uuid, |
|
||||
entity_type varchar(32), |
|
||||
entity_id uuid, |
|
||||
transport varchar(32), |
|
||||
db_storage varchar(32), |
|
||||
re_exec varchar(32), |
|
||||
js_exec varchar(32), |
|
||||
email_exec varchar(32), |
|
||||
sms_exec varchar(32), |
|
||||
alarm_exec varchar(32), |
|
||||
CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS resource ( |
|
||||
id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
tenant_id uuid NOT NULL, |
|
||||
title varchar(255) NOT NULL, |
|
||||
resource_type varchar(32) NOT NULL, |
|
||||
resource_key varchar(255) NOT NULL, |
|
||||
search_text varchar(255), |
|
||||
file_name varchar(255) NOT NULL, |
|
||||
data varchar, |
|
||||
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS edge ( |
|
||||
id uuid NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
additional_info varchar, |
|
||||
customer_id uuid, |
|
||||
root_rule_chain_id uuid, |
|
||||
type varchar(255), |
|
||||
name varchar(255), |
|
||||
label varchar(255), |
|
||||
routing_key varchar(255), |
|
||||
secret varchar(255), |
|
||||
search_text varchar(255), |
|
||||
tenant_id uuid, |
|
||||
CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name), |
|
||||
CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS edge_event ( |
|
||||
id uuid NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
edge_id uuid, |
|
||||
edge_event_type varchar(255), |
|
||||
edge_event_uid varchar(255), |
|
||||
entity_id uuid, |
|
||||
edge_event_action varchar(255), |
|
||||
body varchar(10000000), |
|
||||
tenant_id uuid, |
|
||||
ts bigint NOT NULL |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS rpc ( |
|
||||
id uuid NOT NULL CONSTRAINT rpc_pkey PRIMARY KEY, |
|
||||
created_time bigint NOT NULL, |
|
||||
tenant_id uuid NOT NULL, |
|
||||
device_id uuid NOT NULL, |
|
||||
expiration_time bigint NOT NULL, |
|
||||
request varchar(10000000) NOT NULL, |
|
||||
response varchar(10000000), |
|
||||
additional_info varchar(10000000), |
|
||||
status varchar(255) NOT NULL |
|
||||
); |
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl( |
|
||||
IN regular_events_start_ts bigint, |
|
||||
IN regular_events_end_ts bigint, |
|
||||
IN debug_events_start_ts bigint, |
|
||||
IN debug_events_end_ts bigint, |
|
||||
INOUT deleted bigint) |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
DECLARE |
|
||||
ttl_deleted_count bigint DEFAULT 0; |
|
||||
debug_ttl_deleted_count bigint DEFAULT 0; |
|
||||
BEGIN |
|
||||
IF regular_events_start_ts > 0 AND regular_events_end_ts > 0 THEN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM event WHERE id in (SELECT id from event WHERE ts > %L::bigint AND ts < %L::bigint AND ' || |
|
||||
'(event_type != %L::varchar AND event_type != %L::varchar)) RETURNING *) ' || |
|
||||
'SELECT count(*) FROM deleted', regular_events_start_ts, regular_events_end_ts, |
|
||||
'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into ttl_deleted_count; |
|
||||
END IF; |
|
||||
IF debug_events_start_ts > 0 AND debug_events_end_ts > 0 THEN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM event WHERE id in (SELECT id from event WHERE ts > %L::bigint AND ts < %L::bigint AND ' || |
|
||||
'(event_type = %L::varchar OR event_type = %L::varchar)) RETURNING *) ' || |
|
||||
'SELECT count(*) FROM deleted', debug_events_start_ts, debug_events_end_ts, |
|
||||
'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into debug_ttl_deleted_count; |
|
||||
END IF; |
|
||||
RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count; |
|
||||
RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count; |
|
||||
deleted := ttl_deleted_count + debug_ttl_deleted_count; |
|
||||
END |
|
||||
$$; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || |
|
||||
'-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE cleanup_edge_events_by_ttl(IN ttl bigint, INOUT deleted bigint) |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
DECLARE |
|
||||
ttl_ts bigint; |
|
||||
ttl_deleted_count bigint DEFAULT 0; |
|
||||
BEGIN |
|
||||
IF ttl > 0 THEN |
|
||||
ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint; |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM edge_event WHERE ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', ttl_ts) into ttl_deleted_count; |
|
||||
END IF; |
|
||||
RAISE NOTICE 'Edge events removed by ttl: %', ttl_deleted_count; |
|
||||
deleted := ttl_deleted_count; |
|
||||
END |
|
||||
$$; |
|
||||
@ -1,157 +0,0 @@ |
|||||
-- |
|
||||
-- Copyright © 2016-2022 The Thingsboard Authors |
|
||||
-- |
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
-- you may not use this file except in compliance with the License. |
|
||||
-- You may obtain a copy of the License at |
|
||||
-- |
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
-- |
|
||||
-- Unless required by applicable law or agreed to in writing, software |
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
-- See the License for the specific language governing permissions and |
|
||||
-- limitations under the License. |
|
||||
-- |
|
||||
|
|
||||
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv ( |
|
||||
entity_id uuid NOT NULL, |
|
||||
key int NOT NULL, |
|
||||
ts bigint NOT NULL, |
|
||||
bool_v boolean, |
|
||||
str_v varchar(10000000), |
|
||||
long_v bigint, |
|
||||
dbl_v double precision, |
|
||||
json_v json, |
|
||||
CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv_dictionary ( |
|
||||
key varchar(255) NOT NULL, |
|
||||
key_id serial UNIQUE, |
|
||||
CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
|
||||
); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv_latest ( |
|
||||
entity_id uuid NOT NULL, |
|
||||
key int NOT NULL, |
|
||||
ts bigint NOT NULL, |
|
||||
bool_v boolean, |
|
||||
str_v varchar(10000000), |
|
||||
long_v bigint, |
|
||||
dbl_v double precision, |
|
||||
json_v json, |
|
||||
CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) |
|
||||
); |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || |
|
||||
'-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT device.id as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT asset.id as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT customer.id as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid uuid, |
|
||||
IN system_ttl bigint, INOUT deleted bigint) |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
DECLARE |
|
||||
tenant_cursor CURSOR FOR select tenant.id as tenant_id |
|
||||
from tenant; |
|
||||
tenant_id_record uuid; |
|
||||
customer_id_record uuid; |
|
||||
tenant_ttl bigint; |
|
||||
customer_ttl bigint; |
|
||||
deleted_for_entities bigint; |
|
||||
tenant_ttl_ts bigint; |
|
||||
customer_ttl_ts bigint; |
|
||||
BEGIN |
|
||||
OPEN tenant_cursor; |
|
||||
FETCH tenant_cursor INTO tenant_id_record; |
|
||||
WHILE FOUND |
|
||||
LOOP |
|
||||
EXECUTE format( |
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', |
|
||||
tenant_id_record, 'TTL') INTO tenant_ttl; |
|
||||
if tenant_ttl IS NULL THEN |
|
||||
tenant_ttl := system_ttl; |
|
||||
END IF; |
|
||||
IF tenant_ttl > 0 THEN |
|
||||
tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint; |
|
||||
deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record; |
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record; |
|
||||
END IF; |
|
||||
FOR customer_id_record IN |
|
||||
SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record |
|
||||
LOOP |
|
||||
EXECUTE format( |
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', |
|
||||
customer_id_record, 'TTL') INTO customer_ttl; |
|
||||
IF customer_ttl IS NULL THEN |
|
||||
customer_ttl_ts := tenant_ttl_ts; |
|
||||
ELSE |
|
||||
IF customer_ttl > 0 THEN |
|
||||
customer_ttl_ts := |
|
||||
(EXTRACT(EPOCH FROM current_timestamp) * 1000 - |
|
||||
customer_ttl::bigint * 1000)::bigint; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN |
|
||||
deleted_for_entities := |
|
||||
delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record; |
|
||||
deleted_for_entities := |
|
||||
delete_device_records_from_ts_kv(tenant_id_record, customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; |
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, |
|
||||
customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; |
|
||||
END IF; |
|
||||
END LOOP; |
|
||||
FETCH tenant_cursor INTO tenant_id_record; |
|
||||
END LOOP; |
|
||||
END |
|
||||
$$; |
|
||||
@ -1,339 +0,0 @@ |
|||||
-- |
|
||||
-- Copyright © 2016-2022 The Thingsboard Authors |
|
||||
-- |
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
-- you may not use this file except in compliance with the License. |
|
||||
-- You may obtain a copy of the License at |
|
||||
-- |
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
-- |
|
||||
-- Unless required by applicable law or agreed to in writing, software |
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
-- See the License for the specific language governing permissions and |
|
||||
-- limitations under the License. |
|
||||
-- |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv |
|
||||
( |
|
||||
entity_id uuid NOT NULL, |
|
||||
key int NOT NULL, |
|
||||
ts bigint NOT NULL, |
|
||||
bool_v boolean, |
|
||||
str_v varchar(10000000), |
|
||||
long_v bigint, |
|
||||
dbl_v double precision, |
|
||||
json_v json, |
|
||||
CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts) |
|
||||
) PARTITION BY RANGE (ts); |
|
||||
|
|
||||
CREATE TABLE IF NOT EXISTS ts_kv_dictionary |
|
||||
( |
|
||||
key varchar(255) NOT NULL, |
|
||||
key_id serial UNIQUE, |
|
||||
CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) |
|
||||
); |
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint) |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
DECLARE |
|
||||
max_tenant_ttl bigint; |
|
||||
max_customer_ttl bigint; |
|
||||
max_ttl bigint; |
|
||||
date timestamp; |
|
||||
partition_by_max_ttl_date varchar; |
|
||||
partition_by_max_ttl_month varchar; |
|
||||
partition_by_max_ttl_day varchar; |
|
||||
partition_by_max_ttl_year varchar; |
|
||||
partition varchar; |
|
||||
partition_year integer; |
|
||||
partition_month integer; |
|
||||
partition_day integer; |
|
||||
|
|
||||
BEGIN |
|
||||
SELECT max(attribute_kv.long_v) |
|
||||
FROM tenant |
|
||||
INNER JOIN attribute_kv ON tenant.id = attribute_kv.entity_id |
|
||||
WHERE attribute_kv.attribute_key = 'TTL' |
|
||||
into max_tenant_ttl; |
|
||||
SELECT max(attribute_kv.long_v) |
|
||||
FROM customer |
|
||||
INNER JOIN attribute_kv ON customer.id = attribute_kv.entity_id |
|
||||
WHERE attribute_kv.attribute_key = 'TTL' |
|
||||
into max_customer_ttl; |
|
||||
max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl); |
|
||||
if max_ttl IS NOT NULL AND max_ttl > 0 THEN |
|
||||
date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl); |
|
||||
partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); |
|
||||
RAISE NOTICE 'Date by max ttl: %', date; |
|
||||
RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; |
|
||||
IF partition_by_max_ttl_date IS NOT NULL THEN |
|
||||
CASE |
|
||||
WHEN partition_type = 'DAYS' THEN |
|
||||
partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
|
||||
partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); |
|
||||
partition_by_max_ttl_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5); |
|
||||
WHEN partition_type = 'MONTHS' THEN |
|
||||
partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
|
||||
partition_by_max_ttl_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4); |
|
||||
ELSE |
|
||||
partition_by_max_ttl_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3); |
|
||||
END CASE; |
|
||||
IF partition_by_max_ttl_year IS NULL THEN |
|
||||
RAISE NOTICE 'Failed to remove partitions by max ttl date due to partition_by_max_ttl_year is null!'; |
|
||||
ELSE |
|
||||
IF partition_type = 'YEARS' THEN |
|
||||
FOR partition IN SELECT tablename |
|
||||
FROM pg_tables |
|
||||
WHERE schemaname = 'public' |
|
||||
AND tablename like 'ts_kv_' || '%' |
|
||||
AND tablename != 'ts_kv_latest' |
|
||||
AND tablename != 'ts_kv_dictionary' |
|
||||
AND tablename != 'ts_kv_indefinite' |
|
||||
AND tablename != partition_by_max_ttl_date |
|
||||
LOOP |
|
||||
partition_year := SPLIT_PART(partition, '_', 3)::integer; |
|
||||
IF partition_year < partition_by_max_ttl_year::integer THEN |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
END IF; |
|
||||
END LOOP; |
|
||||
ELSE |
|
||||
IF partition_type = 'MONTHS' THEN |
|
||||
IF partition_by_max_ttl_month IS NULL THEN |
|
||||
RAISE NOTICE 'Failed to remove months partitions by max ttl date due to partition_by_max_ttl_month is null!'; |
|
||||
ELSE |
|
||||
FOR partition IN SELECT tablename |
|
||||
FROM pg_tables |
|
||||
WHERE schemaname = 'public' |
|
||||
AND tablename like 'ts_kv_' || '%' |
|
||||
AND tablename != 'ts_kv_latest' |
|
||||
AND tablename != 'ts_kv_dictionary' |
|
||||
AND tablename != 'ts_kv_indefinite' |
|
||||
AND tablename != partition_by_max_ttl_date |
|
||||
LOOP |
|
||||
partition_year := SPLIT_PART(partition, '_', 3)::integer; |
|
||||
IF partition_year > partition_by_max_ttl_year::integer THEN |
|
||||
RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; |
|
||||
CONTINUE; |
|
||||
ELSE |
|
||||
IF partition_year < partition_by_max_ttl_year::integer THEN |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
ELSE |
|
||||
partition_month := SPLIT_PART(partition, '_', 4)::integer; |
|
||||
IF partition_year = partition_by_max_ttl_year::integer THEN |
|
||||
IF partition_month >= partition_by_max_ttl_month::integer THEN |
|
||||
RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; |
|
||||
CONTINUE; |
|
||||
ELSE |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END LOOP; |
|
||||
END IF; |
|
||||
ELSE |
|
||||
IF partition_type = 'DAYS' THEN |
|
||||
IF partition_by_max_ttl_month IS NULL THEN |
|
||||
RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_month is null!'; |
|
||||
ELSE |
|
||||
IF partition_by_max_ttl_day IS NULL THEN |
|
||||
RAISE NOTICE 'Failed to remove days partitions by max ttl date due to partition_by_max_ttl_day is null!'; |
|
||||
ELSE |
|
||||
FOR partition IN SELECT tablename |
|
||||
FROM pg_tables |
|
||||
WHERE schemaname = 'public' |
|
||||
AND tablename like 'ts_kv_' || '%' |
|
||||
AND tablename != 'ts_kv_latest' |
|
||||
AND tablename != 'ts_kv_dictionary' |
|
||||
AND tablename != 'ts_kv_indefinite' |
|
||||
AND tablename != partition_by_max_ttl_date |
|
||||
LOOP |
|
||||
partition_year := SPLIT_PART(partition, '_', 3)::integer; |
|
||||
IF partition_year > partition_by_max_ttl_year::integer THEN |
|
||||
RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; |
|
||||
CONTINUE; |
|
||||
ELSE |
|
||||
IF partition_year < partition_by_max_ttl_year::integer THEN |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
ELSE |
|
||||
partition_month := SPLIT_PART(partition, '_', 4)::integer; |
|
||||
IF partition_month > partition_by_max_ttl_month::integer THEN |
|
||||
RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; |
|
||||
CONTINUE; |
|
||||
ELSE |
|
||||
IF partition_month < partition_by_max_ttl_month::integer THEN |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
ELSE |
|
||||
partition_day := SPLIT_PART(partition, '_', 5)::integer; |
|
||||
IF partition_day >= partition_by_max_ttl_day::integer THEN |
|
||||
RAISE NOTICE 'Skip iteration! Partition: % is valid!', partition; |
|
||||
CONTINUE; |
|
||||
ELSE |
|
||||
IF partition_day < partition_by_max_ttl_day::integer THEN |
|
||||
RAISE NOTICE 'Partition to delete by max ttl: %', partition; |
|
||||
EXECUTE format('DROP TABLE IF EXISTS %I', partition); |
|
||||
deleted := deleted + 1; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END LOOP; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END |
|
||||
$$; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION get_partition_by_max_ttl_date(IN partition_type varchar, IN date timestamp, OUT partition varchar) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
CASE |
|
||||
WHEN partition_type = 'DAYS' THEN |
|
||||
partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM') || '_' || to_char(date, 'dd'); |
|
||||
WHEN partition_type = 'MONTHS' THEN |
|
||||
partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM'); |
|
||||
WHEN partition_type = 'YEARS' THEN |
|
||||
partition := 'ts_kv_' || to_char(date, 'yyyy'); |
|
||||
ELSE |
|
||||
partition := NULL; |
|
||||
END CASE; |
|
||||
IF partition IS NOT NULL THEN |
|
||||
IF NOT EXISTS(SELECT |
|
||||
FROM pg_tables |
|
||||
WHERE schemaname = 'public' |
|
||||
AND tablename = partition) THEN |
|
||||
partition := NULL; |
|
||||
RAISE NOTICE 'Failed to found partition by ttl'; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || |
|
||||
'-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT device.id as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT asset.id as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id uuid, customer_id uuid, ttl bigint, |
|
||||
OUT deleted bigint) AS |
|
||||
$$ |
|
||||
BEGIN |
|
||||
EXECUTE format( |
|
||||
'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT customer.id as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', |
|
||||
tenant_id, customer_id, ttl) into deleted; |
|
||||
END; |
|
||||
$$ LANGUAGE plpgsql; |
|
||||
|
|
||||
CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid uuid, |
|
||||
IN system_ttl bigint, INOUT deleted bigint) |
|
||||
LANGUAGE plpgsql AS |
|
||||
$$ |
|
||||
DECLARE |
|
||||
tenant_cursor CURSOR FOR select tenant.id as tenant_id |
|
||||
from tenant; |
|
||||
tenant_id_record uuid; |
|
||||
customer_id_record uuid; |
|
||||
tenant_ttl bigint; |
|
||||
customer_ttl bigint; |
|
||||
deleted_for_entities bigint; |
|
||||
tenant_ttl_ts bigint; |
|
||||
customer_ttl_ts bigint; |
|
||||
BEGIN |
|
||||
OPEN tenant_cursor; |
|
||||
FETCH tenant_cursor INTO tenant_id_record; |
|
||||
WHILE FOUND |
|
||||
LOOP |
|
||||
EXECUTE format( |
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', |
|
||||
tenant_id_record, 'TTL') INTO tenant_ttl; |
|
||||
if tenant_ttl IS NULL THEN |
|
||||
tenant_ttl := system_ttl; |
|
||||
END IF; |
|
||||
IF tenant_ttl > 0 THEN |
|
||||
tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint; |
|
||||
deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record; |
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record; |
|
||||
END IF; |
|
||||
FOR customer_id_record IN |
|
||||
SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record |
|
||||
LOOP |
|
||||
EXECUTE format( |
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L', |
|
||||
customer_id_record, 'TTL') INTO customer_ttl; |
|
||||
IF customer_ttl IS NULL THEN |
|
||||
customer_ttl_ts := tenant_ttl_ts; |
|
||||
ELSE |
|
||||
IF customer_ttl > 0 THEN |
|
||||
customer_ttl_ts := |
|
||||
(EXTRACT(EPOCH FROM current_timestamp) * 1000 - |
|
||||
customer_ttl::bigint * 1000)::bigint; |
|
||||
END IF; |
|
||||
END IF; |
|
||||
IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN |
|
||||
deleted_for_entities := |
|
||||
delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record; |
|
||||
deleted_for_entities := |
|
||||
delete_device_records_from_ts_kv(tenant_id_record, customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; |
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, |
|
||||
customer_id_record, |
|
||||
customer_ttl_ts); |
|
||||
deleted := deleted + deleted_for_entities; |
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record; |
|
||||
END IF; |
|
||||
END LOOP; |
|
||||
FETCH tenant_cursor INTO tenant_id_record; |
|
||||
END LOOP; |
|
||||
END |
|
||||
$$; |
|
||||
@ -0,0 +1,100 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2022 The Thingsboard Authors |
||||
|
* <p> |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* <p> |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* <p> |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.ota.files; |
||||
|
|
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.io.FileUtils; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.data.id.OtaPackageId; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.io.InputStream; |
||||
|
import java.util.Optional; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
import java.util.concurrent.ConcurrentMap; |
||||
|
|
||||
|
@Slf4j |
||||
|
@RequiredArgsConstructor |
||||
|
@Component |
||||
|
public class BaseFileCacheService implements FileCacheService { |
||||
|
@Value("${files.temporary_files_directory}/ota/") |
||||
|
private String PATH; |
||||
|
private final static String FILE_NAME_TEMPLATE = "%s.tmp"; |
||||
|
private final TemporaryFileCleaner fileCleaner; |
||||
|
private final ConcurrentMap<OtaPackageId, Boolean> files = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public File saveDataTemporaryFile(InputStream inputStream) { |
||||
|
File path = new File(PATH); |
||||
|
try { |
||||
|
File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp", path); |
||||
|
FileUtils.copyInputStreamToFile(inputStream, tempFile); |
||||
|
return tempFile; |
||||
|
} catch (IOException e) { |
||||
|
log.error("Failed to create temp file", e); |
||||
|
throw new RuntimeException("Failed to create temp file for input stream"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Optional<File> getOtaDataFile(OtaPackageId otaPackageId) { |
||||
|
String fileName = PATH + String.format(FILE_NAME_TEMPLATE,otaPackageId.getId().toString()); |
||||
|
if (exist(fileName)) { |
||||
|
fileCleaner.updateFileUsageStatus(otaPackageId); |
||||
|
return Optional.of(new File(fileName)); |
||||
|
} |
||||
|
return Optional.empty(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public File loadToFile(OtaPackageId otaPackageId, InputStream data) { |
||||
|
if (otaPackageId == null || data == null) { |
||||
|
log.error("Received null variables: {}", otaPackageId == null ? "otaPackageId" : "data"); |
||||
|
throw new RuntimeException("Input values can not be null"); |
||||
|
} |
||||
|
files.computeIfAbsent(otaPackageId, ota -> processFileSaving(ota, data)); |
||||
|
String fileName = PATH + String.format(FILE_NAME_TEMPLATE,otaPackageId.getId().toString()); |
||||
|
return new File(fileName); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private Boolean processFileSaving(OtaPackageId otaPackageId, InputStream data) { |
||||
|
String fileName = PATH + String.format(FILE_NAME_TEMPLATE,otaPackageId.getId().toString()); |
||||
|
saveAsSystemFile(fileName, data); |
||||
|
fileCleaner.updateFileUsageStatus(otaPackageId); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private void saveAsSystemFile(String fileName, InputStream inputStream) { |
||||
|
try { |
||||
|
File file = new File(fileName); |
||||
|
FileUtils.copyInputStreamToFile(inputStream, file); |
||||
|
} catch (IOException e) { |
||||
|
log.error("Failed to copy stream to system file {}", fileName, e); |
||||
|
throw new RuntimeException("Failed to save file"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private boolean exist(String name) { |
||||
|
File file = new File(name); |
||||
|
return file.exists(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
package org.thingsboard.server.cache.ota.files; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.id.OtaPackageId; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.FileNotFoundException; |
||||
|
import java.io.InputStream; |
||||
|
import java.util.Optional; |
||||
|
|
||||
|
public interface FileCacheService { |
||||
|
File loadToFile(OtaPackageId otaPackageId, InputStream data); |
||||
|
File saveDataTemporaryFile(InputStream inputStream); |
||||
|
Optional<File> getOtaDataFile(OtaPackageId otaPackageId) throws FileNotFoundException; |
||||
|
} |
||||
@ -1,137 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2022 The Thingsboard Authors |
|
||||
* <p> |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* <p> |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* <p> |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.cache.ota.service; |
|
||||
|
|
||||
import lombok.RequiredArgsConstructor; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.apache.commons.io.FileUtils; |
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|
||||
|
|
||||
import java.io.*; |
|
||||
import java.sql.Blob; |
|
||||
import java.sql.SQLException; |
|
||||
import java.util.UUID; |
|
||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||
import java.util.concurrent.ConcurrentMap; |
|
||||
import java.util.concurrent.CountDownLatch; |
|
||||
|
|
||||
@Slf4j |
|
||||
@RequiredArgsConstructor |
|
||||
@Component |
|
||||
public class BaseFileCacheService implements FileCacheService { |
|
||||
@Value("${java.io.tmpdir}/ota/") |
|
||||
private String PATH; |
|
||||
|
|
||||
private final TemporaryFileCleaner fileCleaner; |
|
||||
private final ConcurrentMap<OtaPackageId, CountDownLatch> files = new ConcurrentHashMap<>(); |
|
||||
|
|
||||
|
|
||||
public File saveDataTemporaryFile(InputStream inputStream) { |
|
||||
File path = new File(PATH); |
|
||||
try { |
|
||||
File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp", path); |
|
||||
FileUtils.copyInputStreamToFile(inputStream, tempFile); |
|
||||
return tempFile; |
|
||||
} catch (IOException e) { |
|
||||
log.error("Failed to create temp file", e); |
|
||||
throw new RuntimeException("Failed to create temp file for input stream"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public File getOtaDataFile(OtaPackageId otaPackageId) throws FileNotFoundException { |
|
||||
String fileName = PATH + otaPackageId.getId(); |
|
||||
if (exist(fileName)) { |
|
||||
fileCleaner.updateFileUsageStatus(otaPackageId); |
|
||||
return new File(fileName); |
|
||||
} |
|
||||
throw new FileNotFoundException(); |
|
||||
} |
|
||||
|
|
||||
public File loadToFile(OtaPackageId otaPackageId, Blob data) { |
|
||||
if (otaPackageId == null || data == null) { |
|
||||
log.error("Received null variables: {}", otaPackageId == null ? "otaPackageId" : "data"); |
|
||||
throw new NullPointerException(); |
|
||||
} |
|
||||
CountDownLatch latch = files.computeIfAbsent(otaPackageId, ota -> processFileSaving(ota, data)); |
|
||||
String fileName = PATH + otaPackageId.getId(); |
|
||||
if (latch.getCount() == 0) { |
|
||||
return new File(fileName); |
|
||||
} else { |
|
||||
try { |
|
||||
latch.await(); |
|
||||
return new File(fileName); |
|
||||
} catch (InterruptedException e) { |
|
||||
log.error("Failed to save file {} to file system", fileName, e); |
|
||||
throw new RuntimeException(e); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void deleteFile(File file) { |
|
||||
try { |
|
||||
if (file.exists()) { |
|
||||
FileUtils.delete(file); |
|
||||
log.info("System file {} was deleted", file.getName()); |
|
||||
} |
|
||||
} catch (IOException e) { |
|
||||
log.error("Failed to delete file {}", file.getName(), e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public InputStream getOtaDataStream(OtaPackageId otaPackageId) throws FileNotFoundException { |
|
||||
return new FileInputStream(getOtaDataFile(otaPackageId)); |
|
||||
} |
|
||||
|
|
||||
public InputStream loadOtaData(OtaPackageId otaPackageId, Blob data) { |
|
||||
try { |
|
||||
return new FileInputStream(loadToFile(otaPackageId, data)); |
|
||||
} catch (FileNotFoundException e) { |
|
||||
log.error("Failed to upload temporary file {} to system", otaPackageId.getId(), e); |
|
||||
throw new RuntimeException(e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private CountDownLatch processFileSaving(OtaPackageId otaPackageId, Blob data) { |
|
||||
CountDownLatch latch = new CountDownLatch(1); |
|
||||
try { |
|
||||
InputStream binaryStream = data.getBinaryStream(); |
|
||||
String fileName = PATH + otaPackageId.getId(); |
|
||||
saveAsSystemFile(fileName, binaryStream); |
|
||||
latch.countDown(); |
|
||||
return latch; |
|
||||
} catch (SQLException e) { |
|
||||
log.error("Failed to get binary data from otaPackage {}", otaPackageId, e); |
|
||||
throw new RuntimeException("Failed to get binary data from database"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void saveAsSystemFile(String fileName, InputStream inputStream) { |
|
||||
try { |
|
||||
File file = new File(fileName); |
|
||||
FileUtils.copyInputStreamToFile(inputStream, file); |
|
||||
} catch (IOException e) { |
|
||||
log.error("Failed to copy stream to system file {}", fileName, e); |
|
||||
throw new RuntimeException("Failed to save file"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private boolean exist(String name) { |
|
||||
File file = new File(name); |
|
||||
return file.exists(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
package org.thingsboard.server.cache.ota.service; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|
||||
|
|
||||
import java.io.File; |
|
||||
import java.io.FileNotFoundException; |
|
||||
import java.io.InputStream; |
|
||||
import java.sql.Blob; |
|
||||
|
|
||||
public interface FileCacheService { |
|
||||
void deleteFile(File file); |
|
||||
InputStream getOtaDataStream(OtaPackageId otaPackageId) throws FileNotFoundException ; |
|
||||
InputStream loadOtaData(OtaPackageId otaPackageId, Blob data); |
|
||||
File loadToFile(OtaPackageId otaPackageId, Blob data); |
|
||||
File saveDataTemporaryFile(InputStream inputStream); |
|
||||
File getOtaDataFile(OtaPackageId otaPackageId) throws FileNotFoundException; |
|
||||
} |
|
||||
Loading…
Reference in new issue