1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 //! This module provides interfaces for database management.
17 //! Databases are isolated based on users and protected by locks.
18
19 use std::{fs, path::Path};
20
21 use asset_common::{CallingInfo, OwnerType, OWNER_INFO_SEPARATOR};
22 use asset_definition::{log_throw_error, ErrCode, Extension, Result, Value};
23 use asset_file_operator::common::DB_SUFFIX;
24 use asset_log::logi;
25 use asset_utils::hasher;
26
27 use crate::{
28 database::{
29 fmt_backup_path, fmt_de_db_path_with_name, get_db, get_db_by_type, get_split_db_lock_by_user_id, Database,
30 CE_ROOT_PATH, DE_ROOT_PATH, OLD_DB_NAME,
31 },
32 types::{column, DbMap, QueryOptions, DB_UPGRADE_VERSION_V3},
33 };
34
35 const MINIM_OWNER_INFO_LEN: usize = 3;
36 const REMOVE_INDEX: usize = 2;
37 static MAX_BATCH_NUM: u32 = 100;
38
39 #[inline(always)]
fmt_old_de_db_path(user_id: i32) -> String40 pub(crate) fn fmt_old_de_db_path(user_id: i32) -> String {
41 format!("{}/{}/asset.db", DE_ROOT_PATH, user_id)
42 }
43
check_old_db_exist(user_id: i32) -> bool44 fn check_old_db_exist(user_id: i32) -> bool {
45 let path_str = fmt_old_de_db_path(user_id);
46 let path = Path::new(&path_str);
47 path.exists()
48 }
49
to_hex(bytes: &Vec<u8>) -> Vec<u8>50 fn to_hex(bytes: &Vec<u8>) -> Vec<u8> {
51 let bytes_len = bytes.len();
52 let scale_capacity = 2;
53 let mut hex_vec = Vec::with_capacity(bytes_len * scale_capacity);
54 for byte in bytes.iter() {
55 hex_vec.extend(format!("{:02x}", byte).as_bytes());
56 }
57 hex_vec
58 }
59
60 /// Use owner_type and owner_info construct db name.
construct_splited_db_name(calling_info: &CallingInfo, is_ce: bool) -> Result<String>61 pub fn construct_splited_db_name(calling_info: &CallingInfo, is_ce: bool) -> Result<String> {
62 let mut res: String = match calling_info.owner_type_enum() {
63 OwnerType::HapGroup => match (calling_info.developer_id(), calling_info.group_id()) {
64 (Some(developer_id), Some(group_id)) => format!(
65 "Group_{}_{}",
66 String::from_utf8_lossy(developer_id).trim_end_matches('\0'),
67 String::from_utf8_lossy(&to_hex(&hasher::sha256(true, group_id)))
68 ),
69 _ => return log_throw_error!(ErrCode::DatabaseError, "[FATAL]Wrong queried owner group info."),
70 },
71 OwnerType::Hap => {
72 let owner_info_string = String::from_utf8_lossy(calling_info.owner_info()).to_string();
73 let split_owner_info: Vec<&str> = owner_info_string.split(OWNER_INFO_SEPARATOR).collect();
74 if split_owner_info.len() < MINIM_OWNER_INFO_LEN || split_owner_info.last().is_none() {
75 return log_throw_error!(ErrCode::DatabaseError, "[FATAL]Wrong queried owner info!");
76 }
77 let app_index = split_owner_info.last().unwrap();
78 let mut split_owner_info_mut = split_owner_info.clone();
79 for _ in 0..REMOVE_INDEX {
80 split_owner_info_mut.pop();
81 }
82 let owner_info = split_owner_info_mut.join("_").clone();
83 format!("Hap_{}_{}", owner_info, app_index)
84 },
85 OwnerType::Native => format!("Native_{}", String::from_utf8_lossy(calling_info.owner_info())),
86 };
87 if is_ce {
88 res = format!("enc_{}", res)
89 }
90 Ok(res)
91 }
92
get_db_before_split(user_id: i32) -> Result<Database>93 fn get_db_before_split(user_id: i32) -> Result<Database> {
94 let db_path = fmt_de_db_path_with_name(user_id, OLD_DB_NAME);
95 get_db_by_type(user_id, OLD_DB_NAME, db_path, DB_UPGRADE_VERSION_V3, None)
96 }
97
get_value_from_db_map(db_map: &DbMap, key: &str) -> Result<Value>98 fn get_value_from_db_map(db_map: &DbMap, key: &str) -> Result<Value> {
99 match db_map.get(key) {
100 Some(value) => Ok(value.clone()),
101 _ => log_throw_error!(ErrCode::DatabaseError, "[FATAL]Get value from {} failed.", key),
102 }
103 }
104
remove_old_db(user_id: i32) -> Result<()>105 fn remove_old_db(user_id: i32) -> Result<()> {
106 let mut remove_db_files = vec![];
107 let path = fmt_de_db_path_with_name(user_id, OLD_DB_NAME);
108 remove_db_files.push(path.clone());
109 remove_db_files.push(fmt_backup_path(path.as_str()));
110 for file_path in &remove_db_files {
111 fs::remove_file(file_path)?;
112 }
113 Ok(())
114 }
115
get_new_db(user_id: i32, info_map: &DbMap) -> Result<Database>116 fn get_new_db(user_id: i32, info_map: &DbMap) -> Result<Database> {
117 // 1.1 construct db name
118 let owner_type = OwnerType::try_from(info_map.get_num_attr(&column::OWNER_TYPE)?.to_owned())?;
119 let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
120 let calling_info = CallingInfo::new(user_id, owner_type, owner_info.to_vec(), None);
121 let new_db_name = construct_splited_db_name(&calling_info, false)?;
122 // 1.2 construct new db
123 let db_path = fmt_de_db_path_with_name(user_id, &new_db_name);
124 get_db_by_type(user_id, &new_db_name, db_path, DB_UPGRADE_VERSION_V3, None)
125 }
126
127 /// Trigger upgrade of database version and renaming secret key alias.
trigger_db_upgrade(user_id: i32, is_ce: bool) -> Result<()>128 pub fn trigger_db_upgrade(user_id: i32, is_ce: bool) -> Result<()> {
129 let path = if is_ce {
130 format!("{}/{}/asset_service", CE_ROOT_PATH, user_id)
131 } else {
132 format!("{}/{}", DE_ROOT_PATH, user_id)
133 };
134 for entry in fs::read_dir(path)? {
135 let entry = entry?;
136 if entry.file_name().to_string_lossy().ends_with(DB_SUFFIX) {
137 if let Some(file_name_stem) = entry.file_name().to_string_lossy().strip_suffix(DB_SUFFIX) {
138 let _ = get_db(user_id, file_name_stem, is_ce)?;
139 }
140 }
141 }
142 Ok(())
143 }
144
construct_old_query_condition(info_map: &DbMap) -> Result<DbMap>145 fn construct_old_query_condition(info_map: &DbMap) -> Result<DbMap> {
146 let mut old_data_query_condition = DbMap::new();
147 let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
148 old_data_query_condition.insert(column::OWNER, Value::Bytes(owner_info.clone()));
149 Ok(old_data_query_condition)
150 }
151
calculate_batch_split_times(old_data_query_condition: &DbMap, old_db: &mut Database) -> Result<u32>152 fn calculate_batch_split_times(old_data_query_condition: &DbMap, old_db: &mut Database) -> Result<u32> {
153 let query_times = (old_db.query_data_count(old_data_query_condition)? + MAX_BATCH_NUM - 1) / MAX_BATCH_NUM;
154 Ok(query_times)
155 }
156
migrate_data( old_db: &mut Database, new_db: &mut Database, split_time: u32, old_data_query_condition: &DbMap, ) -> Result<()>157 fn migrate_data(
158 old_db: &mut Database,
159 new_db: &mut Database,
160 split_time: u32,
161 old_data_query_condition: &DbMap,
162 ) -> Result<()> {
163 // 3.1 query data in old db
164 let query_options = QueryOptions { offset: None, limit: Some(MAX_BATCH_NUM), order_by: None, order: None };
165
166 let old_data_vec = old_db.query_datas(&vec![], old_data_query_condition, Some(&query_options), false)?;
167 // 3.2 insert data in new db
168 for data in &old_data_vec {
169 let mut condition = DbMap::new();
170 condition.insert(column::ALIAS, get_value_from_db_map(data, column::ALIAS)?);
171 condition.insert(column::OWNER, get_value_from_db_map(data, column::OWNER)?);
172 condition.insert(column::OWNER_TYPE, get_value_from_db_map(data, column::OWNER_TYPE)?);
173 let mut data_clone = data.clone();
174 data_clone.remove(column::ID);
175 new_db.replace_datas(&condition, false, &data_clone)?;
176 // 3.3 remove data in old db
177 old_db.delete_datas(&condition, None, false)?;
178 }
179 logi!("[INFO]Upgrade [{}] [{}]times", new_db.get_db_name(), split_time);
180 Ok(())
181 }
182
split_db(user_id: i32) -> Result<()>183 fn split_db(user_id: i32) -> Result<()> {
184 // 1. open old db
185 let mut old_db = get_db_before_split(user_id)?;
186
187 // 2. get split db info
188 let empty_condition = DbMap::new();
189 let owner_info_db_list =
190 old_db.query_datas(&vec![column::OWNER_TYPE, column::OWNER], &empty_condition, None, false)?;
191 for info_map in &owner_info_db_list {
192 // 1. get new db
193 let mut new_db = get_new_db(user_id, info_map)?;
194 // 2. batch insert data from old db to new db.
195 let old_data_query_condition = construct_old_query_condition(info_map)?;
196 for split_time in 0..calculate_batch_split_times(&old_data_query_condition, &mut old_db)? {
197 migrate_data(&mut old_db, &mut new_db, split_time, &old_data_query_condition)?;
198 }
199 logi!("[INFO]Upgrade [{}] success!", new_db.get_db_name());
200 }
201 logi!("[INFO]Upgrade all db success!");
202 remove_old_db(user_id)?;
203 Ok(())
204 }
205
206 /// check db need split or not. If needed, split it by owner.
check_and_split_db(user_id: i32) -> Result<()>207 pub fn check_and_split_db(user_id: i32) -> Result<()> {
208 if check_old_db_exist(user_id) {
209 let _lock = get_split_db_lock_by_user_id(user_id).mtx.lock().unwrap();
210 if check_old_db_exist(user_id) {
211 logi!("[INFO]Start splitting db.");
212 split_db(user_id)?;
213 }
214 }
215 trigger_db_upgrade(user_id, false)?;
216 Ok(())
217 }
218