Improve db busy handler 51/310351/3
authorIlho Kim <ilho159.kim@samsung.com>
Fri, 26 Apr 2024 00:40:27 +0000 (09:40 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Fri, 26 Apr 2024 00:44:25 +0000 (09:44 +0900)
Threre is a possibility that db operation cannot be performed
for more than 5 seconds on low performance devices
so increase busy handler waiting count
and print the process that owns the lock of database

Change-Id: I2f10b95205c041c0351dc664830a9bfcb1d67dec
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
src/server/database/abstract_db_handler.cc
src/server/database/abstract_db_handler.hh

index 8aa4739fe213aa0faec584358d2596a9f8f3ed03..45f5e156024dd1b70f1da80d787f3f0ee9e695c4 100644 (file)
 namespace {
 
 constexpr useconds_t BUSY_WAITING_USEC = (1000000 / 10 / 2); /* 0.05 sec */
-constexpr int BUSY_WAITING_MAX = 100; /* wait for max 5 sec */
+constexpr int BUSY_WAITING_MAX = 300; /* wait for max 15 sec */
+constexpr int BUSY_LOG_INTERVAL = 1000000 / BUSY_WAITING_USEC; /* interval 1 sec */
+
+void __check_db_lock(const char* dbpath) {
+  struct stat sb;
+  int pid;
+  unsigned int maj;
+  unsigned int min;
+  unsigned long long ino;
+  char cmdline[BUFSIZE];
+  char name[BUFSIZE];
+  char type[1024];
+
+  if (stat(dbpath, &sb) == -1) {
+    LOG(ERROR) << "get db file(" << dbpath << ") status failed: " << errno;
+    return;
+  }
+
+  FILE* fp = fopen("/proc/locks", "r");
+  if (fp == NULL) {
+    LOG(ERROR) << "Failed to open lock info: " << errno;
+    return;
+  }
+
+  while (fscanf(fp, "%*s %*s %*s %5s %d %x:%x:%llu %*s %*s",
+        type, &pid, &maj, &min, &ino) != EOF) {
+    if (maj != major(sb.st_dev) || min != minor(sb.st_dev) ||
+        ino != sb.st_ino || pid == getpid())
+      continue;
+
+    snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
+    FILE* fp_cmdline = fopen(cmdline, "r");
+    name[0] = '\0';
+    if (fp_cmdline != NULL) {
+      size_t len = fread(name, sizeof(char), sizeof(name) - 1,
+          fp_cmdline);
+      if (len > 0) {
+        if (name[len - 1] == '\n')
+          name[len - 1] = '\0';
+        else
+          name[len] = '\0';
+      }
+      fclose(fp_cmdline);
+    }
+
+    LOG(WARNING) << name << "(" << pid << ")" << "has lock("
+        << type << ") on pkgmgr db(" << dbpath << ")";
+  }
+
+  fclose(fp);
+}
+
+int __db_busy_handler(void *data, int count) {
+  if ((count + 1) % BUSY_LOG_INTERVAL == 0 ) {
+    LOG(WARNING) << "Database is busy, waiting count : " << count;
+
+    __check_db_lock(static_cast<const char*>(data));
+  }
 
-int __readdb_busy_handler(void *data, int count) {
   if (count < BUSY_WAITING_MAX) {
     usleep(BUSY_WAITING_USEC);
-    return 1;
-  } else {
-    /* sqlite3_prepare_v2 will return SQLITE_BUSY */
-    return 0;
+    return true;
   }
+
+  LOG(ERROR) << "Try to access db[" << static_cast<const char*>(data) << "] "
+      << BUSY_WAITING_MAX << " times, but can't access";
+  return false;
 }
 
 int __open_read_db(const char *path, sqlite3 **db) {
@@ -58,7 +115,7 @@ int __open_read_db(const char *path, sqlite3 **db) {
     return ret;
   }
 
-  ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
+  ret = sqlite3_busy_handler(*db, __db_busy_handler, (void*)path);
   if (ret != SQLITE_OK) {
     LOG(ERROR) << "failed to register busy handler:" << sqlite3_errmsg(*db);
     sqlite3_close_v2(*db);
@@ -68,24 +125,6 @@ int __open_read_db(const char *path, sqlite3 **db) {
   return ret;
 }
 
-constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
-constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
-constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
-constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
-
-int __writedb_busy_handler(void *data, int count) {
-  if (count < (BUSY_WAITING_MAX / 2)) {
-    usleep(BUSY_WAITING_USEC);
-    return 1;
-  } else if (count < BUSY_WAITING_MAX) {
-    usleep(BUSY_WAITING_USEC);
-    return 1;
-  } else {
-    /* sqlite3_prepare_v2 will return SQLITE_BUSY */
-    return 0;
-  }
-}
-
 int __open_write_db(uid_t uid, const char* path,
     sqlite3** db) {
   int ret;
@@ -96,8 +135,7 @@ int __open_write_db(uid_t uid, const char* path,
     return ret;
   }
 
-  ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
-      reinterpret_cast<void*>(const_cast<char*>(path)));
+  ret = sqlite3_busy_handler(*db, __db_busy_handler, (void*)path);
   if (ret != SQLITE_OK) {
     LOG(ERROR) << "failed to register busy handler:" << sqlite3_errmsg(*db);
     sqlite3_close_v2(*db);
@@ -126,8 +164,7 @@ int __open_create_db(uid_t uid, const char* path,
     return ret;
   }
 
-  ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
-      reinterpret_cast<void*>(const_cast<char*>(path)));
+  ret = sqlite3_busy_handler(*db, __db_busy_handler, (void*)path);
   if (ret != SQLITE_OK) {
     LOG(ERROR) << "failed to register busy handler:" << sqlite3_errmsg(*db);
     sqlite3_close_v2(*db);
@@ -209,6 +246,7 @@ bool AbstractDBHandler::Connect() {
       return false;
 
     db_handle_list_.emplace_back(std::make_pair(db, dbpath.second));
+    db_paths_.emplace_back(std::move(dbpath.first));
   }
 
   return true;
@@ -219,6 +257,7 @@ void AbstractDBHandler::ClearDBHandle() {
     sqlite3_close_v2(db_handle.first);
 
   db_handle_list_.clear();
+  db_paths_.clear();
 }
 
 std::vector<std::pair<sqlite3*, uid_t>> AbstractDBHandler::GetConnection() {
index e552a78544e0f8a3fba2cb021d96597851e29c21..a0d4ee0df618773eef2e4e7cac283fa6ccf3abc1 100644 (file)
@@ -66,6 +66,7 @@ class EXPORT_API AbstractDBHandler {
   pid_t pid_;
   std::string locale_;
   std::vector<std::pair<sqlite3*, uid_t>> db_handle_list_;
+  std::vector<std::string> db_paths_;
 };
 
 }  // namespace database