1 /*
2  * Copyright (C) 2023-2024 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 #include "medialibrary_kvstore_manager.h"
17 
18 #include <atomic>
19 #include <shared_mutex>
20 
21 #include "medialibrary_errno.h"
22 #include "media_log.h"
23 
24 using namespace OHOS::DistributedKv;
25 namespace OHOS::Media {
26 std::mutex MediaLibraryKvStoreManager::mutex_;
27 Utils::Timer MediaLibraryKvStoreManager::timer_("close_kvStore");
28 std::atomic<uint32_t> MediaLibraryKvStoreManager::insertImageCount_ = 0;
29 uint32_t MediaLibraryKvStoreManager::timerId_ = 0;
30 
~MediaLibraryKvStoreManager()31 MediaLibraryKvStoreManager::~MediaLibraryKvStoreManager()
32 {
33     timer_.Unregister(timerId_);
34     timer_.Shutdown();
35     timerId_ = 0;
36 }
37 
InitKvStore(const KvStoreRoleType & roleType,const KvStoreValueType & valueType)38 int32_t MediaLibraryKvStoreManager::InitKvStore(const KvStoreRoleType &roleType, const KvStoreValueType &valueType)
39 {
40     std::lock_guard<std::mutex> lock(mutex_);
41     KvStoreSharedPtr ptr;
42     if (kvStoreMap_.Find(valueType, ptr)) {
43         return E_OK;
44     }
45 
46     std::string baseDir = "";
47     if (roleType == KvStoreRoleType::OWNER) {
48         baseDir = KV_STORE_OWNER_DIR;
49     } else if (roleType == KvStoreRoleType::VISITOR) {
50         baseDir = KV_STORE_VISITOR_DIR;
51     } else {
52         MEDIA_ERR_LOG("invalid role type");
53         return E_ERR;
54     }
55 
56     ptr = std::make_shared<MediaLibraryKvStore>();
57     int32_t status = ptr->Init(roleType, valueType, baseDir);
58     if (status != E_OK) {
59         MEDIA_ERR_LOG("init kvStore failed, status %{public}d", status);
60         return status;
61     }
62     kvStoreMap_.Insert(valueType, ptr);
63     return E_OK;
64 }
65 
GetKvStore(const KvStoreRoleType & roleType,const KvStoreValueType & valueType)66 std::shared_ptr<MediaLibraryKvStore> MediaLibraryKvStoreManager::GetKvStore(
67     const KvStoreRoleType &roleType, const KvStoreValueType &valueType)
68 {
69     RegisterTimer(roleType, valueType);
70     KvStoreSharedPtr ptr;
71     if (kvStoreMap_.Find(valueType, ptr)) {
72         return ptr;
73     }
74 
75     InitKvStore(roleType, valueType);
76     kvStoreMap_.Find(valueType, ptr);
77     return ptr;
78 }
79 
CloseAllKvStore()80 void MediaLibraryKvStoreManager::CloseAllKvStore()
81 {
82     std::lock_guard<std::mutex> lock(mutex_);
83     if (kvStoreMap_.IsEmpty()) {
84         return;
85     }
86 
87     kvStoreMap_.Clear();
88 }
89 
CloseKvStore(const KvStoreValueType & valueType)90 bool MediaLibraryKvStoreManager::CloseKvStore(const KvStoreValueType &valueType)
91 {
92     std::lock_guard<std::mutex> lock(mutex_);
93     KvStoreSharedPtr ptr;
94     if (!kvStoreMap_.Find(valueType, ptr)) {
95         return false;
96     }
97 
98     if (ptr != nullptr && ptr->Close()) {
99         kvStoreMap_.Erase(valueType);
100         MEDIA_INFO_LOG("CloseKvStore success, valueType %{public}d", valueType);
101         return true;
102     }
103     return false;
104 }
105 
RegisterTimer(const KvStoreRoleType & roleType,const KvStoreValueType & valueType)106 void MediaLibraryKvStoreManager::RegisterTimer(const KvStoreRoleType &roleType, const KvStoreValueType &valueType)
107 {
108     if (roleType != KvStoreRoleType::OWNER) {
109         return;
110     }
111 
112     Utils::Timer::TimerCallback timerCallback = [this]() {
113         MEDIA_INFO_LOG("KvStore timerCallback, CloseAllKvStore");
114         insertImageCount_ = 0;
115         CloseAllKvStore();
116     };
117 
118     std::lock_guard<std::mutex> lock(mutex_);
119     if (timerId_ == 0) {
120         MEDIA_INFO_LOG("KvStore timer Setup");
121         timer_.Setup();
122     }
123 
124     if (insertImageCount_ == 0 || insertImageCount_ >= KVSTORE_INSERT_COUNT) {
125         timer_.Unregister(timerId_);
126         insertImageCount_ = 0;
127         timerId_ = timer_.Register(timerCallback, CLOSE_KVSTORE_TIME_INTERVAL, true);
128         MEDIA_INFO_LOG("KvStore timer Restart");
129     }
130     insertImageCount_++;
131 }
132 
InitMonthAndYearKvStore(const KvStoreRoleType & roleType)133 bool MediaLibraryKvStoreManager::InitMonthAndYearKvStore(const KvStoreRoleType& roleType)
134 {
135     if (roleType != KvStoreRoleType::OWNER) {
136         return false;
137     }
138     if (GetKvStore(roleType, KvStoreValueType::MONTH_ASTC) == nullptr ||
139         GetKvStore(roleType, KvStoreValueType::YEAR_ASTC) == nullptr) {
140         return false;
141     }
142     return true;
143 }
144 
IsKvStoreValid(const KvStoreValueType & valueType)145 bool MediaLibraryKvStoreManager::IsKvStoreValid(const KvStoreValueType &valueType)
146 {
147     KvStoreSharedPtr ptr;
148     if (kvStoreMap_.Find(valueType, ptr)) {
149         return true;
150     }
151 
152     ptr = std::make_shared<MediaLibraryKvStore>();
153     int32_t status = ptr->Init(KvStoreRoleType::OWNER, valueType, KV_STORE_OWNER_DIR);
154     if (status == static_cast<int32_t>(Status::DATA_CORRUPTED)) {
155         MEDIA_ERR_LOG("KvStore is invalid and needs to be deleted, status %{public}d, type %{public}d",
156             status, valueType);
157         return false;
158     }
159 
160     if (status == E_OK && ptr != nullptr) {
161         ptr->Close();
162     }
163     return true;
164 }
165 
RebuildInvalidKvStore(const KvStoreValueType & valueType)166 int32_t MediaLibraryKvStoreManager::RebuildInvalidKvStore(const KvStoreValueType &valueType)
167 {
168     std::lock_guard<std::mutex> lock(mutex_);
169     KvStoreSharedPtr ptr = std::make_shared<MediaLibraryKvStore>();
170     return ptr->RebuildKvStore(valueType, KV_STORE_OWNER_DIR);
171 }
172 
GetSingleKvStore(const KvStoreRoleType & roleType,const std::string & storeId,const std::string & baseDir)173 std::shared_ptr<MediaLibraryKvStore> MediaLibraryKvStoreManager::GetSingleKvStore(
174     const KvStoreRoleType &roleType, const std::string &storeId, const std::string &baseDir)
175 {
176     KvStoreSharedPtr ptr = std::make_shared<MediaLibraryKvStore>();
177     int32_t status = ptr->InitSingleKvstore(roleType, storeId, baseDir);
178     if (status != E_OK) {
179         MEDIA_ERR_LOG("Init kvStore failed, status %{public}d", status);
180         return nullptr;
181     }
182     return ptr;
183 }
184 
CloneKvStore(const std::string & oldKvStoreId,const std::string & oldBaseDir,const std::string & newKvStoreId,const std::string & newBaseDir)185 int32_t MediaLibraryKvStoreManager::CloneKvStore(const std::string &oldKvStoreId, const std::string &oldBaseDir,
186     const std::string &newKvStoreId, const std::string &newBaseDir)
187 {
188     KvStoreSharedPtr oldKvStore = std::make_shared<MediaLibraryKvStore>();
189     int32_t status = oldKvStore->InitSingleKvstore(KvStoreRoleType::OWNER, oldKvStoreId, oldBaseDir);
190     if (status != E_OK) {
191         MEDIA_ERR_LOG("Init old kvStore failed, status %{public}d", status);
192         return status;
193     }
194 
195     KvStoreSharedPtr newKvStore = std::make_shared<MediaLibraryKvStore>();
196     status = newKvStore->InitSingleKvstore(KvStoreRoleType::OWNER, newKvStoreId, newBaseDir);
197     if (status != E_OK) {
198         MEDIA_ERR_LOG("Init new kvStore failed, status %{public}d", status);
199         return status;
200     }
201 
202     status = oldKvStore->PutAllValueToNewKvStore(newKvStore);
203     if (status != E_OK) {
204         MEDIA_ERR_LOG("Clone kvstore failed, status %{public}d", status);
205         return status;
206     }
207     return E_OK;
208 }
209 } // namespace OHOS::Media