From ecea0781bfcf4c6f5ddc8d2d6e6b86ddea84e20e Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Thu, 13 Jan 2022 13:26:28 +0900 Subject: [PATCH] Refactor pkgmgr-info - Separace Cache logic from DBHandleProvider. - Change function name for readability. - Add UID setter/getter function at AbstractRequestHandler to provide uid at CacheRequestHandler. - Apply early-return policy to reduce indentation. Change-Id: I1f2bc50247178a70c2268c81d2f2fc5bd2e75b2c Signed-off-by: Junghyun Yeon --- src/manager/pkginfo_manager.cc | 6 +- src/server/cache_flag.hh | 81 ------- src/server/database/appinfo_db_handler.cc | 70 +++--- src/server/database/appinfo_db_handler.hh | 1 - src/server/database/cache.cc | 265 +++++++++++++++++++++ src/server/database/cache.hh | 94 ++++++++ src/server/database/cache_db_handler.cc | 40 +++- src/server/database/cache_provider.cc | 128 ++++++++++ src/server/database/cache_provider.hh | 71 ++++++ src/server/database/db_handle_provider.cc | 177 +------------- src/server/database/db_handle_provider.hh | 17 -- src/server/database/pkg_get_db_handler.cc | 62 +++-- src/server/database/pkg_get_db_handler.hh | 1 - src/server/database/query_handler.cc | 4 +- .../request_handler/abstract_request_handler.cc | 8 + .../request_handler/abstract_request_handler.hh | 3 + .../create_cache_request_handler.cc | 3 +- src/server/runner.cc | 45 +++- src/server/worker_thread.cc | 6 +- 19 files changed, 717 insertions(+), 365 deletions(-) delete mode 100644 src/server/cache_flag.hh create mode 100644 src/server/database/cache.cc create mode 100644 src/server/database/cache.hh create mode 100644 src/server/database/cache_provider.cc create mode 100644 src/server/database/cache_provider.hh diff --git a/src/manager/pkginfo_manager.cc b/src/manager/pkginfo_manager.cc index 2b72d05..d88d2a3 100644 --- a/src/manager/pkginfo_manager.cc +++ b/src/manager/pkginfo_manager.cc @@ -120,9 +120,10 @@ extern "C" EXPORT_API int _pkginfo_get_packages(uid_t uid, LOG(DEBUG) << "No packages meets given condition for user " << uid; return PMINFO_R_ENOENT; } - for (auto& pkginfo : result_list) + for (auto& pkginfo : result_list) { g_hash_table_insert(packages, reinterpret_cast(pkginfo->package), reinterpret_cast(pkginfo.get())); + } return PMINFO_R_OK; } @@ -186,9 +187,10 @@ extern "C" EXPORT_API int _appinfo_get_applications(uid_t uid, std::static_pointer_cast(ptr)); std::vector> result_list = return_parcel->ExtractAppInfo(); - for (auto& app : result_list) + for (auto& app : result_list) { g_hash_table_insert(packages, reinterpret_cast(app->appid), reinterpret_cast(app.get())); + } return PMINFO_R_OK; } diff --git a/src/server/cache_flag.hh b/src/server/cache_flag.hh deleted file mode 100644 index 67aa9a0..0000000 --- a/src/server/cache_flag.hh +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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. - */ - -#ifndef CACHE_FLAG_HH_ -#define CACHE_FLAG_HH_ - -#include -#include - -namespace pkgmgr_server { - -#ifndef EXPORT_API -#define EXPORT_API __attribute__((visibility("default"))) -#endif - -class EXPORT_API CacheFlag { - public: - enum class EXPORT_API Status { - UNPREPARED, - PREPARING, - PREPARED - }; - - static bool SetPreparing() { - bool ret = false; - std::unique_lock u(status_lock_); - if (status_ == Status::UNPREPARED) { - status_ = Status::PREPARING; - ret = true; - } - return ret; - } - - static void SetStatus(Status status) { - std::unique_lock u(status_lock_); - status_ = status; - } - - static Status GetStatus() { - std::unique_lock u(status_lock_); - return status_; - } - - static std::unique_lock GetWriterLock() { - return std::unique_lock(lock_); - } - - static void WriterUnLock() { - lock_.unlock(); - } - - static std::shared_lock GetReaderLock() { - return std::shared_lock(lock_, std::defer_lock); - } - - static void ReaderUnLock() { - lock_.unlock_shared(); - } - - private: - static inline Status status_; - static inline std::mutex status_lock_; - static inline std::shared_timed_mutex lock_; -}; - -} // namespace pkgmgr_server - -#endif // CACHE_FLAG_HH_ diff --git a/src/server/database/appinfo_db_handler.cc b/src/server/database/appinfo_db_handler.cc index 31039ef..dc6360f 100644 --- a/src/server/database/appinfo_db_handler.cc +++ b/src/server/database/appinfo_db_handler.cc @@ -19,7 +19,7 @@ #include #include -#include "cache_flag.hh" +#include "cache_provider.hh" #include "db_handle_provider.hh" #include "utils/logging.hh" @@ -65,38 +65,6 @@ int AppInfoDBHandler::GetHandleFromDB( return ret; } -int AppInfoDBHandler::GetHandleFromCache( - std::vector>& conn_list) { - bool is_write_op = - GetOpType() == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE; - int ret = PMINFO_R_OK; - std::string application; - - for (auto* it = filter_->list; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - if (node->prop == E_PMINFO_APPINFO_PROP_APP_ID) { - application = node->value; - break; - } - } - - std::vector> app_list; - for (auto& conn : conn_list) { - app_list = DBHandleProvider::GetInst(conn.second) - .GetApplications( - GetPID(), is_write_op, filter_, application); - - handle_list_.reserve(app_list.size() + handle_list_.size()); - std::move(std::begin(app_list), std::end(app_list), - std::back_inserter(handle_list_)); - } - - if (handle_list_.empty()) - ret = PMINFO_R_ENOENT; - - return ret; -} - int AppInfoDBHandler::Execute() { std::shared_lock s(lock_); SetOpType(pkgmgr_common::DBOperationType::OPERATION_TYPE_READ); @@ -112,16 +80,40 @@ int AppInfoDBHandler::Execute() { if (DBHandleProvider::GetInst(conn.second).IsWriter(GetPID())) is_writer = true; } + if (is_writer) return GetHandleFromDB(conn_list); - if (CacheFlag::GetStatus() == CacheFlag::Status::PREPARED) { - auto cache_lock = CacheFlag::GetReaderLock(); - if (cache_lock.try_lock() && - CacheFlag::GetStatus() == CacheFlag::Status::PREPARED) - return GetHandleFromCache(conn_list); - } + CacheProvider provider(GetUID()); + if (provider.IsPrepared() && provider.GetReadLock()) { + bool is_write_op = + GetOpType() == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE; + int ret = PMINFO_R_OK; + std::string application; + + for (auto* it = filter_->list; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + if (node->prop == E_PMINFO_APPINFO_PROP_APP_ID) { + application = node->value; + break; + } + } + + std::vector> app_list; + for (auto& conn : conn_list) { + app_list = CacheProvider(conn.second) + .GetApplications( + GetPID(), is_write_op, filter_, application); + handle_list_.reserve(app_list.size() + handle_list_.size()); + std::move(std::begin(app_list), std::end(app_list), + std::back_inserter(handle_list_)); + } + if (handle_list_.empty()) + ret = PMINFO_R_ENOENT; + + return ret; + } return GetHandleFromDB(conn_list); } diff --git a/src/server/database/appinfo_db_handler.hh b/src/server/database/appinfo_db_handler.hh index 1e68059..aabdc99 100644 --- a/src/server/database/appinfo_db_handler.hh +++ b/src/server/database/appinfo_db_handler.hh @@ -43,7 +43,6 @@ class EXPORT_API AppInfoDBHandler : public AbstractDBHandler{ protected: int GetHandleFromDB(std::vector>& conn_list); - int GetHandleFromCache(std::vector>& conn_list); pkgmgrinfo_filter_x* filter_; std::vector> handle_list_; uid_t uid_; diff --git a/src/server/database/cache.cc b/src/server/database/cache.cc new file mode 100644 index 0000000..f26ec0a --- /dev/null +++ b/src/server/database/cache.cc @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include "cache.hh" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "filter_checker_provider.hh" +#include "utils/logging.hh" + +#include "pkgmgrinfo_private.h" +#include "pkgmgrinfo_internal.h" +#include "pkgmgrinfo_internal.hh" + +namespace pkgmgr_server { +namespace database { + +std::unordered_map> Cache::cache_map_; + +Cache::Cache(uid_t uid) : uid_(uid), status_(Status::UNPREPARED) {} + +Cache& Cache::GetInst(uid_t uid) { + static std::mutex singleton_lock_; + std::unique_lock u(singleton_lock_); + + auto& prov = cache_map_[uid]; + if (prov == nullptr) + prov.reset(new Cache(uid)); + + return *prov; +} + +void Cache::ReleaseAll() { + static std::mutex singleton_lock_; + std::unique_lock u(singleton_lock_); + + for (auto& i : cache_map_) + i.second->ReleaseCache(); +} + +bool Cache::IsCachePreparationNecessary() { + bool result = false; + std::unique_lock u(status_lock_); + if (status_ == Status::UNPREPARED) { + status_ = Status::PREPARING; + result = true; + } + + return result; +} + +void Cache::SetPrepared() { + std::unique_lock u(status_lock_); + status_ = Status::PREPARED; +} + +void Cache::SetUnprepared() { + std::unique_lock u(status_lock_); + status_ = Status::UNPREPARED; +} + +void Cache::SetPreparing() { + std::unique_lock u(status_lock_); + status_ = Status::PREPARING; +} + +bool Cache::IsPrepared() { + std::unique_lock u(status_lock_); + return (status_ == Status::PREPARED); +} + +void Cache::ReleaseCache() { + auto lock = GetWriterLock(); + SetStatus(Status::PREPARING); + + pkg_map_.clear(); + app_map_.clear(); + + SetStatus(Status::UNPREPARED); +} + +void Cache::SetStatus(Status status) { + std::unique_lock u(status_lock_); + status_ = status; +} + +std::unique_lock Cache::GetWriterLock() { + return std::unique_lock(lock_); +} + +void Cache::WriterUnLock() { + lock_.unlock(); +} + +std::shared_lock Cache::GetReaderLock() { + return std::shared_lock(lock_, std::defer_lock); +} + +void Cache::ReaderUnLock() { + lock_.unlock(); +} + +void Cache::AddPackage(std::string package, package_x* info) { + auto ptr = std::shared_ptr(info, pkgmgrinfo_basic_free_package); + pkg_map_[package].push_back(ptr); + pkg_map_[""].push_back(std::move(ptr)); +} + +void Cache::AddApplication( + std::string app, std::shared_ptr info) { + app_map_[app].push_back(info); + app_map_[""].push_back(std::move(info)); +} + +int Cache::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write, + const std::string& locale) { + // CacheProvider should lock first and try lock before executing this func + pkg_map_.clear(); + app_map_.clear(); + + GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal); + if (list == nullptr) { + LOG(ERROR) << "Out of memory"; + return PMINFO_R_ERROR; + } + + auto tmp_filter = reinterpret_cast( + calloc(1, sizeof(pkgmgrinfo_filter_x))); + if (tmp_filter == nullptr) { + LOG(ERROR) << "Out of memory"; + g_hash_table_destroy(list); + return PMINFO_R_ERROR; + } + + int ret = pkginfo_internal_filter_get_list(db, tmp_filter, uid_, + locale.c_str(), list); + if (ret != PMINFO_R_OK) { + g_hash_table_destroy(list); + free(tmp_filter); + return ret; + } + + GHashTableIter iter; + gpointer value; + g_hash_table_iter_init(&iter, list); + while (g_hash_table_iter_next(&iter, nullptr, &value)) { + auto* pkg = reinterpret_cast(value); + AddPackage(pkg->package, pkg); + } + g_hash_table_destroy(list); + + std::vector> app_list; + ret = pkgmgr_server::internal::appinfo_internal_filter_get_list(db, + tmp_filter, uid_, uid, locale.c_str(), app_list); + free(tmp_filter); + if (ret == PMINFO_R_OK) { + for (auto& app : app_list) { + app->privileges = pkg_map_[app->package].front()->privileges; + std::string appid = app->appid; + AddApplication(std::move(appid), std::move(app)); + } + } + + return 0; +} + +std::vector> Cache::GetPackages( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& package) { + std::vector> ret; + + for (auto& info : pkg_map_[package]) { + bool pass = true; + for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + auto* checker = FilterCheckerProvider::GetInst(). + GetPkgFilterChecker(node->prop); + if (!checker->CheckFilter(node, info.get())) { + pass = false; + break; + } + } + if (pass) + ret.push_back(info); + } + + return ret; +} + + +std::vector> Cache::GetApplications( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& app) { + /* make metadata filter map */ + std::unordered_map metadata_map; + for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + if (node->key == nullptr) + continue; + + metadata_map[node->key] = (node->value ? node->value : ""); + } + + std::vector> ret; + for (auto& info : app_map_[app]) { + bool pass = true; + for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + auto* checker = FilterCheckerProvider::GetInst(). + GetAppFilterChecker(node->prop); + if (!checker->CheckFilter(node, info.get())) { + pass = false; + break; + } + } + if (!pass) + continue; + + if (!metadata_map.empty()) { + pass = false; + for (auto* it = info->metadata; it != nullptr; it = g_list_next(it)) { + auto* node = reinterpret_cast(it->data); + if (node->key != nullptr) { + auto metadata = metadata_map.find(node->key); + if (metadata != metadata_map.end() && + strstr(node->value ? node->value : "", + metadata->second.c_str()) != nullptr) { + pass = true; + break; + } + } + } + } + + if (pass) + ret.push_back(info); + } + + return ret; +} + +} // namespace database +} // namespace pkgmgr_server diff --git a/src/server/database/cache.hh b/src/server/database/cache.hh new file mode 100644 index 0000000..4c9fee9 --- /dev/null +++ b/src/server/database/cache.hh @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef SERVER_CACHE_HH_ +#define SERVER_CACHE_HH_ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "pkgmgrinfo_private.h" + +namespace pkgmgr_server { +namespace database { + +#ifndef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) +#endif + +class EXPORT_API Cache { + public: + ~Cache() = default; + static Cache& GetInst(uid_t uid); + + void ReleaseCache(); + bool IsCachePreparationNecessary(); + int UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write, + const std::string& locale); + std::vector> GetPackages( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& package); + std::vector> GetApplications( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& app); + void SetPrepared(); + void SetUnprepared(); + void SetPreparing(); + bool IsPrepared(); + + std::unique_lock GetWriterLock(); + void WriterUnLock(); + std::shared_lock GetReaderLock(); + void ReaderUnLock(); + + static void ReleaseAll(); + + private: + explicit Cache(uid_t uid); + enum class EXPORT_API Status { + UNPREPARED, + PREPARING, + PREPARED + }; + + void SetStatus(Status status); + + void AddPackage(std::string package, package_x* info); + void AddApplication(std::string app, std::shared_ptr info); + + std::mutex status_lock_; + std::shared_timed_mutex lock_; + uid_t uid_; + Status status_; + std::unordered_map>> + pkg_map_; + std::unordered_map>> + app_map_; + + static std::unordered_map> cache_map_; +}; + +} // namespace database +} // namespace pkgmgr_server + +#endif // SERVER_CACHE_HH_ diff --git a/src/server/database/cache_db_handler.cc b/src/server/database/cache_db_handler.cc index aaf1592..a590740 100644 --- a/src/server/database/cache_db_handler.cc +++ b/src/server/database/cache_db_handler.cc @@ -19,10 +19,30 @@ #include #include -#include "cache_flag.hh" +#include "cache_provider.hh" #include "db_handle_provider.hh" #include "utils/logging.hh" +namespace { + +uid_t globaluser_uid = -1; + +uid_t GetGlobalUID() { + if (globaluser_uid == (uid_t)-1) + globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + + return globaluser_uid; +} + +uid_t ConvertUID(uid_t uid) { + if (uid < REGULAR_USER) + return GetGlobalUID(); + else + return uid; +} + +} // namespace + namespace pkgmgr_server { namespace database { @@ -38,26 +58,26 @@ int CacheDBHandler::Execute() { std::vector> conn_list; if (!Connect()) { - CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED); + CacheProvider(GetUID()).SetUnprepared(); return PMINFO_R_ERROR; } conn_list = GetConnection(); - auto lock = CacheFlag::GetWriterLock(); int ret = PMINFO_R_OK; + for (auto& conn : conn_list) { - ret = DBHandleProvider::GetInst(conn.second) - .UpdateCache(conn.first, GetPID(), uid_, false, GetLocale()); + if (conn.second != ConvertUID(uid_)) + continue; + + CacheProvider provider(conn.second); + ret = provider.UpdateCache(conn.first, GetPID(), uid_, false, GetLocale()); if (ret != PMINFO_R_OK) { - LOG(ERROR) << "Failed to update pkginfo cache : " << ret; + LOG(ERROR) << "Failed to update pkginfo cache for uid[" + << uid_ << "], ret : " << ret; break; } } - CacheFlag::SetStatus(ret == PMINFO_R_OK ? - CacheFlag::Status::PREPARED : - CacheFlag::Status::UNPREPARED); - return ret; } diff --git a/src/server/database/cache_provider.cc b/src/server/database/cache_provider.cc new file mode 100644 index 0000000..25b82f7 --- /dev/null +++ b/src/server/database/cache_provider.cc @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include "cache_provider.hh" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cache.hh" +#include "filter_checker_provider.hh" +#include "utils/logging.hh" + +#include "pkgmgrinfo_private.h" +#include "pkgmgrinfo_internal.h" +#include "pkgmgrinfo_internal.hh" + +namespace { + +uid_t globaluser_uid = -1; + +uid_t GetGlobalUID() { + if (globaluser_uid == (uid_t)-1) + globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + + return globaluser_uid; +} + +uid_t ConvertUID(uid_t uid) { + if (uid < REGULAR_USER) + return GetGlobalUID(); + else + return uid; +} + +} // namespace + +namespace pkgmgr_server { +namespace database { + +bool CacheProvider::IsCachePreparationNecessary() { + return Cache::GetInst(ConvertUID(uid_)).IsCachePreparationNecessary(); +} + +void CacheProvider::ReleaseCache() { + Cache::GetInst(ConvertUID(uid_)).ReleaseCache(); +} + +void CacheProvider::ReleaseAll() { + Cache::ReleaseAll(); +} + +bool CacheProvider::IsPrepared() { + return Cache::GetInst(ConvertUID(uid_)).IsPrepared(); +} + +bool CacheProvider::GetReadLock() { + reader_lock_ = Cache::GetInst(ConvertUID(uid_)).GetReaderLock(); + if (reader_lock_.try_lock() && Cache::GetInst(ConvertUID(uid_)).IsPrepared()) + return true; + + reader_lock_.unlock(); + return false; +} + +void CacheProvider::SetUnprepared() { + Cache::GetInst(ConvertUID(uid_)).SetUnprepared(); +} + +int CacheProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write, + const std::string& locale) { + auto lock = Cache::GetInst(ConvertUID(uid_)).GetWriterLock(); + + int ret = Cache::GetInst(ConvertUID(uid_)).UpdateCache( + db, pid, uid, write, locale); + + if (ret == PMINFO_R_OK) + Cache::GetInst(ConvertUID(uid_)).SetPrepared(); + else + Cache::GetInst(ConvertUID(uid_)).SetUnprepared(); + + return ret; +} + +std::vector> CacheProvider::GetPackages( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& package) { + std::vector> ret; + + uid_t target_uid = ConvertUID(uid_); + ret = Cache::GetInst(target_uid).GetPackages(pid, write, filter, package); + + return ret; +} + +std::vector> CacheProvider::GetApplications( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& app) { + std::vector> ret; + uid_t target_uid = ConvertUID(uid_); + ret = Cache::GetInst(target_uid).GetApplications(pid, write, filter, app); + + return ret; +} + + +} // namespace database +} // namespace pkgmgr_server diff --git a/src/server/database/cache_provider.hh b/src/server/database/cache_provider.hh new file mode 100644 index 0000000..d1b8db2 --- /dev/null +++ b/src/server/database/cache_provider.hh @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef SERVER_CACHE_PROVIDER_HH_ +#define SERVER_CACHE_PROVIDER_HH_ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "pkgmgrinfo_private.h" + +namespace pkgmgr_server { +namespace database { + +#ifndef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) +#endif + +class EXPORT_API CacheProvider { + public: + enum class EXPORT_API CacheOpResult { + + PREPARED + }; + + CacheProvider(uid_t uid) : uid_(uid) {}; + bool IsCachePreparationNecessary(); + int UpdateCache(sqlite3* db, pid_t pid, uid_t uid, + bool write, const std::string& locale); + bool GetReadLock(); + bool IsPrepared(); + void ReleaseCache(); + static void ReleaseAll(); + void SetUnprepared(); + + std::vector> GetPackages( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& package); + std::vector> GetApplications( + pid_t pid, bool write, pkgmgrinfo_filter_x* filter, + const std::string& app); + + private: + uid_t uid_; + std::shared_lock reader_lock_; +}; + +} // namespace database +} // namespace pkgmgr_server + +#endif // SERVER_CACHE_PROVIDER_HH_ diff --git a/src/server/database/db_handle_provider.cc b/src/server/database/db_handle_provider.cc index 013c8e9..c8e95ee 100644 --- a/src/server/database/db_handle_provider.cc +++ b/src/server/database/db_handle_provider.cc @@ -26,7 +26,7 @@ #include #include -#include "cache_flag.hh" +#include "cache_provider.hh" #include "utils/logging.hh" #include "pkgmgr-info.h" @@ -165,8 +165,10 @@ std::vector> DBHandleProvider::GetParserDBPath( db_path_list.emplace_back( std::make_pair(global_parser_memdb_path, GetGlobalUID())); } else { - if (uid_ > REGULAR_USER) - db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_)); + if (uid_ > REGULAR_USER) { + db_path_list.emplace_back( + std::make_pair(user_parser_filedb_path_, uid_)); + } db_path_list.emplace_back( std::make_pair(global_parser_filedb_path_, GetGlobalUID())); @@ -194,7 +196,7 @@ std::string DBHandleProvider::GetCertDBPath(pid_t pid, bool write) { } sqlite3* DBHandleProvider::CreateMemoryDBHandle(const std::string& filedb_path, - const std::string& memorydb_path) { + const std::string& memorydb_path) { sqlite3* memorydb = nullptr; sqlite3* filedb = nullptr; int ret = sqlite3_open_v2(memorydb_path.c_str(), &memorydb, @@ -271,12 +273,12 @@ void DBHandleProvider::UnsetMemoryMode(pid_t pid) { is_user_memdb_set_ = false; is_global_memdb_set_ = false; - auto lock = CacheFlag::GetWriterLock(); - CacheFlag::SetStatus(CacheFlag::Status::PREPARING); + CacheProvider provider(uid_); + provider.ReleaseCache(); + + if (ConvertUID(uid_) != GetGlobalUID()) + CacheProvider(GetGlobalUID()).ReleaseCache(); - pkg_map_.clear(); - app_map_.clear(); - CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED); LOG(DEBUG) << "Set Memory mode : File"; } @@ -294,168 +296,11 @@ bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) { return true; } -void DBHandleProvider::TrimCache() { - std::unique_lock u(lock_); - if (!released_) - ReleaseCache(); -} - -void DBHandleProvider::ReleaseCache() { - auto lock = CacheFlag::GetWriterLock(); - CacheFlag::SetStatus(CacheFlag::Status::PREPARING); - - app_map_.clear(); - pkg_map_.clear(); - CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED); - - released_ = true; -} - bool DBHandleProvider::IsWriter(pid_t pid) { std::unique_lock u(pid_list_lock_); return writer_pid_list_.find(pid) != writer_pid_list_.end(); } -int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write, - const std::string& locale) { - pkg_map_.clear(); - app_map_.clear(); - - GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal); - if (list == nullptr) { - LOG(ERROR) << "Out of memory"; - return PMINFO_R_ERROR; - } - - auto tmp_filter = reinterpret_cast( - calloc(1, sizeof(pkgmgrinfo_filter_x))); - if (tmp_filter == nullptr) { - LOG(ERROR) << "Out of memory"; - g_hash_table_destroy(list); - return PMINFO_R_ERROR; - } - - int ret = pkginfo_internal_filter_get_list(db, tmp_filter, uid_, - locale.c_str(), list); - if (ret == PMINFO_R_OK) { - GHashTableIter iter; - gpointer value; - g_hash_table_iter_init(&iter, list); - while (g_hash_table_iter_next(&iter, nullptr, &value)) { - auto* pkg = reinterpret_cast(value); - std::string pkgid = pkg->package; - AddPackage(std::move(pkgid), pkg); - } - } - - g_hash_table_destroy(list); - if (ret == PMINFO_R_ERROR) { - free(tmp_filter); - return ret; - } - - std::vector> app_list; - ret = pkgmgr_server::internal::appinfo_internal_filter_get_list(db, - tmp_filter, uid_, uid, locale.c_str(), app_list); - free(tmp_filter); - if (ret == PMINFO_R_OK) { - for (auto& app : app_list) { - app->privileges = pkg_map_[app->package].front()->privileges; - std::string appid = app->appid; - AddApplication(std::move(appid), std::move(app)); - } - } - released_ = false; - - return ret; -} - -std::vector> DBHandleProvider::GetPackages( - pid_t pid, bool write, pkgmgrinfo_filter_x* filter, - const std::string& package) { - std::vector> ret; - for (auto& info : pkg_map_[package]) { - bool pass = true; - for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - auto* checker = FilterCheckerProvider::GetInst(). - GetPkgFilterChecker(node->prop); - if (!checker->CheckFilter(node, info.get())) { - pass = false; - break; - } - } - if (pass) - ret.push_back(info); - } - - return ret; -} - -void DBHandleProvider::AddPackage(std::string package, package_x* info) { - auto ptr = std::shared_ptr(info, pkgmgrinfo_basic_free_package); - pkg_map_[package].push_back(ptr); - pkg_map_[""].push_back(std::move(ptr)); -} - -std::vector> DBHandleProvider::GetApplications( - pid_t pid, bool write, pkgmgrinfo_filter_x* filter, - const std::string& app) { - /* make metadata filter map */ - std::unordered_map metadata_map; - for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - if (node->key == nullptr) - continue; - - metadata_map[node->key] = (node->value ? node->value : ""); - } - - std::vector> ret; - for (auto& info : app_map_[app]) { - bool pass = true; - for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - auto* checker = FilterCheckerProvider::GetInst(). - GetAppFilterChecker(node->prop); - if (!checker->CheckFilter(node, info.get())) { - pass = false; - break; - } - } - if (!pass) - continue; - - if (!metadata_map.empty()) { - pass = false; - for (auto* it = info->metadata; it != nullptr; it = g_list_next(it)) { - auto* node = reinterpret_cast(it->data); - if (node->key != nullptr) { - auto metadata = metadata_map.find(node->key); - if (metadata == metadata_map.end()) - continue; - - if (metadata->second.empty() || - strcmp(node->value ? node->value : "", - metadata->second.c_str()) == 0) { - pass = true; - break; - } - } - } - } - - if (pass) - ret.push_back(info); - } - return ret; -} - -void DBHandleProvider::AddApplication(std::string app, std::shared_ptr info) { - app_map_[app].push_back(info); - app_map_[""].push_back(std::move(info)); -} - void DBHandleProvider::InsertPID(pid_t pid) { std::unique_lock u(pid_list_lock_); diff --git a/src/server/database/db_handle_provider.hh b/src/server/database/db_handle_provider.hh index 7795732..16dc89c 100644 --- a/src/server/database/db_handle_provider.hh +++ b/src/server/database/db_handle_provider.hh @@ -50,15 +50,6 @@ class EXPORT_API DBHandleProvider { std::string GetCertDBPath(int pid, bool write); void SetMemoryMode(pid_t pid); void UnsetMemoryMode(pid_t pid); - int UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write, - const std::string& locale); - std::vector> GetPackages( - pid_t pid, bool write, pkgmgrinfo_filter_x* filter, - const std::string& package); - std::vector> GetApplications( - pid_t pid, bool write, pkgmgrinfo_filter_x* filter, - const std::string& app); - void TrimCache(); bool IsWriter(pid_t pid); private: @@ -66,9 +57,6 @@ class EXPORT_API DBHandleProvider { sqlite3* CreateMemoryDBHandle(const std::string& filedb_path, const std::string& memorydb_path); bool IsMemoryDBActive(pid_t pid, bool write); - void ReleaseCache(); - void AddPackage(std::string package, package_x* info); - void AddApplication(std::string app, std::shared_ptr info); void InsertPID(pid_t pid); bool ErasePID(pid_t pid); @@ -92,11 +80,6 @@ class EXPORT_API DBHandleProvider { parser_memdb_handle_; std::string user_parser_memdb_path_; std::string user_parser_filedb_path_; - bool released_ = true; - std::unordered_map>> - pkg_map_; - std::unordered_map>> - app_map_; }; } // namespace database diff --git a/src/server/database/pkg_get_db_handler.cc b/src/server/database/pkg_get_db_handler.cc index 0e67de7..b4c7c4f 100644 --- a/src/server/database/pkg_get_db_handler.cc +++ b/src/server/database/pkg_get_db_handler.cc @@ -19,7 +19,7 @@ #include #include -#include "cache_flag.hh" +#include "cache_provider.hh" #include "db_handle_provider.hh" #include "pkgmgrinfo_debug.h" @@ -80,35 +80,6 @@ int PkgGetDBHandler::GetHandleFromDB( return ret; } -int PkgGetDBHandler::GetHandleFromCache( - std::vector>& conn_list) { - int ret = PMINFO_R_OK; - std::string package; - - for (auto* it = filter_->list; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - if (node->prop == E_PMINFO_PKGINFO_PROP_PACKAGE_ID) { - package = node->value; - break; - } - } - - std::vector> pkg_list; - for (auto& conn : conn_list) { - pkg_list = DBHandleProvider::GetInst(conn.second) - .GetPackages(GetPID(), false, filter_, package); - - handle_list_.reserve(pkg_list.size() + handle_list_.size()); - std::move(std::begin(pkg_list), std::end(pkg_list), - std::back_inserter(handle_list_)); - } - - if (handle_list_.empty()) - return PMINFO_R_ENOENT; - - return ret; -} - int PkgGetDBHandler::Execute() { std::shared_lock s(lock_); SetOpType(pkgmgr_common::DBOperationType::OPERATION_TYPE_READ); @@ -128,11 +99,32 @@ int PkgGetDBHandler::Execute() { if (is_writer) return GetHandleFromDB(conn_list); - if (CacheFlag::GetStatus() == CacheFlag::Status::PREPARED) { - auto cache_lock = CacheFlag::GetReaderLock(); - if (cache_lock.try_lock() && - CacheFlag::GetStatus() == CacheFlag::Status::PREPARED) - return GetHandleFromCache(conn_list); + CacheProvider provider(GetUID()); + if (provider.IsPrepared() && provider.GetReadLock()) { + int ret = PMINFO_R_OK; + std::string package; + + for (auto* it = filter_->list; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + if (node->prop == E_PMINFO_PKGINFO_PROP_PACKAGE_ID) { + package = node->value; + break; + } + } + + std::vector> pkg_list; + for (auto& conn : conn_list) { + pkg_list = CacheProvider(conn.second) + .GetPackages(GetPID(), false, filter_, package); + handle_list_.reserve(pkg_list.size() + handle_list_.size()); + std::move(std::begin(pkg_list), std::end(pkg_list), + std::back_inserter(handle_list_)); + } + + if (handle_list_.empty()) + return PMINFO_R_ENOENT; + + return ret; } return GetHandleFromDB(conn_list); diff --git a/src/server/database/pkg_get_db_handler.hh b/src/server/database/pkg_get_db_handler.hh index ba16187..e34c099 100644 --- a/src/server/database/pkg_get_db_handler.hh +++ b/src/server/database/pkg_get_db_handler.hh @@ -42,7 +42,6 @@ class EXPORT_API PkgGetDBHandler : public AbstractDBHandler { protected: int GetHandleFromDB(std::vector>& conn_list); - int GetHandleFromCache(std::vector>& conn_list); pkgmgrinfo_filter_x* filter_ = nullptr; std::vector> handle_list_; uid_t uid_; diff --git a/src/server/database/query_handler.cc b/src/server/database/query_handler.cc index d450751..78d9c8c 100644 --- a/src/server/database/query_handler.cc +++ b/src/server/database/query_handler.cc @@ -21,6 +21,7 @@ #include "utils/logging.hh" #include "db_handle_provider.hh" +#include "cache_provider.hh" #include "pkgmgrinfo_debug.h" #include "pkgmgrinfo_internal.h" @@ -299,7 +300,8 @@ int QueryHandler::Execute() { } } __free_query_list(queries, args_list); - database::DBHandleProvider::GetInst(GetUID()).TrimCache(); + CacheProvider(GetUID()).ReleaseCache(); + return ret; } return ret; diff --git a/src/server/request_handler/abstract_request_handler.cc b/src/server/request_handler/abstract_request_handler.cc index 4f00260..d93b7c9 100644 --- a/src/server/request_handler/abstract_request_handler.cc +++ b/src/server/request_handler/abstract_request_handler.cc @@ -19,5 +19,13 @@ pid_t AbstractRequestHandler::GetPID() { return pid_; } +void AbstractRequestHandler::SetUID(uid_t uid) { + uid_ = uid; +} + +uid_t AbstractRequestHandler::GetUID() { + return uid_; +} + } // namespace request_handler } // namespace pkgmgr_server diff --git a/src/server/request_handler/abstract_request_handler.hh b/src/server/request_handler/abstract_request_handler.hh index 8285e80..ea82ef0 100644 --- a/src/server/request_handler/abstract_request_handler.hh +++ b/src/server/request_handler/abstract_request_handler.hh @@ -27,12 +27,15 @@ class EXPORT_API AbstractRequestHandler { virtual std::vector ExtractResult() = 0; void SetPID(pid_t pid); + void SetUID(uid_t uid); protected: pid_t GetPID(); + uid_t GetUID(); private: pid_t pid_; + uid_t uid_; }; } // namespace request_handler diff --git a/src/server/request_handler/create_cache_request_handler.cc b/src/server/request_handler/create_cache_request_handler.cc index 4e60054..1c2c071 100644 --- a/src/server/request_handler/create_cache_request_handler.cc +++ b/src/server/request_handler/create_cache_request_handler.cc @@ -15,8 +15,7 @@ namespace request_handler { bool CreateCacheRequestHandler::HandleRequest(unsigned char* data, int size, const std::string& locale) { - // TODO(ilho159.kim) need to get logined user id - psd::CacheDBHandler db(5001, GetPID()); + psd::CacheDBHandler db(GetUID(), GetPID()); db.SetLocale(locale); int ret = db.Execute(); diff --git a/src/server/runner.cc b/src/server/runner.cc index 52e8211..9686d96 100644 --- a/src/server/runner.cc +++ b/src/server/runner.cc @@ -24,7 +24,7 @@ #include #include -#include "cache_flag.hh" +#include "cache_provider.hh" #include "create_cache_request.hh" #include "cynara_checker.hh" #include "pkg_request.hh" @@ -39,6 +39,26 @@ #endif #define LOG_TAG "PKGMGR_INFO" +namespace { + +uid_t globaluser_uid = -1; + +uid_t GetGlobalUID() { + if (globaluser_uid == (uid_t)-1) + globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + + return globaluser_uid; +} + +uid_t ConvertUID(uid_t uid) { + if (uid < REGULAR_USER) + return GetGlobalUID(); + else + return uid; +} + +} // namespace + namespace pkgmgr_server { namespace { @@ -94,16 +114,27 @@ int Runner::OnReceiveRequest(int fd, GIOCondition cond, void* user_data) { } auto req = std::make_shared(client_fd); - if (req->ReceiveData()) { - pkgmgr_common::ReqType type = req->GetRequestType(); - if (CacheFlag::SetPreparing()) { + if (!req->ReceiveData()) + return G_SOURCE_CONTINUE; + + pkgmgr_server::database::CacheProvider provider(req->GetSenderUID()); + if (provider.IsCachePreparationNecessary()) { + runner->QueueRequest( + std::make_shared(req->GetSenderUID())); + } + + if (ConvertUID(req->GetSenderUID()) != GetGlobalUID()) { + pkgmgr_server::database::CacheProvider global_provider(GetGlobalUID()); + if (global_provider.IsCachePreparationNecessary()) { runner->QueueRequest( - std::make_shared(req->GetSenderUID())); + std::make_shared(GetGlobalUID())); } - std::vector&& privileges = GetPrivileges(type); - CynaraChecker::GetInst().CheckPrivilege(runner, req, privileges); } + pkgmgr_common::ReqType type = req->GetRequestType(); + std::vector&& privileges = GetPrivileges(type); + CynaraChecker::GetInst().CheckPrivilege(runner, req, privileges); + return G_SOURCE_CONTINUE; } diff --git a/src/server/worker_thread.cc b/src/server/worker_thread.cc index 08f2929..87287e0 100644 --- a/src/server/worker_thread.cc +++ b/src/server/worker_thread.cc @@ -20,6 +20,7 @@ #include #include "abstract_parcelable.hh" +#include "cache_provider.hh" #include "command_request_handler.hh" #include "create_cache_request_handler.hh" #include "create_db_request_handler.hh" @@ -120,6 +121,7 @@ void WorkerThread::Run() { try { handler[type]->SetPID(req->GetSenderPID()); + handler[type]->SetUID(req->GetSenderUID()); if (!handler[type]->HandleRequest(req->GetData(), req->GetSize(), locale_.GetObject())) LOG(ERROR) << "Failed to handle request"; @@ -165,9 +167,7 @@ gboolean WorkerThread::TrimMemory(void* data) { database::DBHandleProvider:: GetInst(getuid()).UnsetMemoryMode(getpid()); - database::DBHandleProvider:: - GetInst(getuid()).TrimCache(); - + database::CacheProvider::ReleaseAll(); return false; } -- 2.7.4