From 463e566cfaa8d40a0d674fb4caab1b2cad05cad3 Mon Sep 17 00:00:00 2001 From: Hari Babu Date: Wed, 27 Feb 2019 16:29:29 +1100 Subject: [PATCH 5/5] New read-only target_session_attrs type With this read-only option type, application can connect to connecting to a read-only server in the list of hosts, in case if there is any read-only servers available, the connection attempt fails. --- doc/src/sgml/libpq.sgml | 2 +- src/interfaces/libpq/fe-connect.c | 28 ++++++++++++++++++--------- src/interfaces/libpq/libpq-fe.h | 3 ++- src/interfaces/libpq/libpq-int.h | 2 +- src/test/recovery/t/001_stream_rep.pl | 14 +++++++++++++- 5 files changed, 36 insertions(+), 13 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 7918e398c7..f7331fba32 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1578,7 +1578,7 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname The supported options for this parameter are, any, - read-write and prefer-read. + read-write, prefer-read and read-only. The default value of this parameter, any, regards all connections as acceptable. If multiple hosts were specified in the connection string, based on the specified value, any remaining servers diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 55bf9f1522..0f89af0787 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -1245,6 +1245,8 @@ connectOptions2(PGconn *conn) conn->requested_session_type = SESSION_TYPE_READ_WRITE; else if (strcmp(conn->target_session_attrs, "prefer-read") == 0) conn->requested_session_type = SESSION_TYPE_PREFER_READ; + else if (strcmp(conn->target_session_attrs, "read-only") == 0) + conn->requested_session_type = SESSION_TYPE_READ_ONLY; else { conn->status = CONNECTION_BAD; @@ -3254,7 +3256,8 @@ keep_going: /* We will come back to here until there is */ if (conn->sversion >= 70400 && (conn->requested_session_type == SESSION_TYPE_READ_WRITE || - conn->requested_session_type == SESSION_TYPE_PREFER_READ)) + conn->requested_session_type == SESSION_TYPE_PREFER_READ || + conn->requested_session_type == SESSION_TYPE_READ_ONLY)) { if (conn->sversion < 120000) { @@ -3284,8 +3287,9 @@ keep_going: /* We will come back to here until there is else if ((conn->transaction_read_only && conn->requested_session_type == SESSION_TYPE_READ_WRITE) || (!conn->transaction_read_only && - conn->requested_session_type == SESSION_TYPE_PREFER_READ && - conn->read_write_host_index != -2)) + ((conn->requested_session_type == SESSION_TYPE_PREFER_READ && + conn->read_write_host_index != -2) || + conn->requested_session_type == SESSION_TYPE_READ_ONLY))) { /* Not a requested type; fail this connection. */ const char *displayed_host; @@ -3319,6 +3323,7 @@ keep_going: /* We will come back to here until there is /* Record read-write host index */ if (!conn->transaction_read_only && + conn->requested_session_type == SESSION_TYPE_PREFER_READ && conn->read_write_host_index == -1) conn->read_write_host_index = conn->whichhost; @@ -3344,15 +3349,17 @@ keep_going: /* We will come back to here until there is * Requested type is prefer-read, then record this host index * and try the other before considering it later */ - if (conn->requested_session_type == SESSION_TYPE_PREFER_READ && - conn->read_write_host_index != -2) + if ((conn->requested_session_type == SESSION_TYPE_PREFER_READ && + conn->read_write_host_index != -2) || + conn->requested_session_type == SESSION_TYPE_READ_ONLY) { /* Close connection politely. */ conn->status = CONNECTION_OK; sendTerminateConn(conn); /* Record read-write host index */ - if (conn->read_write_host_index == -1) + if (conn->requested_session_type == SESSION_TYPE_PREFER_READ && + conn->read_write_host_index == -1) conn->read_write_host_index = conn->whichhost; /* @@ -3443,8 +3450,9 @@ keep_going: /* We will come back to here until there is if ((readonly_server && conn->requested_session_type == SESSION_TYPE_READ_WRITE) || (!readonly_server && - conn->requested_session_type == SESSION_TYPE_PREFER_READ && - conn->read_write_host_index != -2)) + ((conn->requested_session_type == SESSION_TYPE_PREFER_READ && + conn->read_write_host_index != -2) || + conn->requested_session_type == SESSION_TYPE_READ_ONLY))) { /* Not a requested type; fail this connection. */ PQclear(res); @@ -3477,7 +3485,9 @@ keep_going: /* We will come back to here until there is sendTerminateConn(conn); /* Record read-write host index */ - if (!readonly_server && conn->read_write_host_index == -1) + if (!readonly_server && + conn->requested_session_type == SESSION_TYPE_PREFER_READ && + conn->read_write_host_index == -1) conn->read_write_host_index = conn->whichhost; /* diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 4b0fc80df2..5d0b885dae 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -74,7 +74,8 @@ typedef enum { SESSION_TYPE_ANY = 0, /* Any session (default) */ SESSION_TYPE_READ_WRITE, /* Read-write session */ - SESSION_TYPE_PREFER_READ /* Prefer read only session */ + SESSION_TYPE_PREFER_READ, /* Prefer read only session */ + SESSION_TYPE_READ_ONLY /* Read only session */ } TargetSessionAttrsType; typedef enum diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index d6c482fd0b..8690f86956 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -365,7 +365,7 @@ struct pg_conn /* * Type of connection to make. Possible values: any, read-write, - * prefer-read. + * prefer-read and read-only. */ char *target_session_attrs; TargetSessionAttrsType requested_session_type; diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index 0e398136a5..0d6f279586 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -3,7 +3,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 29; +use Test::More tests => 32; # Initialize master node my $node_master = get_new_node('master'); @@ -129,6 +129,18 @@ test_target_session_attrs($node_standby_1, $node_master, $node_standby_1, test_target_session_attrs($node_master, $node_master, $node_master, "prefer-read", 0); +# Connect to standby1 in "read-only" mode with master,standby1 list. +test_target_session_attrs($node_master, $node_standby_1, $node_standby_1, + "read-only", 0); + +# Connect to standby1 in "read-only" mode with standby1,master list. +test_target_session_attrs($node_standby_1, $node_master, $node_standby_1, + "read-only", 0); + +# Connection should fail in "read-only" mode with only master list. +test_target_session_attrs($node_master, $node_master, $node_master, + "read-only", 1); + note "switching to physical replication slot"; # Switch to using a physical replication slot. We can do this without a new -- 2.20.1.windows.1