Remove unnecessary unique_lock from read operation
[platform/core/appfw/pkgmgr-info.git] / src / server / database / db_handle_provider.cc
index c8e95ee..375c3eb 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <fcntl.h>
 #include <glib.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 
 #include <tzplatform_config.h>
@@ -26,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include "cache_provider.hh"
+#include "cache_flag.hh"
 #include "utils/logging.hh"
 
 #include "pkgmgr-info.h"
@@ -58,6 +59,24 @@ uid_t ConvertUID(uid_t uid) {
     return uid;
 }
 
+bool GetModifiedTime(const char* dbpath, timespec* t) {
+  if (dbpath == nullptr || t == nullptr) {
+    LOG(ERROR) << "Invalid argument";
+    return false;
+  }
+
+  struct stat attr;
+  if (stat(dbpath, &attr)) {
+    LOG(ERROR) << "Fail to get status from file "
+        << dbpath << " errno : " << errno;
+    return false;
+  }
+
+  *t = attr.st_mtim;
+
+  return true;
+}
+
 static const std::string global_parser_memdb_path =
     "file:parserdb?mode=memory&cache=shared";
 
@@ -81,7 +100,7 @@ std::string DBHandleProvider::global_parser_filedb_path_;
 std::string DBHandleProvider::cert_filedb_path_;
 std::unordered_set<pid_t> DBHandleProvider::writer_pid_list_;
 std::recursive_mutex DBHandleProvider::lock_;
-std::mutex DBHandleProvider::pid_list_lock_;
+std::shared_mutex DBHandleProvider::pid_list_lock_;
 
 DBHandleProvider::DBHandleProvider(uid_t uid)
     : uid_(uid),
@@ -111,10 +130,16 @@ DBHandleProvider::DBHandleProvider(uid_t uid)
 }
 
 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
-  static std::mutex singleton_lock_;
-  std::unique_lock<std::mutex> u(singleton_lock_);
+  static std::shared_mutex singleton_lock_;
+  std::shared_lock<std::shared_mutex> s(singleton_lock_);
 
   uid = ConvertUID(uid);
+  auto it = provider_map_.find(uid);
+  if (it != provider_map_.end())
+    return *(it->second);
+
+  s.unlock();
+  std::unique_lock<std::shared_mutex> u(singleton_lock_);
   auto& prov = provider_map_[uid];
   if (prov == nullptr)
     prov.reset(new DBHandleProvider(uid));
@@ -123,7 +148,7 @@ DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
 }
 
 bool DBHandleProvider::IsCrashedWriteRequest() {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   if (writer_pid_list_.empty())
     return false;
@@ -165,10 +190,8 @@ std::vector<std::pair<std::string, uid_t>> 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()));
@@ -196,7 +219,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,
@@ -273,17 +296,13 @@ void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
   is_user_memdb_set_ = false;
   is_global_memdb_set_ = false;
 
-  CacheProvider provider(uid_);
-  provider.ReleaseCache();
-
-  if (ConvertUID(uid_) != GetGlobalUID())
-    CacheProvider(GetGlobalUID()).ReleaseCache();
+  TrimCache();
 
   LOG(DEBUG) << "Set Memory mode : File";
 }
 
 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
   if (!is_user_memdb_set_)
     return false;
 
@@ -296,19 +315,228 @@ bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
   return true;
 }
 
+void DBHandleProvider::TrimCache() {
+  std::unique_lock<std::recursive_mutex> 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<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> s(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();
+
+  const char* dbpath = sqlite3_db_filename(db, "main");
+  bool is_inmemory_db = false;
+  if (dbpath == nullptr || strlen(dbpath) == 0) {
+    LOG(INFO) << "database is inmemory db";
+    is_inmemory_db = true;
+  }
+
+  timespec start_time = { 0, };
+  timespec end_time = { 0, };
+  if (!is_inmemory_db && !GetModifiedTime(dbpath, &start_time))
+    return PMINFO_R_ERROR;
+
+  GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
+  if (list == nullptr) {
+    LOG(ERROR) << "Out of memory";
+    return PMINFO_R_ERROR;
+  }
+
+  pkgmgrinfo_filter_x tmp_filter = { 0, };
+  tmp_filter.cache_flag = true;
+  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<package_x*>(value);
+      std::string pkgid = pkg->package;
+      AddPackage(std::move(pkgid), pkg);
+    }
+  }
+
+  g_hash_table_destroy(list);
+  if (ret == PMINFO_R_ERROR)
+    return ret;
+
+  if (!is_inmemory_db && !GetModifiedTime(dbpath, &end_time))
+    return PMINFO_R_ERROR;
+
+  if (start_time.tv_sec != end_time.tv_sec ||
+      start_time.tv_nsec != end_time.tv_nsec) {
+    LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
+    return PMINFO_R_ERROR;
+  }
+
+  std::vector<std::shared_ptr<application_x>> app_list;
+  ret = pkgmgr_server::internal::appinfo_internal_filter_get_list(db,
+      &tmp_filter, uid_, uid, locale.c_str(), app_list);
+
+  if (!is_inmemory_db && !GetModifiedTime(dbpath, &end_time))
+    return PMINFO_R_ERROR;
+
+  if (start_time.tv_sec != end_time.tv_sec ||
+      start_time.tv_nsec != end_time.tv_nsec) {
+    LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
+    return PMINFO_R_ERROR;
+  }
+
+  if (ret == PMINFO_R_OK) {
+    for (auto& app : app_list) {
+      if (pkg_map_.find(app->package) == pkg_map_.end()) {
+        LOG(ERROR) << "Can not find package from pkg_map";
+        return PMINFO_R_ERROR;
+      }
+
+      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<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
+    pid_t pid, pkgmgrinfo_filter_x* filter,
+    const std::string& package) {
+  std::vector<std::shared_ptr<package_x>> ret;
+  auto map_it = pkg_map_.find(package);
+  if (map_it == pkg_map_.end())
+    return ret;
+
+  if (__check_package_storage_status(filter)) {
+    if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
+        PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
+      LOG(ERROR) << "Fail to add check storage value to filter";
+      return {};
+    }
+  }
+
+  for (auto& info : map_it->second) {
+    bool pass = true;
+    for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
+      auto node = reinterpret_cast<pkgmgrinfo_node_x*>(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<package_x>(info, pkgmgrinfo_basic_free_package);
+  pkg_map_[package].push_back(ptr);
+  pkg_map_[""].push_back(std::move(ptr));
+}
+
+std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
+    pid_t pid, pkgmgrinfo_filter_x* filter,
+    const std::string& app) {
+  /* make metadata filter map */
+  std::unordered_map<std::string, std::string> metadata_map;
+  for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
+    auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
+    if (node->key == nullptr)
+      continue;
+
+    metadata_map[node->key] = (node->value ? node->value : "");
+  }
+
+  std::vector<std::shared_ptr<application_x>> ret;
+  auto map_it = app_map_.find(app);
+  if (map_it == app_map_.end())
+    return ret;
+
+  if (pkgmgr_server::internal::check_app_storage_status(filter)) {
+    if (pkgmgrinfo_appinfo_filter_add_bool(filter,
+        PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
+      LOG(ERROR) << "Fail to add check storage value to filter";
+      return {};
+    }
+  }
+
+  for (auto& info : map_it->second) {
+    bool pass = true;
+    for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
+      auto node = reinterpret_cast<pkgmgrinfo_node_x*>(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<metadata_x*>(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<application_x> info) {
+  app_map_[app].push_back(info);
+  app_map_[""].push_back(std::move(info));
+}
+
 void DBHandleProvider::InsertPID(pid_t pid) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   writer_pid_list_.insert(pid);
 }
 
 bool DBHandleProvider::ErasePID(pid_t pid) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   return writer_pid_list_.erase(pid) == 1;
 }