Wednesday, December 10, 2014

Dynamic RLS implementation in PPAS 9.3

In the course of my work at EnterpriseDB, migrating Oracle databases to EnterpriseDB's Postgres Plus Advanced Server is a common task. However, now and then we encounter unique situations. While working on a migration project recently, we encountered a new use case for RLS (Row level Security).

The customer had a centralized database where it stored a huge number of transactions. These transactions are performed by different business units located in different parts of the world. There are certain types of transactions that should not be visible even if they are being queried by the same company. That is where RLS comes in. With RSL, specific transactions, or kinds of transactions, that can remain visible are mapped back to an attribute in the table.

The customer needed the application to authenticate users and set the context for which records in the database become visible for a specific session. In its deployment of Oracle, the customer had used the functions/procedure in the Oracle package DBMS_SESSION. In the application, the customer used DBMS_SESSION.SET_CONTEXT to set the context. And for the Row Level Security, the customer was using the DBMS_SESSION.SYS_CONTEXT to implement security around the transactions. 

Postgres Plus Advanced Server has a DBMS_SESSION package that is compatible with Oracle. However, it does not currently offer users the capability of setting the user defined context and implementing RLS based on those context. Given others may experience similar situations , as our customer, I wanted to provide the procedures and functions that users could deploy.

SET_CONTEXT procedure.

The definition of this procedure is given below:
CREATE OR REPLACE PROCEDURE set_context(namespace TEXT, 
                                        attribute TEXT, 
                                        val       TEXT)
    EXECUTE IMMEDIATE format('SET %s.%s TO %s',namespace, attribute,val);

Using this procedure, users can set their own context at session level.

The following is a function to help view the context in session, which is set using the above procedure.
                                        parameter TEXT,
                                        len       BIGINT DEFAULT 8)
    return_val TEXT;
    EXECUTE IMMEDIATE format('SHOW %s.%s',namespace,parameter) INTO return_val;
    RETURN substr(return_val,1,len);
The following is an example of how we can implement row level security based on the above procedure and functions:

1. Create a table which will have attribute context_check to map the context set by procedure:
CREATE TABLE test_rls(id numeric, col text, context_check text);
INSERT INTO test_rls SELECT id, 'First_check','aaa' FROM generate_series(1,10) foo(id);
INSERT INTO test_rls SELECT id, 'First_check','bbb' FROM generate_series(1,10) foo(id);
INSERT INTO test_rls SELECT id, 'First_check','ddd' FROM generate_series(1,10) foo(id);
2. Now create a function to check the application context. Below is one function:
CREATE OR REPLACE FUNCTION verify_user_context (
    p_schema       TEXT,
    p_object       TEXT
   predicate TEXT;
    predicate := format('context_check = public.usys_context(''%s''::text,''%s''::text, 8)','CONTEXT','APP_PREDICATE');
    RETURN predicate;
3. Now Apply Security Policy using Policy Functions shown below:
    v_object_schema         VARCHAR2(30) := 'public';
    v_object_name           VARCHAR2(30) := 'test_rls';
    v_policy_name           VARCHAR2(30) := 'secure_data';
    v_function_schema       VARCHAR2(30) := 'public';
    v_policy_function       VARCHAR2(30) := 'verify_user_context';
    v_statement_types       VARCHAR2(30) := 'INSERT,UPDATE,DELETE,SELECT';
    v_update_check          BOOLEAN      := TRUE;
    v_enable                BOOLEAN      := TRUE;
Now we are set to test this implementation. Connect to one session and try the following:

1. Set the context using procedure SET_CONTEXT as given below:

EDB-SPL Procedure successfully completed
2. Verify in the same session to determine if we have set the Context properly:
(1 row)
3. Since in session, we have Context set as ddd, there in this session, we should be able to see rows respective to set contexts:
beta=# SELECT * FROM test_rls ;
 id |     col     | context_check 
  1 | First_check | ddd
  2 | First_check | ddd
  3 | First_check | ddd
  4 | First_check | ddd
  5 | First_check | ddd
  6 | First_check | ddd
  7 | First_check | ddd
  8 | First_check | ddd
  9 | First_check | ddd
 10 | First_check | ddd
(10 rows)
As you can see, the DBMS_RLS package in Postgres Plus Advanced Service can help in implementing Row Level Security based on Application Context.

Monday, December 1, 2014

Compiling PLV8 with Postgres Plus Advanced Server

PLV8 is a programming language that lets users write stored procedures and triggers in JavaScript and store them in their Postgres database. This allows application programmers to write a lot of their server-side programming in the same language they use to build their web client applications.  Fewer languages to learn usually means fewer mistakes and faster time to completion.  The extensive language support is one of many reasons why Postgres’ use across the world is increasing lately.  The recent addition of document data support with JSON and JSONB data types in PostgreSQL, and in Postgres Plus Advanced Server from EnterpriseDB, is the main reason for the increasing interest in the PL/V8 language extension.

Below are the steps you need to compile PLV8 with Postgres Plus Advanced Server 9.3/9.4.

To get started, here are the prerequisites:
1. A supported version of PostgreSQL or Postgres Plus Advanced Server, such as versions 9.1 and higher.
2. V8 version 3.14.5
3. g++ version 4.5.1

If you want to know more about V8, you can visit the following wiki page:

It’s important to note that when compiling PLV8 with Postgres Plus Advanced Server 9.3 or the upcoming 9.4, you will get the following two types of error messages:

The first error:
[root@localhost plv8js]# make

sed -e 's/^#undef PLV8_VERSION/#define PLV8_VERSION "1.5.0-dev1"/' > plv8_config.h

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8.o In function ‘void _PG_init()’: error: invalid conversion from ‘void (*)(XactEvent, void*)’ to ‘void (*)(XactEvent, void*, bool)’ error:   initializing argument 1 of ‘void RegisterXactCallback(void (*)(XactEvent, void*, bool), void*)’

make: *** [plv8.o] Error 1

The above error message is a result of a different signature of typedef void (*XactCallback) in the Advanced Server transaction system.

To fix the above issue, the user can replace the following in
static void plv8_xact_cb(XactEvent event, void *arg);

static void plv8_xact_cb(XactEvent event, void *arg, bool spl_context);

The second error:
After making the above changes, you may get the following error after trying to compile the source code using the “make” command:
[root@localhost plv8js]# make

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8.o warning: ‘void plv8_xact_cb(XactEvent, void*, bool)’ used but never defined warning: ‘void plv8_xact_cb(XactEvent, void*)’ defined but not used

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8_type.o

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8_func.o

In file included from plv8_param.h:11,


/usr/ppas-9.4/include/server/nodes/params.h:77: error: expected ‘,’ or ‘...’ before ‘typeid’

make: *** [plv8_func.o] Error 1

The above is mainly due to the use of typeid in params.h; typeid is the reserved keyword of C++ compiler.

To fix this issue, make the following changes in plv8.h
extern "C" {

#include "postgres.h"

#include "access/htup.h"

#include "fmgr.h"

#include "mb/pg_wchar.h"

#include "utils/tuplestore.h"

#include "windowapi.h"


#define typeid __typeid

extern "C" {

#include "postgres.h"

#include "access/htup.h"

#include "fmgr.h"

#include "mb/pg_wchar.h"

#include "utils/tuplestore.h"

#include "windowapi.h"


#undef typeid

In plv8_param.h, change the following:
extern "C" {

#include "postgres.h"


 * Variable SPI parameter is since 9.0.  Avoid include files in prior versions,

 * as they contain C++ keywords.


#include "nodes/params.h"

#if PG_VERSION_NUM >= 90000

#include "parser/parse_node.h"

#endif // PG_VERSION_NUM >= 90000

} // extern "C"

#define typeid __typeid

extern "C" {

#include "postgres.h"


 * Variable SPI parameter is since 9.0.  Avoid including files in prior versions,

 * as they contain C++ keywords.


#include "nodes/params.h"

#if PG_VERSION_NUM >= 90000

#include "parser/parse_node.h"

#endif // PG_VERSION_NUM >= 90000

} // extern "C"

#undef typeid

In, replace following:
extern "C" {

#include "catalog/pg_type.h"

#include "utils/builtins.h"

#include "utils/lsyscache.h"

} // extern "C"

#define typeid __typeid

extern "C" {

#include "catalog/pg_type.h"

#include "utils/builtins.h"

#include "utils/lsyscache.h"

} // extern "C"

#undef typeid

After making the above changes, you will be able to compile PLV8 with Advanced Server as shown below:
[root@localhost plv8js]# make

sed -e 's/^#undef PLV8_VERSION/#define PLV8_VERSION "1.5.0-dev1"/' > plv8_config.h

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8.o

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8_type.o

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8_func.o

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o plv8_param.o

echo "extern const unsigned char coffee_script_binary_data[] = {" >

(od -txC -v coffee-script.js | \

 sed -e "s/^[0-9]*//" -e s"/ \([0-9a-f][0-9a-f]\)/0x\1,/g" -e"\$d" ) >>

echo "0x00};" >>

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o coffee-script.o

echo "extern const unsigned char livescript_binary_data[] = {" >

(od -txC -v livescript.js | \

 sed -e "s/^[0-9]*//" -e s"/ \([0-9a-f][0-9a-f]\)/0x\1,/g" -e"\$d" ) >>

echo "0x00};" >>

g++ -Wall -O2 -DV8_USE_UNSAFE_HANDLES  -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -fPIC -c -o livescript.o

g++ -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -I/usr/include/et -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fpic -shared -o plv8.o plv8_type.o plv8_func.o plv8_param.o coffee-script.o livescript.o -L/usr/ppas-9.4/lib -L/usr/lib64 -Wl,--as-needed -Wl,-rpath,'/usr/ppas-9.4/lib',--enable-new-dtags  -lv8

sed -e 's/@PLV8_VERSION@/1.5.0-dev1/g' plv8.control.common | g++ -E -P -DLANG_plv8 - > plv8.control

sed -e 's/@LANG_NAME@/plv8/g' plv8.sql.common | g++ -E -P -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -DLANG_plv8 - > plv8--1.5.0-dev1.sql

sed -e 's/@PLV8_VERSION@/1.5.0-dev1/g' plv8.control.common | g++ -E -P -DLANG_plcoffee - > plcoffee.control

sed -e 's/@LANG_NAME@/plcoffee/g' plv8.sql.common | g++ -E -P -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -DLANG_plcoffee - > plcoffee--1.5.0-dev1.sql

sed -e 's/@PLV8_VERSION@/1.5.0-dev1/g' plv8.control.common | g++ -E -P -DLANG_plls - > plls.control

sed -e 's/@LANG_NAME@/plls/g' plv8.sql.common | g++ -E -P -I. -I./ -I/usr/ppas-9.4/include/server -I/usr/ppas-9.4/include/internal -I/usr/include/et -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -DLANG_plls - > plls--1.5.0-dev1.sql

/bin/mkdir -p '/usr/ppas-9.4/lib'

/bin/mkdir -p '/usr/ppas-9.4/share/extension'

/bin/mkdir -p '/usr/ppas-9.4/share/extension'

/usr/bin/install -c -m 755 '/usr/ppas-9.4/lib/'

/usr/bin/install -c -m 644 plv8.control '/usr/ppas-9.4/share/extension/'

/usr/bin/install -c -m 644 plv8.control plv8--1.5.0-dev1.sql plcoffee.control plcoffee--1.5.0-dev1.sql plls.control plls--1.5.0-dev1.sql '/usr/ppas-9.4/share/extension/'

After compiling PLV8, you now can install the PLV8 language in Advanced Server using the following command:




To test your installed PLV8, here is some sample code:
beta=# DO $$ PLV8.elog(NOTICE, 'this', 'is', 'inline', 'code') $$ LANGUAGE PLV8;

NOTICE:  this is inline code


beta=# CREATE TYPE rec AS (i integer, t text);


beta=# CREATE FUNCTION set_of_records() RETURNS SETOF rec AS

beta-# $$

beta$#     // PLV8.return_next() stores records in an internal tuplestore,

beta$#     // and return all of them at the end of function.

beta$#     PLV8.return_next( { "i": 1, "t": "a" } );

beta$#     PLV8.return_next( { "i": 2, "t": "b" } );


beta$#     // You can also return records with an array of JSON.

beta$#     return [ { "i": 3, "t": "c" }, { "i": 4, "t": "d" } ];

beta$# $$



beta=# SELECT * FROM set_of_records();

 i | t


 1 | a

 2 | b

 3 | c

 4 | d

(4 rows)

In case you need a patched version of PLV8, use the following git repository: PLV8_ppas

To use this, execute the following command:
 git clone PLV8_ppas

cd PLV8_ppas


make install

To test the compiled PLV8, you can use the following command:
[root@localhost plv8js]# make installcheck

/usr/ppas-9.4/lib/pgxs/src/makefiles/../../src/test/regress/pg_regress --inputdir=./ --psqldir='/usr/ppas-9.4/bin'    --dbname=contrib_regression init-extension plv8 inline json startup_pre startup varparam json_conv window dialect

(using postmaster on Unix socket, port 5444)

============== dropping database "contrib_regression" ==============


============== creating database "contrib_regression" ==============



============== running regression test queries        ==============

test init-extension           ... ok

test plv8                     ... ok

test inline                   ... ok

test json                     ... ok

test startup_pre              ... ok

test startup                  ... ok

test varparam                 ... ok

test json_conv                ... ok

test window                   ... ok

test dialect                  ... ok


 All 10 tests passed.


Tuesday, November 18, 2014

Meet BART – A New Tool for Backup And Recovery Management

EnterpriseDB recently launched a new tool for backup and recovery – named simply EDB Backup and Recovery Tool, or BART. This tool makes the DBA’s life easier by simplifying the tasks for managing their Postgres physical backup and recovery tasks, whether they are PostgreSQL or Postgres Plus Advanced Server deployments.
BART has the following advantages over custom scripts for managing backups:
1. It’s stable and it uses the tool pg_basebackup to take a physical backup. This tool has been well defined and is well-supported by the PostgreSQL community.
2. It catalogs all of the backups users are taking, which is important in terms of:
    i. Listing the type of backups used
   ii. Listing the status of those backups with server information.
3. BART also provides functionality to restore backups, with all required archived WAL files. So automation around this tool will make DBAs’ lives easier for restore and recovery.
4. BART provides an option to validate your backup by using checksum. This is useful for confirming you took a valid backup and it is not corrupted at disk level.
5. BART provides an option to define your retention policy around the backups you are keeping.
Given all of the above advantages, I decided to give this new tool a try and share some tips. To get started, you need the following prerequisites:
1. BART currently requires a Linux 64 bit platform, CentOS 6.x or RHEL 6.x
2. Need to have password-less, direct SSH access to the target machine where you want to restore backups as well as the database servers you want backed up
3. Install the Postgres Plus Advanced Server or PostgreSQL binaries for pg_basebackup
Yum or rpm
To install this tool, you have two options that I will explore below:
1. Yum command
2. Rpm command.
Using the yum command:
To perform a yum command installation, BART users can ask EDB for credentials to the EnterpriseDB yum repository and configure the their local yum repository as follows:
echo "[tools]
name=EnterpriseDB Tools
gpgcheck=0" >/etc/yum.repos.d/edbtools.repo
After creating the yum repo, the user can execute the following command to install BART:
yum install edb-bart
If the user doesn't want to install the EDB Backup and Recovery Tool using the yum command, then the user can download a free standing rpm using the link below from EDB’s website:
and then enter the rpm install command as follows:
rpm -ivh edb-bart-1.0.1-1.rhel6.x86_64.rpm
After installing BART using the above commands, the user can see the binaries in the directory:/usr/edb-bart-1.0/bin and a sample BART configuration file in /usr/edb-bart-1.0/etc
That’s a very easy installation.
For more information on configuring BART Host and Database Host, the following are some documents that will help:
1. pg_basebackup configuration for PostgreSQL:
2. For direct password less ssh configuration user can refer following link
After the installation of the BART binaries, the user also has to create a BART configuration file.
The following is a sample configuration file for BART:
bart-host= enterprisedb@
backup_path = /opt/backup
pg_basebackup_path = /usr/ppas-9.4/bin/pg_basebackup
logfile = /tmp/bart.log

host =
port = 5432
user = postgres
description = Postgres server

host =
port = 5444
user = enterprisedb
description = PPAS 94 server
Global Configuration Settings
Content under the [BART] tag are called global configuration settings. Under this tag are the following:
1. bart-host: the IP address of the host on which BART is installed. The value for this parameter must be specified in the form: bart_user@bart_host_address, where bart_user is the operating system user account on the BART host that is used to run BART and owns the BART backup catalog directory. bart_host_address is the IP address of the BART host.
2. backup_path: specifies the file system parent directory where all BART database server base backups and archived WAL files are stored. This parameter is required.
3. pg_basebackup_path: specifies the path to the pg_basebackup program of the Postgres database server installed on the BART host.
4. log file: specifies the path to the BART log file. This parameter is optional. If no path to a log file is specified after logfile =, or if the parameter is commented out, BART does not create a log file.
The remaining part of configuration file is self-explanatory. The TAG: [PG]/[PPAS94] part is content for servers which the user wants to back up.
Pg_basebackup Settings
After performing the above configuration on the Backup Server, the user has to do set following settings on the servers that they want to back up. Below are the settings for enabling backup using pg_basebackup.
The user has to set a few parameters in PostgreSQL postgresql.conf file, which he wants to backup:
1. wal_level parameter to archive or hot_standby.
2. archive_mode=on
3. archive_command setting.
4. max_wal_senders to 1 or more than one, since pg_basebackup uses the replication protocol to copy data directory.
For more information on each setting please refer to the following:
1. wal_level:
2. archive_mode and archive_command:
3. max_wal_senders:
With the above settings, the user then needs to update the pg_hba.conf file for the replication connection.
Note: The above settings are for pg_basebackup to take backups using replication protocols. In case users need more information about pg_basebackup and settings, please use the above mentioned link
How BART Works
Now, since we have configured both servers, let’s have a look how BART works.
The following command executes a backup:
 bart -c bart.cfg BACKUP -s ppas94
And below is the output:
[bart@localhost ~]$ bart -c bart.cfg BACKUP -s ppas94

INFO:  creating backup for server 'ppas94'
INFO:  backup identifier: '1413852137762'
6394456/6394456 kB (100%), 1/1 tablespace

INFO:  backup checksum: 7f49ea9653511308710c174f22ec765d
INFO:  backup completed successfully
[bart@localhost ~]$ 
That was an easy way to take a backup. The DBA can also create a job to execute the above command to take backups.
If the user wants to list the backup using BART, the user can use the option SHOW-BACKUPS:
[bart@localhost ~]$ bart -c bart.cfg SHOW-BACKUPS -s ppas94
 Server Name   Backup ID       Backup Time           Backup Size  
 ppas94        1413852137762   2014-10-20 17:43:41   6244.59 MB   
This is useful for knowing what backups a user has available for recovery. The above command gives important information:
1. Backup ID: It’s a unique ID for the physical backup
2. Backup Time: Time when backup was taken
3. Backup Size: Size of backup
This information is useful when a user wants to plan for recovery using backup. This way, the user can also plan for disk size.
Sometimes a user wants to verify their backup state. VERIFY-CHKSUM option is useful in this case:
[bart@localhost ~]$ bart -c bart.cfg VERIFY-CHKSUM -s ppas94 -i 1413852137762
 Server Name   Backup ID       Verify  
 ppas94        1413852137762   OK
I have to say, after putting EDB BART through its paces, I think DBAs will enjoy having such a great tool for making Backup Management easy.
In my next post, I will blog about the Recovery process.

Monday, June 30, 2014

Switchover/Switchback in PostgreSQL 9.3

PostgreSQL 9.3 has two key software updates making switchover/switchback easier in High Availability configurations.

First, let’s address the software patches and their descriptions:
1. First patch was committed by Fujii Masao.
 Patch commit#  985bd7d49726c9f178558491d31a570d47340459

With this patch, the walsender process tries to send all outstanding WAL records to the standby in replication when the user shuts down the master.

This means:
 a. All WAL records are synced between two servers after the clean shutdown of the master
 b. After promoting the standby to new master, the user can restart the stopped master as new standby without a fresh backup from new master.

2. Second patch was committed by Heikki Linnakangas in PostgreSQL 9.3.
 Patch commit# abfd192b1b5ba5216ac4b1f31dcd553106304b19

Before PostgreSQL version 9.3, streaming replication used to stop replicating if the timeline on the primary didn’t match the standby. This generally happens when the user promotes one of the standbys to become the new master. Promoting a standby always results in an increment of timeline ID and after that increment, other standbys will refuse to continue replicating.

With this patch in PostgreSQL 9.3, the standby asks the primary for any timeline history files that are missing from the standby when it connects – if the standby recovery.conf file has the following setting:

The missing files are sent using a new replication command TIMELINE_HISTORY, and stored in the standby's pg_xlog directory. Using the timeline history files, the standby can follow the latest timeline present in the primary, just as it can follow new timelines appearing in an archive WAL directory.

Because of above patches, if the user performs the following sequence of steps then switchover/switchback can be easily achieved:
To switchover from Master to Standby, use following steps:
On Master:
1. Use any one of following stop options for clean shutdown.
 pg_ctl stop --pgdata=data_dire --mode=fast
 pg_ctl stop --pgdata=data_directory --mode=smart

2.  Before promoting standby:
. Make sure all WAL send by Master applied on Standby. Use following functions to verify it:
  * pg_last_xlog_receive_location()
  * pg_last_xlog_replay_location()

3.  Have the proper archive location and archive_command setting accessible to old Master.

Following is a presentation I delivered at a recent BPUG Meet (Boston PostgreSQL User Group) to discuss switchover/switchback.

Wednesday, May 21, 2014

Monitoring approach for Streaming Replication with Hot Standby in PostgreSQL 9.3.

The people using PostgreSQL and the Streaming Replication feature seem to ask many of the same questions:
1. How best to monitor Streaming Replication?
2. What is the best way to do that?
3. Are there alternatives, when monitoring on Standby, to using the pg_stat_replication view on Master?
4. How should I calculate replication lag-time, in seconds, minutes, etc.?

In light of these commonly asked questions, I thought a blog would help. The following are some methods I’ve found to be useful.

Monitoring is critical for large infrastructure deployments where you have Streaming Replication for:
1. Disaster recovery
2. Streaming Replication is for High Availability
3. Load balancing, when using Streaming Replication with Hot Standby

PostgreSQL has some building blocks for replication monitoring, and the following are some important functions and views which can be use for monitoring the replication:

1. pg_stat_replication view on master/primary server.
   This view helps in monitoring the standby on Master. It gives you the following details:

   pid:              Process id of walsender process
   usesysid:         OID of user which is used for Streaming replication.
   usename:          Name of user which is used for Streaming replication
   application_name: Application name connected to master
   client_addr:      Address of standby/streaming replication
   client_hostname:  Hostname of standby.
   client_port:      TCP port number on which standby communicating with WAL sender
   backend_start:    Start time when SR connected to Master.
   state:            Current WAL sender state i.e streaming
   sent_location:    Last transaction location sent to standby.
   write_location:   Last transaction written on disk at standby
   flush_location:   Last transaction flush on disk at standby.
   replay_location:  Last transaction flush on disk at standby.
   sync_priority:    Priority of standby server being chosen as synchronous standby
   sync_state:       Sync State of standby (is it async or synchronous).

postgres=# select * from pg_stat_replication ;
-[ RECORD 1 ]----+---------------------------------
pid              | 1114
usesysid         | 16384
usename          | repuser
application_name | walreceiver
client_addr      |
client_hostname  |
client_port      | 52444
backend_start    | 15-MAY-14 19:54:05.535695 -04:00
state            | streaming
sent_location    | 0/290044C0
write_location   | 0/290044C0
flush_location   | 0/290044C0
replay_location  | 0/290044C0
sync_priority    | 0
sync_state       | async

2. pg_is_in_recovery() : Function which tells whether standby is still in recovery mode or not.
postgres=# select pg_is_in_recovery();
(1 row)

3. pg_last_xlog_receive_location: Function which tells location of last transaction log which was streamed by Standby and also written on standby disk.
postgres=# select pg_last_xlog_receive_location();
(1 row)

4. pg_last_xlog_replay_location: Function which tells last transaction replayed during recovery process. e.g is given below:
postgres=# select pg_last_xlog_replay_location();
(1 row)

5. pg_last_xact_replay_timestamp: This function tells about the time stamp of last transaction which was replayed during recovery. Below is an example:
postgres=# select pg_last_xact_replay_timestamp();
 15-MAY-14 20:54:27.635591 -04:00
(1 row)

Above are some important functions/views, which are already available in PostgreSQL for monitoring the streaming replication.

So, the logical next question is, “What’s the right way to monitor the Hot Standby with Streaming Replication on Standby Server?”
If you have Hot Standby with Streaming Replication, the following are the points you should monitor:
1. Check if your Hot Standby is in recovery mode or not:
   For this you can use pg_is_in_recovery() function.

2.Check whether Streaming Replication is working or not.
   And easy way of doing this is checking the pg_stat_replication view on Master/Primary. This view gives information only on master if Streaming Replication is working.

3. Check If Streaming Replication is not working and Hot standby is recovering from archived WAL file.
   For this, either the DBA can use the PostgreSQL Log file to monitor it or utilize the following functions provided in PostgreSQL 9.3:


4. Check how far off is the Standby from Master.
   There are two ways to monitor lag for Standby.

   i. Lags in Bytes: For calculating lags in bytes, users can use the pg_stat_replication view on the master with the function pg_xlog_location_diff function. Below is an example:

pg_xlog_location_diff(pg_stat_replication.sent_location, pg_stat_replication.replay_location)

  which gives the lag in bytes.

  ii. Calculating lags in Seconds. The following is SQL, which most people uses to find the lag in seconds:
   SELECT CASE WHEN pg_last_xlog_receive_location() = pg_last_xlog_replay_location()
                 THEN 0
               ELSE EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())
          END AS log_delay;

Including the above into your repertoire can give you good monitoring for PostgreSQL.

I will in a future post include the script that can be used for monitoring the Hot Standby with PostgreSQL streaming replication.

Thursday, May 15, 2014

Write Operation: MongoDB Vs PostgreSQL 9.3 (JSON)

PostgreSQL 9.3 has lot of new improvement like the addition of new operators for JSON data type in postgreSQL, that prompted me to explore its features for NoSQL capabilities.

MongoDB is one of NoSQL solutions that have gotten a great deal of attention in the NoSQL market. So, this time I thought to do some benchmarking with the NoSQL capability of JSON in MongoDB and the JSON datatype in PostgreSQL 9.3

For this benchmark, I have used the same machine with no optimization in installation of PostgreSQL and MongoDB (since I wanted to see how things work, out of box with default installation). And I used the sample data from MongoDB's site, around which I had developed the functions which can generate random data using the same sample for Mongo and for PostgreSQL.

In this benchmarking, I have verified following:
1. PostgreSQL COPY Vs Mongo-Import
2. Data Disk Size of PostgreSQL and Mongo for same amount of data.
3. PostgreSQL INSERT Vs Mongo Insert

Some specification before I would display the result:
1. Operating System: CentOS 6.5, 64 bit.
2. Total Memory: 1.538 GB
3. MongoDB version: 2.4.9
4. PostgreSQL: 9.3

Below is the results which I have got:

For Bulkload (COPY Vs MongoImport):
# of rows            1000               10000         100000          1000000
mongo-import (ms)    86.241679          569.761325      6940.837053   68610.69793
PG COPY (ms)         27.36344           176.705094      1769.641917   24801.23291

Disk space utilization:

# of rows           1000        10000         100000         1000000
mongo disks (mb)    208         208           208.2033236    976
pg size (mb)     0.3515625      3.2890625     32.71875       326.8984375


# of Inserts         1000         10000         100000         1000000
MONGO INSERTS (sec)  0.521397404  4.578372454   43.92753611    449.4023542
PG INSERTS (sec)     0.326254529  4.169742939   32.21799302    319.2562722

If you look at above stats, you can see PostgreSQL JSON is much better in bulk loading and INSERTs.

Best thing is that it takes less space than MongoDB and doesn't eat up much disk space.