Thread: read-only database

read-only database

From
Satoshi Nagayasu
Date:
Hi all,

I've read TODO list in the 8.0.1,
then I'm interested in the following topic.

> * Allow a warm standby system to also allow read-only queries

Does anyone have any plan to work on this?

I think we need to extend the pg_database catalog to
have a database state (read-only or writable),
and also need to extend ALTER DATABASE command
to change the state.

To make a database read-only, ALTER DATABASE command may change
MyDatabaseReadOnly flag (like XactReadOnly)
and update the pg_database catalog.
If MyDatabaseReadOnly is true, check_xact_readonly() or
ExecCheckXactReadOnly() will prevent from updating the database.

Otherwise, I think we can also prevent from updating the database
around acquiring the XLogInsert lock.

Any ideas?  or any suggestions?

-- 
NAGAYASU Satoshi <nagayasus@nttdata.co.jp>
OpenSource Development Center,
NTT DATA Corp. http://www.nttdata.co.jp



Re: read-only database

From
Tom Lane
Date:
Satoshi Nagayasu <nagayasus@nttdata.co.jp> writes:
>> * Allow a warm standby system to also allow read-only queries

> Does anyone have any plan to work on this?

> I think we need to extend the pg_database catalog to
> have a database state (read-only or writable),
> and also need to extend ALTER DATABASE command
> to change the state.

Uh, no, because changing that would by definition not be a read-only
operation.  Therefore there'd be no way to enter the read-only state,
and definitely no way to get out of it again.  Furthermore, the
envisioned behavior is cluster-wide not per-database: the point is
to not execute transactions and not generate WAL entries, and you
don't get to be selective about that.  (If it doesn't work like that,
you couldn't use it for the intended purpose of examining the state
of a hot-standby PITR backup that is actively tracking WAL logs
shipped from a master.  It'd also not be useful for looking at
a corrupted cluster.)

I'd view this as a postmaster state that propagates to backends.
Probably you'd enable it by means of a postmaster option, and the
only way to get out of it is to shut down and restart the postmaster
without the option.
        regards, tom lane


Re: read-only database

From
Satoshi Nagayasu
Date:
Tom Lane wrote:
> Uh, no, because changing that would by definition not be a read-only
> operation.  Therefore there'd be no way to enter the read-only state,
> and definitely no way to get out of it again.

I saw Oracle's reference manual, and found ALTER DATABASE OPEN READ ONLY command
to make a stand-by database.

In Oracle, when the user execute the command, the database goes read-only mode.
Is this a bad idea?

I guess some users need per-database read-only state.
Don't we need to have both read-only and writable databases in single cluster?

Of course, the super-user can change the database state even in read-only.

> Furthermore, the
> envisioned behavior is cluster-wide not per-database: the point is
> to not execute transactions and not generate WAL entries, and you
> don't get to be selective about that.  (If it doesn't work like that,
> you couldn't use it for the intended purpose of examining the state
> of a hot-standby PITR backup that is actively tracking WAL logs
> shipped from a master.  It'd also not be useful for looking at
> a corrupted cluster.)
>
> I'd view this as a postmaster state that propagates to backends.
> Probably you'd enable it by means of a postmaster option, and the
> only way to get out of it is to shut down and restart the postmaster
> without the option.

I agree this is a reasonable way to make cluster-wide read-only state.

-- 
NAGAYASU Satoshi <nagayasus@nttdata.co.jp>
OpenSource Development Center,
NTT DATA Corp. http://www.nttdata.co.jp/


Re: read-only database

From
Tom Lane
Date:
Satoshi Nagayasu <nagayasus@nttdata.co.jp> writes:
> Tom Lane wrote:
>> Uh, no, because changing that would by definition not be a read-only
>> operation.  Therefore there'd be no way to enter the read-only state,
>> and definitely no way to get out of it again.

> I saw Oracle's reference manual, and found ALTER DATABASE OPEN READ ONLY command
> to make a stand-by database.

Perhaps, but that's *not* what the TODO item is about.
        regards, tom lane


Re: read-only database

From
Satoshi Nagayasu
Date:
Tom Lane wrote:
>>I saw Oracle's reference manual, and found ALTER DATABASE OPEN READ ONLY command
>>to make a stand-by database.
> 
> Perhaps, but that's *not* what the TODO item is about.

I see.

Thanks for comments.
-- 
NAGAYASU Satoshi <nagayasus@nttdata.co.jp>
OpenSource Development Center,
NTT DATA Corp. http://www.nttdata.co.jp/


Re: read-only database

From
Simon Riggs
Date:
On Thu, 2005-03-17 at 12:40 +0900, Satoshi Nagayasu wrote:
> Tom Lane wrote:
> >>I saw Oracle's reference manual, and found ALTER DATABASE OPEN READ ONLY command
> >>to make a stand-by database.
> > 
> > Perhaps, but that's *not* what the TODO item is about.
> 
> I see.
> 
> Thanks for comments.

The Oracle ALTER DATABASE command is part of the multi-step process to
mount an Oracle database into a running instance. It isn't something
that you can dip in and out of when you choose, as far as I am aware:
you can only run it on a warm standby database that is receiving logs
shipped from another database.
i.e. Oracle warm-standby databases have 3 run states (ok, more, but...)
1. warm standby
2. read-only
3. fully-operational
You can switch between 1 and 2 and back again, but once you go to 3 then
you cannot switch back.

What Tom just proposed about having an additional run-state between
running-recovery and fully-operational is essentially the same thing.
Tom's overall strategy would be workable in PostgreSQL terms, with some
work and would provide similar functionality to Oracle.

Having said that, I believe we're not close to making that work just yet
- its a good end goal because there may be choices along the way that
may need to consider the longer term goal.

Best Regards, Simon Riggs





Re: read-only database

From
Satoshi Nagayasu
Date:
Tom Lane wrote:
> I'd view this as a postmaster state that propagates to backends.
> Probably you'd enable it by means of a postmaster option, and the
> only way to get out of it is to shut down and restart the postmaster
> without the option.

I've created a patch to make a postmaster read-only.
(attached patch can be applied to 8.0.1)

Read-only state can be enabled/disabled by the postmaster option,
or the postgresql.conf option.

If you start the postmaster with "-r" options,
the cluster will go to read-only.

% pg_ctl -o "-i -r" -D $PGDATA start

Or if you set "readonly_cluster = true" in the postgresql.conf,
the cluster will also become read-only.

Any comments?
--
NAGAYASU Satoshi <nagayasus@nttdata.co.jp>
OpenSource Development Center,
NTT DATA Corp. http://www.nttdata.co.jp
diff -ru postgresql-8.0.1.orig/src/backend/executor/execMain.c postgresql-8.0.1/src/backend/executor/execMain.c
--- postgresql-8.0.1.orig/src/backend/executor/execMain.c    2005-01-15 02:53:33.000000000 +0900
+++ postgresql-8.0.1/src/backend/executor/execMain.c    2005-03-21 13:12:22.000000000 +0900
@@ -43,6 +43,7 @@
 #include "optimizer/clauses.h"
 #include "optimizer/var.h"
 #include "parser/parsetree.h"
+#include "postmaster/postmaster.h"
 #include "utils/acl.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
@@ -127,7 +128,7 @@
      * If the transaction is read-only, we need to check if any writes are
      * planned to non-temporary tables.
      */
-    if (XactReadOnly && !explainOnly)
+    if ( (XactReadOnly || ReadOnlyCluster) && !explainOnly)
         ExecCheckXactReadOnly(queryDesc->parsetree);

     /*
diff -ru postgresql-8.0.1.orig/src/backend/postmaster/postmaster.c postgresql-8.0.1/src/backend/postmaster/postmaster.c
--- postgresql-8.0.1.orig/src/backend/postmaster/postmaster.c    2005-01-13 01:38:17.000000000 +0900
+++ postgresql-8.0.1/src/backend/postmaster/postmaster.c    2005-03-21 13:21:17.000000000 +0900
@@ -236,6 +236,8 @@
 extern int    optreset;
 #endif

+bool        ReadOnlyCluster = false;
+
 /*
  * postmaster.c - function prototypes
  */
@@ -440,7 +442,7 @@

     opterr = 1;

-    while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
+    while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:rSs-:")) != -1)
     {
         switch (opt)
         {
@@ -515,6 +517,9 @@
             case 'p':
                 SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                 break;
+            case 'r':
+                SetConfigOption("readonly_cluster", "true", PGC_POSTMASTER, PGC_S_ARGV);
+                break;
             case 'S':

                 /*
diff -ru postgresql-8.0.1.orig/src/backend/tcop/utility.c postgresql-8.0.1/src/backend/tcop/utility.c
--- postgresql-8.0.1.orig/src/backend/tcop/utility.c    2005-01-25 02:46:29.000000000 +0900
+++ postgresql-8.0.1/src/backend/tcop/utility.c    2005-03-21 13:13:45.000000000 +0900
@@ -47,6 +47,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_type.h"
 #include "postmaster/bgwriter.h"
+#include "postmaster/postmaster.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteRemove.h"
 #include "storage/fd.h"
@@ -265,7 +266,7 @@
 static void
 check_xact_readonly(Node *parsetree)
 {
-    if (!XactReadOnly)
+    if (!XactReadOnly && !ReadOnlyCluster)
         return;

     /*
diff -ru postgresql-8.0.1.orig/src/backend/utils/misc/guc.c postgresql-8.0.1/src/backend/utils/misc/guc.c
--- postgresql-8.0.1.orig/src/backend/utils/misc/guc.c    2005-01-01 14:43:08.000000000 +0900
+++ postgresql-8.0.1/src/backend/utils/misc/guc.c    2005-03-21 13:06:42.000000000 +0900
@@ -851,6 +851,15 @@
 #endif
     },

+    {
+        {"readonly_cluster", PGC_POSTMASTER, UNGROUPED,
+            gettext_noop("Enables the postmaster read-only."),
+            NULL
+        },
+        &ReadOnlyCluster,
+        false, NULL, NULL
+    },
+
     /* End-of-list marker */
     {
         {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL
diff -ru postgresql-8.0.1.orig/src/include/postmaster/postmaster.h postgresql-8.0.1/src/include/postmaster/postmaster.h
--- postgresql-8.0.1.orig/src/include/postmaster/postmaster.h    2005-01-01 07:03:39.000000000 +0900
+++ postgresql-8.0.1/src/include/postmaster/postmaster.h    2005-03-21 13:03:16.000000000 +0900
@@ -34,6 +34,7 @@
 extern HANDLE PostmasterHandle;
 #endif

+extern bool ReadOnlyCluster;

 extern int    PostmasterMain(int argc, char *argv[]);
 extern void ClosePostmasterPorts(bool am_syslogger);