Browse Source

Better locking? I think.

I removed the prepared statements.  I think that
helps with the database locks.
Steve Thielemann 4 years ago
parent
commit
442312f25e
2 changed files with 98 additions and 70 deletions
  1. 93 67
      db.cpp
  2. 5 3
      db.h

+ 93 - 67
db.cpp

@@ -26,23 +26,23 @@ Change the strategy so we only update when the game ends.
 
 DBData::DBData(void)
     : db("space-data.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE) {
-  locked_retries = 5;
+  locked_retries = 50;
   create_tables();
-  stmt_getSet = std::make_unique<SQLite::Statement>(
-      db, "SELECT value FROM settings WHERE username=? AND setting=?");
-  stmt_setSet = std::make_unique<SQLite::Statement>(
-      db, "REPLACE INTO settings(username, setting, value) VALUES(?,?,?);");
 }
 
 DBData::~DBData() {}
 
+void DBData::retry_wait(void) {
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
+}
+
 #define DBLOCK "database is locked"
 
 /**
  * @brief create tables if they don't exist.
  */
 void DBData::create_tables(void) {
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -59,16 +59,19 @@ PRIMARY KEY(\"username\", \"date\", \"hand\"));");
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0) {
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
+  }
 }
 
 /**
@@ -83,15 +86,17 @@ PRIMARY KEY(\"username\", \"date\", \"hand\"));");
  */
 std::string DBData::getSetting(const std::string &setting,
                                std::string ifMissing) {
-  int tries = locked_retries;
+  SQLite::Statement stmt_getSet = SQLite::Statement(
+      db, "SELECT value FROM settings WHERE username=? AND setting=?");
+  int tries = 0;
 
 retry:
   try {
-    stmt_getSet->reset();
-    stmt_getSet->bind(1, user);
-    stmt_getSet->bind(2, setting);
-    if (stmt_getSet->executeStep()) {
-      std::string value = stmt_getSet->getColumn(0);
+
+    stmt_getSet.bind(1, user);
+    stmt_getSet.bind(2, setting);
+    if (stmt_getSet.executeStep()) {
+      std::string value = stmt_getSet.getColumn(0);
       return value;
     };
     return ifMissing;
@@ -102,16 +107,20 @@ retry:
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0) {
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
+  }
+
   return ifMissing;
 }
 
@@ -125,15 +134,17 @@ retry:
  * @param value
  */
 void DBData::setSetting(const std::string &setting, const std::string &value) {
-  int tries = locked_retries;
+  SQLite::Statement stmt_setSet = SQLite::Statement(
+      db, "REPLACE INTO settings(username, setting, value) VALUES(?,?,?);");
+  int tries = 0;
 
 retry:
   try {
-    stmt_setSet->reset();
-    stmt_setSet->bind(1, user);
-    stmt_setSet->bind(2, setting);
-    stmt_setSet->bind(3, value);
-    stmt_setSet->exec();
+
+    stmt_setSet.bind(1, user);
+    stmt_setSet.bind(2, setting);
+    stmt_setSet.bind(3, value);
+    stmt_setSet.exec();
   } catch (std::exception &e) {
     if (get_logger) {
       get_logger() << "setSettings( " << setting << "," << value
@@ -141,16 +152,18 @@ retry:
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
 }
 
 /**
@@ -163,7 +176,7 @@ retry:
  * @param score
  */
 void DBData::saveScore(time_t when, time_t date, int hand, int won, int score) {
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -184,16 +197,18 @@ retry:
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
 }
 
 /**
@@ -204,7 +219,7 @@ retry:
  * @return int
  */
 int DBData::handsPlayedOnDay(time_t day) {
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -224,16 +239,18 @@ retry:
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
   return 0;
 }
 
@@ -247,7 +264,7 @@ retry:
 
 std::vector<scores_details> DBData::getScoresOnDay(time_t date) {
   std::vector<scores_details> scores;
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -272,16 +289,18 @@ retry:
     }
     scores.clear();
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
   return scores;
 }
 
@@ -293,7 +312,7 @@ retry:
  */
 std::map<time_t, std::vector<scores_data>> DBData::getScores(void) {
   std::map<time_t, std::vector<scores_data>> scores;
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -335,9 +354,9 @@ retry:
     }
     scores.clear();
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
@@ -345,6 +364,9 @@ retry:
                      << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
   return scores;
 }
 
@@ -357,7 +379,7 @@ retry:
  */
 std::map<time_t, int> DBData::getPlayed(void) {
   std::map<time_t, int> hands;
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -378,16 +400,18 @@ retry:
     }
     hands.clear();
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
   return hands;
 }
 
@@ -402,7 +426,7 @@ std::map<time_t, int> DBData::whenPlayed(void) {
   // select "date", count(hand) from scores where username='?' group by
   // "date";
   std::map<time_t, int> plays;
-  int tries = locked_retries;
+  int tries = 0;
 
 retry:
   try {
@@ -420,16 +444,18 @@ retry:
     }
     plays.clear();
     if (strcmp(e.what(), DBLOCK) == 0) {
-      --tries;
-      if (tries > 0) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+      ++tries;
+      if (tries < locked_retries) {
+        retry_wait();
         goto retry;
       }
       if (get_logger)
-        get_logger() << "giving up! " << locked_retries << " retries."
-                     << std::endl;
+        get_logger() << "giving up! " << tries << " retries." << std::endl;
     }
   }
+  if (tries > 0)
+    if (get_logger)
+      get_logger() << "success after " << tries << std::endl;
   return plays;
 }
 

+ 5 - 3
db.h

@@ -28,16 +28,18 @@ class DBData {
   void create_tables(void);
   std::string user;
   int locked_retries;
-  
+
   /*
   I thought some of my performance problems were from the prepared statement
   calls.  It was not the case, there's a weird delay when I save/hit the
   database.  This didn't fix it, but they are still present.
   Prepared statements, prepared ahead of time, are a good thing.
-   */
+   
   std::unique_ptr<SQLite::Statement> stmt_getSet;
   std::unique_ptr<SQLite::Statement> stmt_setSet;
-
+  */
+  void retry_wait(void);
+  
 public:
   DBData();
   virtual ~DBData();