Improve db busy handler 23/310323/6
authorIlho Kim <ilho159.kim@samsung.com>
Thu, 25 Apr 2024 06:30:24 +0000 (15:30 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Thu, 25 Apr 2024 10:44:05 +0000 (19: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: Iba95a14fb2a41450cf011e98c83a61a1295e6c23
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
src/server/database/abstract_db_handler.cc

index e580d9638da050dd1ae99c449aa27677c2f68caf..7e829a308a286b5a082d712c7681ed6d43d0de69 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 */
+
+static void CheckDbLock(const std::string& 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.c_str(), &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);
+}
+
+bool DbBusyHandler(int count, const std::string& path) {
+  if ((count + 1) % BUSY_LOG_INTERVAL == 0 ) {
+    LOG(WARNING) << "Database is busy, waiting count : " << count;
+    CheckDbLock(path);
+  }
 
-bool ReadDbBusyHandler(int count) {
   if (count < BUSY_WAITING_MAX) {
     usleep(BUSY_WAITING_USEC);
     return true;
-  } else {
-    return false;
   }
+
+  LOG(ERROR) << "Try to access db[" << path << "] "
+      << BUSY_WAITING_MAX << " times, but can't access";
+  return false;
 }
 
 tizen_base::Database OpenReadDb(const std::string& path) {
   tizen_base::Database db(path.c_str(), SQLITE_OPEN_READONLY | SQLITE_OPEN_URI,
-      ReadDbBusyHandler);
+      [path = path] (int count) -> bool {
+        return DbBusyHandler(count, path);
+      });
 
   return db;
 }
 
-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";
-
-bool WriteDbBusyHandler(int count) {
-  if (count < (BUSY_WAITING_MAX / 2)) {
-    usleep(BUSY_WAITING_USEC);
-    return true;
-  } else if (count < BUSY_WAITING_MAX) {
-    usleep(BUSY_WAITING_USEC);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-tizen_base::Database OpenWriteDb(uid_t uid, const std::string& path) {
+tizen_base::Database OpenWriteDb(const std::string& path) {
   tizen_base::Database db(path.c_str(), SQLITE_OPEN_READWRITE,
-      WriteDbBusyHandler);
+      [path = path] (int count) -> bool {
+        return DbBusyHandler(count, path);
+      });
   db.OneStepExec({ "PRAGMA foreign_keys=ON" });
   db.OneStepExec({ "PRAGMA recursive_triggers=ON" });
 
   return db;
 }
 
-tizen_base::Database OpenCreateDb(uid_t uid, const std::string& path) {
+tizen_base::Database OpenCreateDb(const std::string& path) {
   tizen_base::Database db(path.c_str(), SQLITE_OPEN_READWRITE |
-      SQLITE_OPEN_CREATE, WriteDbBusyHandler);
+      SQLITE_OPEN_CREATE,
+      [path = path] (int count) -> bool {
+        return DbBusyHandler(count, path);
+      });
 
   return db;
 }
@@ -138,7 +185,7 @@ bool AbstractDBHandler::Connect() {
           op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE) {
         if (ConvertUID(uid) != ConvertUID(uid_))
           continue;
-        db_handle_list_.emplace_back(OpenWriteDb(uid_, path), uid);
+        db_handle_list_.emplace_back(OpenWriteDb(path), uid);
       } else {
         if (ConvertUID(uid) != ConvertUID(uid_))
           continue;
@@ -148,7 +195,7 @@ bool AbstractDBHandler::Connect() {
           return false;
         }
 
-        db_handle_list_.emplace_back(OpenCreateDb(uid_, path), uid);
+        db_handle_list_.emplace_back(OpenCreateDb(path), uid);
       }
     }
   } catch (const tizen_base::DbException& e) {