diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9f417de..07d5f85 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -21,6 +21,7 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+#include "access/xlog.h"
 #include "access/clog.h"
 #include "access/multixact.h"
 #include "access/rewriteheap.h"
@@ -61,6 +62,9 @@
 #include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
+#include "utils/pg_lzcompress.h"
+#include "utils/pg_snappy.h"
+#include "utils/pg_lz4.h"
 #include "utils/ps_status.h"
 #include "utils/relmapper.h"
 #include "utils/snapmgr.h"
@@ -85,6 +89,7 @@ bool		XLogArchiveMode = false;
 char	   *XLogArchiveCommand = NULL;
 bool		EnableHotStandby = false;
 bool		fullPageWrites = true;
+int			full_page_compression = BACKUP_BLOCK_COMPRESSION_OFF;
 bool		wal_log_hints = false;
 bool		log_checkpoints = false;
 int			sync_method = DEFAULT_SYNC_METHOD;
@@ -741,6 +746,10 @@ static bool holdingAllLocks = false;
 static MemoryContext walDebugCxt = NULL;
 #endif
 
+/* For storing backup blocks before and after compression */
+static char *compressed_pages;
+static char *uncompressed_pages;
+
 static void readRecoveryCommandFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsBefore(XLogRecord *record);
@@ -813,6 +822,7 @@ static void ReserveXLogInsertLocation(int size, XLogRecPtr *StartPos,
 static bool ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos,
 				  XLogRecPtr *PrevPtr);
 static XLogRecPtr WaitXLogInsertionsToFinish(XLogRecPtr upto);
+static char *CompressBackupBlock(char *page, uint32 orig_len, char *dest, uint32 *len);
 static char *GetXLogBuffer(XLogRecPtr ptr);
 static XLogRecPtr XLogBytePosToRecPtr(uint64 bytepos);
 static XLogRecPtr XLogBytePosToEndRecPtr(uint64 bytepos);
@@ -864,6 +874,11 @@ XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata)
 	XLogRecPtr	StartPos;
 	XLogRecPtr	EndPos;
 
+	char *compressed_blocks;
+	int orig_len = 0;
+	uint32 compressed_len = 0;
+	bool compressed = 0;
+
 	if (rechdr == NULL)
 	{
 		static char rechdrbuf[SizeOfXLogRecord + MAXIMUM_ALIGNOF];
@@ -1042,8 +1057,47 @@ begin:;
 			write_len += rdt->len;
 			rdt->next = NULL;
 		}
+
+	}
+
+	/*
+     * If compression is set on replace the rdata chains of backup blocks added in the loop
+     * above by single rdata node that contains compressed backupblocks and their headers
+     */
+	if (full_page_compression != BACKUP_BLOCK_COMPRESSION_OFF)
+	{
+		for (rdt = rdt_lastnormal->next; rdt != NULL; rdt = rdt->next)
+		{
+			memcpy(uncompressed_pages + orig_len, rdt->data, rdt->len);
+			orig_len += rdt->len;
+		}
+		if(orig_len)
+		{
+			/* Compress the backup blocks before including it in rdata chain */
+			compressed_blocks = CompressBackupBlock(uncompressed_pages, orig_len,
+											compressed_pages, &(compressed_len));
+			if (compressed_blocks != NULL)
+			{
+				/*
+				 * write_len is the length of compressed block and its varlena
+				 * header
+				 */
+				rdt = rdt_lastnormal->next;
+				rdt->data = compressed_blocks;
+				rdt->len = compressed_len;
+				write_len = len;
+				write_len += rdt->len;
+				rdt->next = NULL;
+				compressed = 1;
+			}
+		}
 	}
 
+		/* Adding information about compression in record header */
+	if (!compressed)
+		rechdr->xl_compress = BACKUP_BLOCK_COMPRESSION_OFF;
+	else
+		rechdr->xl_compress = full_page_compression;
 	/*
 	 * Calculate CRC of the data, including all the backup blocks
 	 *
@@ -1774,6 +1828,65 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 }
 
 /*
+ * Create a compressed version of a backup block
+ *
+ * If successful, return a compressed result and set 'len' to its length.
+ * Otherwise (ie, compressed result is actually bigger than original),
+ * return NULL.
+ */
+static char *
+CompressBackupBlock(char *page, uint32 orig_len, char *dest, uint32 *len)
+{
+	struct varlena *buf = (struct varlena *) dest;
+
+	if (full_page_compression == BACKUP_BLOCK_COMPRESSION_SNAPPY)
+	{
+		int ret;
+		ret = pg_snappy_compress(page,orig_len,buf);
+		/* EIO is returned for incompressible data */
+		if (ret == EIO)
+			return NULL;
+	}
+	else if (full_page_compression == BACKUP_BLOCK_COMPRESSION_LZ4)
+	{
+		int ret;
+		ret = pg_LZ4_compress(page,orig_len,buf);
+		/* Zero is returned for incompressible data */
+		if (ret == 0)
+			return NULL;
+	}
+	else if (full_page_compression == BACKUP_BLOCK_COMPRESSION_PGLZ)
+	{
+		bool ret;
+		ret = pglz_compress(page, orig_len,
+							(PGLZ_Header *) buf, PGLZ_strategy_default);
+		/* Zero is returned for incompressible data */
+		if(!ret)
+			return NULL;
+	}
+	else
+		elog(ERROR, "Wrong value for full_page_compression GUC");
+
+	/*
+	 * We recheck the actual size even if pglz_compress(),pg_LZ4_compress() and
+	 * pg_snappy_compress report success,
+	 * because it might be satisfied with having saved as little as one byte
+	 * in the compressed data --- which could turn into a net loss once you
+	 * consider header and alignment padding.  Worst case, the compressed
+	 * format might require three padding bytes (plus header, which is
+	 * included in VARSIZE(buf)), whereas the uncompressed format would take
+	 * only one header byte and no padding if the value is short enough.  So
+	 * we insist on a savings of more than 2 bytes to ensure we have a gain.
+	*/
+	if(VARSIZE(buf) >= orig_len - 2)
+	{
+		return NULL;
+	}
+	*len = VARSIZE(buf);
+	return (char *) buf;
+}
+
+/*
  * Get a pointer to the right location in the WAL buffer containing the
  * given XLogRecPtr.
  *
@@ -4017,9 +4130,48 @@ RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record, int block_index,
 	BkpBlock	bkpb;
 	char	   *blk;
 	int			i;
+	char *blk_uncompress = (char *)palloc(XLR_TOTAL_BLCKSZ);
 
 	/* Locate requested BkpBlock in the record */
 	blk = (char *) XLogRecGetData(record) + record->xl_len;
+
+	/* check if blocks in WAL record are compressed */
+	if (record->xl_compress != BACKUP_BLOCK_COMPRESSION_OFF)
+	{
+		if (record->xl_compress == BACKUP_BLOCK_COMPRESSION_SNAPPY)
+		{
+			int ret;
+			size_t compressed_length = VARSIZE((struct varlena *) blk) - VARHDRSZ;
+			char *compressed_data = (char *)VARDATA((struct varlena *) blk);
+			size_t s_uncompressed_length;
+
+			ret = snappy_uncompressed_length(compressed_data,compressed_length,
+											&s_uncompressed_length);
+			if (!ret)
+				elog(ERROR, "snappy: failed to determine compression length");
+
+			ret = snappy_uncompress(compressed_data,
+									compressed_length,
+									blk_uncompress);
+			if (ret != 0)
+				elog(ERROR, "snappy: decompression failed: %d", ret);
+		}
+		else if (record->xl_compress == BACKUP_BLOCK_COMPRESSION_LZ4)
+		{
+			int ret;
+			size_t compressed_length = VARSIZE((struct varlena *) blk) - VARHDRSZ;
+			char *compressed_data = (char *)VARDATA((struct varlena *) blk);
+			ret = LZ4_uncompress_unknownOutputSize(compressed_data,blk_uncompress,compressed_length,XLR_TOTAL_BLCKSZ);
+		}
+		else if (record->xl_compress == BACKUP_BLOCK_COMPRESSION_PGLZ)
+		{
+			/* Checks to see if decompression is successful is made inside the function */
+			pglz_decompress((PGLZ_Header *) blk, blk_uncompress);
+		}
+		else
+			elog(ERROR, "Wrong value for compression algorithm in block header");
+		blk = blk_uncompress;
+	}
 	for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
 	{
 		if (!(record->xl_info & XLR_BKP_BLOCK(i)))
@@ -4034,7 +4186,6 @@ RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record, int block_index,
 			return RestoreBackupBlockContents(lsn, bkpb, blk, get_cleanup_lock,
 											  keep_buffer);
 		}
-
 		blk += BLCKSZ - bkpb.hole_length;
 	}
 
@@ -7233,6 +7384,9 @@ StartupXLOG(void)
 	 */
 	if (fast_promoted)
 		RequestCheckpoint(CHECKPOINT_FORCE);
+
+	/* Allocate pages to store compressed backup blocks */
+	CompressBackupBlockPagesAlloc();
 }
 
 /*
@@ -7626,9 +7780,41 @@ InitXLOGAccess(void)
 
 	/* Use GetRedoRecPtr to copy the RedoRecPtr safely */
 	(void) GetRedoRecPtr();
+
+	/* Allocate pages to store compressed backup blocks */
+	CompressBackupBlockPagesAlloc();
 }
 
 /*
+ * Allocate pages to store compressed backup blocks once per backend.
+ * Size of pages depend on the compression algorithm used. These pages
+ * persist till the end of the backend process. If memory allocation
+ * fails we disable compression of backup blocks entirely.
+ */
+void
+CompressBackupBlockPagesAlloc(void)
+{
+
+	if (full_page_compression != BACKUP_BLOCK_COMPRESSION_OFF &&
+		compressed_pages == NULL)
+	{
+		size_t buffer_size = VARHDRSZ;
+		if (full_page_compression == BACKUP_BLOCK_COMPRESSION_SNAPPY)
+			buffer_size += snappy_max_compressed_length(XLR_TOTAL_BLCKSZ);
+		else if (full_page_compression == BACKUP_BLOCK_COMPRESSION_LZ4)
+			buffer_size += LZ4_compressBound(XLR_TOTAL_BLCKSZ);
+		else if (full_page_compression == BACKUP_BLOCK_COMPRESSION_PGLZ)
+			buffer_size += PGLZ_MAX_OUTPUT(XLR_TOTAL_BLCKSZ);
+		compressed_pages = (char *) malloc(buffer_size);
+		if(compressed_pages == NULL)
+			full_page_compression = BACKUP_BLOCK_COMPRESSION_OFF;
+
+		uncompressed_pages = (char *)malloc(XLR_TOTAL_BLCKSZ);
+		if(	uncompressed_pages == NULL)
+			full_page_compression = BACKUP_BLOCK_COMPRESSION_OFF;
+	}
+}
+/*
  * Return the current Redo pointer from shared memory.
  *
  * As a side-effect, the local RedoRecPtr copy is updated.
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index f06daa2..a22d702 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -15,6 +15,9 @@
 
 #include "postgres.h"
 
+#include "utils/pg_lzcompress.h"
+#include "utils/pg_snappy.h"
+#include "utils/pg_lz4.h"
 #include "access/transam.h"
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
@@ -689,52 +692,56 @@ ValidXLogRecord(XLogReaderState *state, XLogRecord *record, XLogRecPtr recptr)
 
 	/* Add in the backup blocks, if any */
 	blk = (char *) XLogRecGetData(record) + len;
-	for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
+	if (record->xl_compress == BACKUP_BLOCK_COMPRESSION_OFF)
 	{
-		uint32		blen;
+		for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
+		{
+			uint32		blen;
 
-		if (!(record->xl_info & XLR_BKP_BLOCK(i)))
-			continue;
+			if (!(record->xl_info & XLR_BKP_BLOCK(i)))
+				continue;
 
-		if (remaining < sizeof(BkpBlock))
-		{
-			report_invalid_record(state,
+			if (remaining < sizeof(BkpBlock))
+			{
+				report_invalid_record(state,
 							  "invalid backup block size in record at %X/%X",
 								  (uint32) (recptr >> 32), (uint32) recptr);
-			return false;
-		}
-		memcpy(&bkpb, blk, sizeof(BkpBlock));
+				return false;
+			}
+			memcpy(&bkpb, blk, sizeof(BkpBlock));
 
-		if (bkpb.hole_offset + bkpb.hole_length > BLCKSZ)
-		{
-			report_invalid_record(state,
+			if (bkpb.hole_offset + bkpb.hole_length > BLCKSZ)
+			{
+				report_invalid_record(state,
 								  "incorrect hole size in record at %X/%X",
 								  (uint32) (recptr >> 32), (uint32) recptr);
-			return false;
-		}
-		blen = sizeof(BkpBlock) + BLCKSZ - bkpb.hole_length;
+				return false;
+			}
 
-		if (remaining < blen)
-		{
-			report_invalid_record(state,
+			blen = sizeof(BkpBlock) + BLCKSZ - bkpb.hole_length;
+
+			if (remaining < blen)
+			{
+				report_invalid_record(state,
 							  "invalid backup block size in record at %X/%X",
 								  (uint32) (recptr >> 32), (uint32) recptr);
-			return false;
+				return false;
+			}
+			remaining -= blen;
+			COMP_CRC32(crc, blk, blen);
+			blk += blen;
 		}
-		remaining -= blen;
-		COMP_CRC32(crc, blk, blen);
-		blk += blen;
-	}
-
-	/* Check that xl_tot_len agrees with our calculation */
-	if (remaining != 0)
-	{
-		report_invalid_record(state,
+		/* Check that xl_tot_len agrees with our calculation */
+		if (remaining != 0)
+		{
+			report_invalid_record(state,
 							  "incorrect total length in record at %X/%X",
 							  (uint32) (recptr >> 32), (uint32) recptr);
-		return false;
+			return false;
+		}
 	}
-
+	else
+		COMP_CRC32(crc, blk, remaining);
 	/* Finally include the record header */
 	COMP_CRC32(crc, (char *) record, offsetof(XLogRecord, xl_crc));
 	FIN_CRC32(crc);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 3a31a75..93bc994 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -403,6 +403,22 @@ static const struct config_enum_entry huge_pages_options[] = {
 	{NULL, 0, false}
 };
 
+
+/*
+ * Although only "off" in documented, we accept all likely variants of "off".
+ * "on" is indicated by specifying name of compression algorithm.
+ */
+static const struct config_enum_entry backup_block_compression_options[] = {
+	{"off", BACKUP_BLOCK_COMPRESSION_OFF, false},
+	{"false", BACKUP_BLOCK_COMPRESSION_OFF, true},
+	{"no", BACKUP_BLOCK_COMPRESSION_OFF, true},
+	{"0", BACKUP_BLOCK_COMPRESSION_OFF, true},
+	{"pglz", BACKUP_BLOCK_COMPRESSION_PGLZ, true},
+	{"snappy", BACKUP_BLOCK_COMPRESSION_SNAPPY, true},
+	{"lz4", BACKUP_BLOCK_COMPRESSION_LZ4, true},
+	{NULL, 0, false}
+};
+
 /*
  * Options for enum values stored in other modules
  */
@@ -3510,6 +3526,16 @@ static struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"full_page_compression", PGC_SIGHUP, WAL_SETTINGS,
+			gettext_noop("Compress backup block in WAL using specified compression algorithm."),
+			NULL
+		},
+		&full_page_compression,
+		BACKUP_BLOCK_COMPRESSION_OFF, backup_block_compression_options,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..9db8e64 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -45,10 +45,10 @@ typedef struct XLogRecord
 	uint32		xl_len;			/* total len of rmgr data */
 	uint8		xl_info;		/* flag bits, see below */
 	RmgrId		xl_rmid;		/* resource manager for this record */
-	/* 2 bytes of padding here, initialize to zero */
+	/* 1 byte of padding here, initialize to zero */
+    uint8		xl_compress;		/* compression of fpws in record */
 	XLogRecPtr	xl_prev;		/* ptr to previous record in log */
 	pg_crc32	xl_crc;			/* CRC for this record */
-
 	/* If MAXALIGN==8, there are 4 wasted bytes here */
 
 	/* ACTUAL LOG DATA FOLLOWS AT END OF STRUCT */
@@ -177,6 +177,14 @@ typedef enum
 	RECOVERY_TARGET_IMMEDIATE
 } RecoveryTargetType;
 
+typedef enum
+{
+	BACKUP_BLOCK_COMPRESSION_OFF,
+	BACKUP_BLOCK_COMPRESSION_PGLZ,
+	BACKUP_BLOCK_COMPRESSION_SNAPPY,
+	BACKUP_BLOCK_COMPRESSION_LZ4
+} BackupBlockCompressionAlgorithm;
+
 extern XLogRecPtr XactLastRecEnd;
 
 extern bool reachedConsistency;
@@ -190,6 +198,7 @@ extern bool XLogArchiveMode;
 extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
+extern int full_page_compression;
 extern bool wal_log_hints;
 extern bool log_checkpoints;
 extern int	num_xloginsert_locks;
@@ -252,7 +261,8 @@ extern bool XLOG_DEBUG;
 /* These indicate the cause of a checkpoint request */
 #define CHECKPOINT_CAUSE_XLOG	0x0020	/* XLOG consumption */
 #define CHECKPOINT_CAUSE_TIME	0x0040	/* Elapsed time */
-
+/* Total size of maximum number of backup blocks including their headers in an XLOG record */
+#define XLR_TOTAL_BLCKSZ XLR_MAX_BKP_BLOCKS * BLCKSZ + XLR_MAX_BKP_BLOCKS * sizeof(BkpBlock)
 /* Checkpoint statistics */
 typedef struct CheckpointStatsData
 {
@@ -340,6 +350,7 @@ extern bool CheckPromoteSignal(void);
 extern void WakeupRecovery(void);
 extern void SetWalWriterSleeping(bool sleeping);
 
+extern void CompressBackupBlockPagesAlloc(void);
 /*
  * Starting/stopping a base backup
  */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..d8b13fd 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -48,7 +48,6 @@ typedef struct BkpBlock
 	BlockNumber block;			/* block number */
 	uint16		hole_offset;	/* number of bytes before "hole" */
 	uint16		hole_length;	/* number of bytes in "hole" */
-
 	/* ACTUAL BLOCK DATA FOLLOWS AT END OF STRUCT */
 } BkpBlock;
 
diff --git a/src/include/utils/pg_lz4.h b/src/include/utils/pg_lz4.h
index dfae502..4aa5e47 100644
--- a/src/include/utils/pg_lz4.h
+++ b/src/include/utils/pg_lz4.h
@@ -1,6 +1,7 @@
 #ifndef _PG_LZ4
 #define _PG_LZ4
 int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
+int LZ4_uncompress_unknownOutputSize(const char* compressed_data, char* blk_uncompress, int compressed_length, int originalSize);
 int LZ4_compressBound(int isize);
 int pg_LZ4_compress(const char *source, int32 slen, struct varlena *dest);
 #endif
