• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 #include <libxml/parser.h>
16 #include <libxml/tree.h>
17 
18 #include "geo_knowledge_restore.h"
19 
20 #include "backup_database_utils.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "result_set_utils.h"
25 #include "locale_config.h"
26 #include "upgrade_restore_task_report.h"
27 #include "medialibrary_unistore_manager.h"
28 
29 namespace OHOS::Media {
30 const int32_t PAGE_SIZE = 200;
31 const int32_t UPDATE_GEO = 3;
32 const string NOT_MATCH = "NOT MATCH";
33 const string LATITUDE = "latitude";
34 const string LONGITUDE = "longitude";
35 const string LOCATION_KEY = "location_key";
36 const string LANGUAGE = "language";
37 const string COUNTRY = "country";
38 const string ADMIN_AREA = "admin_area";
39 const string SUB_ADMIN_AREA = "sub_admin_area";
40 const string LOCALITY = "locality";
41 const string SUB_LOCALITY = "sub_locality";
42 const string THOROUGHFARE = "thoroughfare";
43 const string SUB_THOROUGHFARE = "sub_thoroughfare";
44 const string FEATURE_NAME = "feature_name";
45 const string ADDRESS_DESCRIPTION = "address_description";
46 const string FILE_ID = "file_id";
47 const string DATA = "data";
48 const string SINGLE_CH = "zh-Hans";
49 const string SINGLE_EN = "en-Latn-US";
50 const string DOUBLE_CH = "zh";
51 const string DOUBLE_EN = "en";
52 const int32_t GEO_STATUS_SUCCESS = 1;
53 constexpr double DOUBLE_EPSILON = 1e-15;
54 
55 // LCOV_EXCL_START
Init(int32_t sceneCode,std::string taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::shared_ptr<NativeRdb::RdbStore> galleryRdb)56 void GeoKnowledgeRestore::Init(int32_t sceneCode, std::string taskId,
57     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb, std::shared_ptr<NativeRdb::RdbStore> galleryRdb)
58 {
59     sceneCode_ = sceneCode;
60     taskId_ = taskId;
61     mediaLibraryRdb_ = mediaLibraryRdb;
62     galleryRdb_ = galleryRdb;
63     batchCnt_ = 0;
64     successInsertCnt_ = 0;
65     successUpdateCnt_ = 0;
66     failInsertCnt_ = 0;
67     failUpdateCnt_ = 0;
68     systemLanguage_ = Global::I18n::LocaleConfig::GetSystemLanguage();
69 }
70 
RestoreGeo(const std::unordered_map<int32_t,PhotoInfo> & photoInfoMap)71 void GeoKnowledgeRestore::RestoreGeo(const std::unordered_map<int32_t, PhotoInfo> &photoInfoMap)
72 {
73     CHECK_AND_RETURN_LOG(galleryRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr");
74     GetGeoKnowledgeInfos();
75     RestoreMaps(photoInfoMap);
76     ReportGeoRestoreTask();
77 }
78 
GetGeoKnowledgeInfos()79 void GeoKnowledgeRestore::GetGeoKnowledgeInfos()
80 {
81     const std::string QUERY_SQL = "SELECT " + LATITUDE + ", " + LONGITUDE + ", " + LOCATION_KEY + ", " + LANGUAGE + ", "
82         + COUNTRY + ", " + ADMIN_AREA + ", " + SUB_ADMIN_AREA + ", " + LOCALITY + ", " + SUB_LOCALITY + ", "
83         + THOROUGHFARE + ", " + SUB_THOROUGHFARE + ", " + FEATURE_NAME + " "
84         "FROM t_geo_knowledge WHERE COALESCE(" + LANGUAGE + ", '') <> ' ' AND rowid > ? ORDER BY rowid LIMIT ?";
85     int rowCount = 0;
86     int offset = 0;
87     do {
88         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
89         auto resultSet = galleryRdb_->QuerySql(QUERY_SQL, params);
90         CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
91         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
92             GeoKnowledgeInfo info;
93             info.latitude = GetDoubleVal(LATITUDE, resultSet);
94             info.longitude = GetDoubleVal(LONGITUDE, resultSet);
95             info.locationKey = GetInt64Val(LOCATION_KEY, resultSet);
96             info.language = GetStringVal(LANGUAGE, resultSet);
97             info.country = GetStringVal(COUNTRY, resultSet);
98             info.adminArea = GetStringVal(ADMIN_AREA, resultSet);
99             info.subAdminArea = GetStringVal(SUB_ADMIN_AREA, resultSet);
100             info.locality = GetStringVal(LOCALITY, resultSet);
101             info.subLocality = GetStringVal(SUB_LOCALITY, resultSet);
102             info.thoroughfare = GetStringVal(THOROUGHFARE, resultSet);
103             info.subThoroughfare = GetStringVal(SUB_THOROUGHFARE, resultSet);
104             info.featureName = GetStringVal(FEATURE_NAME, resultSet);
105             albumInfos_.emplace_back(info);
106         }
107         resultSet->GetRowCount(rowCount);
108         offset += PAGE_SIZE;
109         resultSet->Close();
110     } while (rowCount > 0);
111 }
112 
RestoreMaps(const std::unordered_map<int32_t,PhotoInfo> & photoInfoMap)113 void GeoKnowledgeRestore::RestoreMaps(const std::unordered_map<int32_t, PhotoInfo> &photoInfoMap)
114 {
115     if (mediaLibraryRdb_ == nullptr || galleryRdb_ == nullptr) {
116         MEDIA_ERR_LOG("rdbStore is nullptr");
117         batchCnt_ = 0;
118         return;
119     }
120     std::string querySql = "SELECT _id, latitude, longitude FROM gallery_media "
121         "WHERE (ABS(latitude) >= 1e-15 OR ABS(longitude) >= 1e-15) AND _id > ? ORDER BY _id ASC LIMIT ?;";
122     int rowCount = 0;
123     int offset = 0;
124     do {
125         std::vector<std::string> fileIds;
126         std::vector<NativeRdb::ValuesBucket> values;
127         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
128         auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, querySql, params);
129         CHECK_AND_RETURN(resultSet != nullptr);
130         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
131             GeoMapInfo geoMapInfo;
132             geoMapInfo.fileIdOld = GetInt32Val("_id", resultSet);
133             offset = geoMapInfo.fileIdOld;
134             CHECK_AND_CONTINUE(photoInfoMap.find(geoMapInfo.fileIdOld) != photoInfoMap.end());
135             geoMapInfo.photoInfo = photoInfoMap.at(geoMapInfo.fileIdOld);
136             geoMapInfo.latitude = GetDoubleVal("latitude", resultSet);
137             geoMapInfo.longitude = GetDoubleVal("longitude", resultSet);
138             std::string fileIdString = UpdateMapInsertValues(values, geoMapInfo);
139             CHECK_AND_EXECUTE(fileIdString == NOT_MATCH, fileIds.push_back(fileIdString));
140         }
141         resultSet->GetRowCount(rowCount);
142         resultSet->Close();
143         UpdateMaps(values, fileIds);
144     } while (rowCount == PAGE_SIZE);
145 }
146 
UpdateMaps(std::vector<NativeRdb::ValuesBucket> & values,std::vector<std::string> & fileIds)147 void GeoKnowledgeRestore::UpdateMaps(std::vector<NativeRdb::ValuesBucket> &values, std::vector<std::string> &fileIds)
148 {
149     int64_t rowNum = 0;
150     int32_t errCodeGeo = BatchInsertWithRetry("tab_analysis_geo_knowledge", values, rowNum);
151     if (errCodeGeo != E_OK) {
152         MEDIA_ERR_LOG("GeoKnowledge: RestoreMaps insert fail");
153         ErrorInfo errorInfo(RestoreError::INSERT_FAILED, values.size(),
154             "errCodeGeo: " + std::to_string(errCodeGeo), "GeoKnowledge: RestoreMaps insert fail");
155         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
156         failInsertCnt_ += batchCnt_;
157         batchCnt_ = 0;
158         return;
159     }
160     successInsertCnt_ += batchCnt_;
161     int32_t errCodeUpdate = BatchUpdate("tab_analysis_total", fileIds);
162     if (errCodeUpdate != E_OK) {
163         MEDIA_ERR_LOG("AnalysisTotal: RestoreMaps update fail");
164         ErrorInfo errorInfo(RestoreError::UPDATE_FAILED, values.size(),
165             "errCodeUpdate: " + std::to_string(errCodeUpdate), "AnalysisTotal: RestoreMaps update fail");
166         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
167         failUpdateCnt_ += batchCnt_;
168         batchCnt_ = 0;
169         return;
170     }
171     successUpdateCnt_ += batchCnt_;
172     batchCnt_ = 0;
173 }
174 
UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> & values,const GeoMapInfo & geoMapInfo)175 std::string GeoKnowledgeRestore::UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> &values,
176     const GeoMapInfo &geoMapInfo)
177 {
178     // no need restore or info missing
179     CHECK_AND_RETURN_RET(geoMapInfo.photoInfo.fileIdNew > 0, NOT_MATCH);
180     return UpdateByGeoLocation(values, geoMapInfo);
181 }
182 
UpdateByGeoLocation(std::vector<NativeRdb::ValuesBucket> & values,const GeoMapInfo & geoMapInfo)183 std::string GeoKnowledgeRestore::UpdateByGeoLocation(
184     std::vector<NativeRdb::ValuesBucket> &values, const GeoMapInfo &geoMapInfo)
185 {
186     std::string language = systemLanguage_;
187     CHECK_AND_EXECUTE(!language.empty(), language = DOUBLE_CH);
188     language = (language == SINGLE_EN) ? DOUBLE_EN : DOUBLE_CH;
189 
190     auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
191         [geoMapInfo, language](const GeoKnowledgeInfo& info) {
192             return std::fabs(info.latitude - geoMapInfo.latitude) < 0.0001
193         && std::fabs(info.longitude - geoMapInfo.longitude) < 0.0001 && info.language == language;
194         });
195     CHECK_AND_RETURN_RET(it != albumInfos_.end(), NOT_MATCH);
196     values.push_back(GetMapInsertValue(it, geoMapInfo.photoInfo.fileIdNew));
197     batchCnt_++;
198     return std::to_string(geoMapInfo.photoInfo.fileIdNew);
199 }
200 
GetMapInsertValue(std::vector<GeoKnowledgeInfo>::iterator it,int32_t fileId)201 NativeRdb::ValuesBucket GeoKnowledgeRestore::GetMapInsertValue(std::vector<GeoKnowledgeInfo>::iterator it,
202     int32_t fileId)
203 {
204     NativeRdb::ValuesBucket value;
205     value.PutDouble(LATITUDE, it->latitude);
206     value.PutDouble(LONGITUDE, it->longitude);
207     value.PutLong(LOCATION_KEY, it->locationKey);
208     value.PutString(COUNTRY, it->country);
209     value.PutString(ADMIN_AREA, it->adminArea);
210     value.PutString(SUB_ADMIN_AREA, it->subAdminArea);
211     value.PutString(LOCALITY, it->locality);
212     value.PutString(SUB_LOCALITY, it->subLocality);
213     value.PutString(THOROUGHFARE, it->thoroughfare);
214     value.PutString(SUB_THOROUGHFARE, it->subThoroughfare);
215     value.PutString(FEATURE_NAME, it->featureName);
216     value.PutInt(FILE_ID, fileId);
217     if (it->adminArea == it->locality) {
218         value.PutString(ADDRESS_DESCRIPTION, it->locality + it->subLocality + it->thoroughfare
219         + it->subThoroughfare + it->featureName);
220     } else {
221         value.PutString(ADDRESS_DESCRIPTION, it->adminArea + it->subAdminArea + it->locality
222         + it->subLocality + it->thoroughfare + it->subThoroughfare + it->featureName);
223     }
224 
225     if (it->language == DOUBLE_CH) {
226         value.PutString(LANGUAGE, SINGLE_CH);
227         return value;
228     }
229 
230     value.PutString(LANGUAGE, SINGLE_EN);
231     return value;
232 }
233 
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)234 int32_t GeoKnowledgeRestore::BatchInsertWithRetry(const std::string &tableName,
235     std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
236 {
237     CHECK_AND_RETURN_RET(!values.empty(), E_OK);
238     int32_t errCode = E_ERR;
239     TransactionOperations trans{ __func__ };
240     trans.SetBackupRdbStore(mediaLibraryRdb_);
241     std::function<int(void)> func = [&]()->int {
242         errCode = trans.BatchInsert(rowNum, tableName, values);
243         CHECK_AND_PRINT_LOG(errCode == E_OK, "InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.",
244             errCode, (long)rowNum);
245         return errCode;
246     };
247     errCode = trans.RetryTrans(func, true);
248     CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
249     return errCode;
250 }
251 
BatchUpdate(const std::string & tableName,std::vector<std::string> & fileIds)252 int32_t GeoKnowledgeRestore::BatchUpdate(const std::string &tableName, std::vector<std::string> &fileIds)
253 {
254     NativeRdb::RdbPredicates updatePredicates(tableName);
255     updatePredicates.In(FILE_ID, fileIds);
256     NativeRdb::ValuesBucket rdbValues;
257     rdbValues.PutInt("geo", UPDATE_GEO);
258     int32_t changedRows = -1;
259     int32_t errCode = E_OK;
260     errCode = mediaLibraryRdb_->Update(changedRows, rdbValues, updatePredicates);
261     CHECK_AND_PRINT_LOG(errCode == E_OK, "Database update failed, errCode = %{public}d", errCode);
262     return errCode;
263 }
264 
ReportGeoRestoreTask()265 void GeoKnowledgeRestore::ReportGeoRestoreTask()
266 {
267     MEDIA_INFO_LOG("GeoKnowledge Insert successInsertCnt_: %{public}d, failInsertCnt_: %{public}d, "
268         "AnalysisTotal Update successUpdateCnt_: %{public}d, failUpdateCnt_: %{public}d, "
269         "Current System Language: %{public}s",
270         successInsertCnt_.load(), failInsertCnt_.load(), successUpdateCnt_.load(),
271         failUpdateCnt_.load(), systemLanguage_.c_str());
272     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
273         .Report("GeoKnowledge Restore", std::to_string(GEO_STATUS_SUCCESS),
274         "successInsertCnt_: " + std::to_string(successInsertCnt_) +
275         ", failInsertCnt_: " + std::to_string(failInsertCnt_) +
276         ", successUpdateCnt_: " + std::to_string(successUpdateCnt_) +
277         ", failUpdateCnt_: " + std::to_string(failUpdateCnt_) +
278         ", Current System Language: " + systemLanguage_);
279 }
280 // LCOV_EXCL_STOP
281 } // namespace OHOS::Media