changeset 163:43d5a4e03e8d readonly-mode

added Readonly mode to try to improve transactions isolation
author amazy
date Tue, 13 Mar 2018 11:26:46 +0100 (2018-03-13)
parents c2ea17961dfc
children f0ca1c5facf6
files Core/Configuration.cpp Core/PostgreSQLConnection.cpp Core/PostgreSQLConnection.h Core/PostgreSQLTransaction.cpp StoragePlugin/PostgreSQLStorageArea.cpp
diffstat 5 files changed, 49 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Configuration.cpp	Thu Mar 08 12:27:20 2018 +0100
+++ b/Core/Configuration.cpp	Tue Mar 13 11:26:46 2018 +0100
@@ -126,6 +126,7 @@
                                          OrthancPluginContext* context,
                                          const Json::Value& configuration)
   {
+    bool readonly = false;
     useLock = true;  // Use locking by default
     std::auto_ptr<PostgreSQLConnection> connection(new PostgreSQLConnection);
 
@@ -146,6 +147,7 @@
       }
 
       useLock = GetBooleanValue(c, "Lock", useLock);
+      readonly = GetBooleanValue(c, "Readonly", readonly);
     }
 
     if (!useLock)
@@ -153,6 +155,12 @@
       OrthancPluginLogWarning(context, "Locking of the PostgreSQL database is disabled");
     }
 
+    if (readonly)
+    {
+      OrthancPluginLogWarning(context, "The PostgreSQL database is accessible in readonly mode");
+    }
+    connection->SetReadOnly(readonly);
+
     connection->Open();
 
     return connection.release();
--- a/Core/PostgreSQLConnection.cpp	Thu Mar 08 12:27:20 2018 +0100
+++ b/Core/PostgreSQLConnection.cpp	Tue Mar 13 11:26:46 2018 +0100
@@ -54,6 +54,7 @@
     username_ = "postgres";
     password_ = "postgres";
     database_ = "";
+    readonly_ = false;
     uri_.clear();
   }
 
@@ -64,6 +65,7 @@
     username_(other.username_),
     password_(other.password_),
     database_(other.database_),
+    readonly_(other.readonly_),
     pg_(NULL)
   {
   }
@@ -149,6 +151,11 @@
     database_ = database;
   }
 
+  void PostgreSQLConnection::SetReadOnly(bool readonly)
+  {
+    readonly_ = readonly;
+  }
+
   void PostgreSQLConnection::Open()
   {
     if (pg_ != NULL)
--- a/Core/PostgreSQLConnection.h	Thu Mar 08 12:27:20 2018 +0100
+++ b/Core/PostgreSQLConnection.h	Tue Mar 13 11:26:46 2018 +0100
@@ -39,6 +39,7 @@
     std::string password_;
     std::string database_;
     std::string uri_;
+    bool readonly_;
     void* pg_;   /* Object of type "PGconn*" */
 
     void Close();
@@ -104,5 +105,12 @@
     bool DoesTableExist(const char* name);
 
     void ClearAll();
+
+    void SetReadOnly(bool readonly);
+
+    bool  IsReadOnly() const
+    {
+      return readonly_;
+    }
   };
 }
--- a/Core/PostgreSQLTransaction.cpp	Thu Mar 08 12:27:20 2018 +0100
+++ b/Core/PostgreSQLTransaction.cpp	Tue Mar 13 11:26:46 2018 +0100
@@ -51,8 +51,15 @@
       throw PostgreSQLException("PostgreSQL: Beginning a transaction twice!");
     }
 
-    connection_.Execute("BEGIN");
-    connection_.Execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+    if (connection_.IsReadOnly())
+    {
+      connection_.Execute("BEGIN TRANSACTION READ ONLY");
+    }
+    else
+    {
+      connection_.Execute("BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+    }
+
     isOpen_ = true;
   }
 
--- a/StoragePlugin/PostgreSQLStorageArea.cpp	Thu Mar 08 12:27:20 2018 +0100
+++ b/StoragePlugin/PostgreSQLStorageArea.cpp	Tue Mar 13 11:26:46 2018 +0100
@@ -44,27 +44,30 @@
   {
     PostgreSQLTransaction transaction(*db_);
 
-    db_->Execute("CREATE TABLE IF NOT EXISTS StorageArea("
-                 "uuid VARCHAR NOT NULL PRIMARY KEY,"
-                 "content OID NOT NULL,"
-                 "type INTEGER NOT NULL)");
+    if (!db_->IsReadOnly())
+    {
+      db_->Execute("CREATE TABLE IF NOT EXISTS StorageArea("
+                   "uuid VARCHAR NOT NULL PRIMARY KEY,"
+                   "content OID NOT NULL,"
+                   "type INTEGER NOT NULL)");
+
+      // Automatically remove the large objects associated with the table
+      db_->Execute("CREATE OR REPLACE RULE StorageAreaDelete AS ON DELETE TO StorageArea DO SELECT lo_unlink(old.content);");
 
-    // Automatically remove the large objects associated with the table
-    db_->Execute("CREATE OR REPLACE RULE StorageAreaDelete AS ON DELETE TO StorageArea DO SELECT lo_unlink(old.content);");
+      create_.reset(new PostgreSQLStatement(*db_, "INSERT INTO StorageArea VALUES ($1,$2,$3)"));
+      create_->DeclareInputString(0);
+      create_->DeclareInputLargeObject(1);
+      create_->DeclareInputInteger(2);
 
-    create_.reset(new PostgreSQLStatement(*db_, "INSERT INTO StorageArea VALUES ($1,$2,$3)"));
-    create_->DeclareInputString(0);
-    create_->DeclareInputLargeObject(1);
-    create_->DeclareInputInteger(2);
+      remove_.reset(new PostgreSQLStatement(*db_, "DELETE FROM StorageArea WHERE uuid=$1 AND type=$2"));
+      remove_->DeclareInputString(0);
+      remove_->DeclareInputInteger(1);
+    }
 
     read_.reset(new PostgreSQLStatement(*db_, "SELECT content FROM StorageArea WHERE uuid=$1 AND type=$2"));
     read_->DeclareInputString(0);
     read_->DeclareInputInteger(1);
 
-    remove_.reset(new PostgreSQLStatement(*db_, "DELETE FROM StorageArea WHERE uuid=$1 AND type=$2"));
-    remove_->DeclareInputString(0);
-    remove_->DeclareInputInteger(1);
-
     transaction.Commit();
   }