*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 1805,1817 **** include 'filename'
       </varlistentry>
  
       <varlistentry id="guc-full-page-writes" xreflabel="full_page_writes">
!       <term><varname>full_page_writes</varname> (<type>boolean</type>)</term>
        <indexterm>
         <primary><varname>full_page_writes</> configuration parameter</primary>
        </indexterm>
        <listitem>
         <para>
!         When this parameter is on, the <productname>PostgreSQL</> server
          writes the entire content of each disk page to WAL during the
          first modification of that page after a checkpoint.
          This is needed because
--- 1805,1818 ----
       </varlistentry>
  
       <varlistentry id="guc-full-page-writes" xreflabel="full_page_writes">
!       <term><varname>full_page_writes</varname> (<type>enum</type>)</term>
        <indexterm>
         <primary><varname>full_page_writes</> configuration parameter</primary>
        </indexterm>
        <listitem>
         <para>
!         When this parameter is <literal>on</> or <literal>compress</>,
!         the <productname>PostgreSQL</> server
          writes the entire content of each disk page to WAL during the
          first modification of that page after a checkpoint.
          This is needed because
***************
*** 1829,1834 **** include 'filename'
--- 1830,1840 ----
         </para>
  
         <para>
+         Valid values are <literal>on</>, <literal>compress</>, and <literal>off</>.
+         The default is <literal>on</>.
+        </para>
+ 
+        <para>
          Turning this parameter off speeds normal operation, but
          might lead to either unrecoverable data corruption, or silent
          data corruption, after a system failure. The risks are similar to turning off
***************
*** 1843,1851 **** include 'filename'
         </para>
  
         <para>
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
-         The default is <literal>on</>.
         </para>
        </listitem>
       </varlistentry>
--- 1849,1861 ----
         </para>
  
         <para>
+         Setting this parameter to <literal>compress</> compresses
+         the full page image to reduce the amount of WAL data.
+        </para>
+ 
+        <para>
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
         </para>
        </listitem>
       </varlistentry>
*** a/src/backend/access/rmgrdesc/xlogdesc.c
--- b/src/backend/access/rmgrdesc/xlogdesc.c
***************
*** 31,36 **** const struct config_enum_entry wal_level_options[] = {
--- 31,51 ----
  	{NULL, 0, false}
  };
  
+ static const char *
+ full_page_writes_str(FullPageWritesLevel level)
+ {
+ 	switch (level)
+ 	{
+ 		case FULL_PAGE_WRITES_ON:
+ 			return "true";
+ 		case FULL_PAGE_WRITES_COMPRESS:
+ 			return "compress";
+ 		case FULL_PAGE_WRITES_OFF:
+ 			return "false";
+ 	}
+ 	return "unrecognized";
+ }
+ 
  void
  xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
  {
***************
*** 48,54 **** xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
  				(uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
  						 checkpoint->ThisTimeLineID,
  						 checkpoint->PrevTimeLineID,
! 						 checkpoint->fullPageWrites ? "true" : "false",
  						 checkpoint->nextXidEpoch, checkpoint->nextXid,
  						 checkpoint->nextOid,
  						 checkpoint->nextMulti,
--- 63,69 ----
  				(uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
  						 checkpoint->ThisTimeLineID,
  						 checkpoint->PrevTimeLineID,
! 						 full_page_writes_str(checkpoint->fullPageWrites),
  						 checkpoint->nextXidEpoch, checkpoint->nextXid,
  						 checkpoint->nextOid,
  						 checkpoint->nextMulti,
***************
*** 126,135 **** xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
  	}
  	else if (info == XLOG_FPW_CHANGE)
  	{
! 		bool		fpw;
  
! 		memcpy(&fpw, rec, sizeof(bool));
! 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
  	}
  	else if (info == XLOG_END_OF_RECOVERY)
  	{
--- 141,150 ----
  	}
  	else if (info == XLOG_FPW_CHANGE)
  	{
! 		int		fpw;
  
! 		memcpy(&fpw, rec, sizeof(int));
! 		appendStringInfo(buf, "full_page_writes: %s", full_page_writes_str(fpw));
  	}
  	else if (info == XLOG_END_OF_RECOVERY)
  	{
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 55,60 ****
--- 55,61 ----
  #include "storage/spin.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
+ #include "utils/pg_lzcompress.h"
  #include "utils/ps_status.h"
  #include "utils/relmapper.h"
  #include "utils/snapmgr.h"
***************
*** 78,84 **** int			XLogArchiveTimeout = 0;
  bool		XLogArchiveMode = false;
  char	   *XLogArchiveCommand = NULL;
  bool		EnableHotStandby = false;
! bool		fullPageWrites = true;
  bool		log_checkpoints = false;
  int			sync_method = DEFAULT_SYNC_METHOD;
  int			wal_level = WAL_LEVEL_MINIMAL;
--- 79,85 ----
  bool		XLogArchiveMode = false;
  char	   *XLogArchiveCommand = NULL;
  bool		EnableHotStandby = false;
! int			fullPageWrites = FULL_PAGE_WRITES_ON;
  bool		log_checkpoints = false;
  int			sync_method = DEFAULT_SYNC_METHOD;
  int			wal_level = WAL_LEVEL_MINIMAL;
***************
*** 165,171 **** static TimeLineID receiveTLI = 0;
   * that the recovery starting checkpoint record indicates, and then updated
   * each time XLOG_FPW_CHANGE record is replayed.
   */
! static bool lastFullPageWrites;
  
  /*
   * Local copy of SharedRecoveryInProgress variable. True actually means "not
--- 166,172 ----
   * that the recovery starting checkpoint record indicates, and then updated
   * each time XLOG_FPW_CHANGE record is replayed.
   */
! static int lastFullPageWrites;
  
  /*
   * Local copy of SharedRecoveryInProgress variable. True actually means "not
***************
*** 796,801 **** static bool ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos,
--- 797,803 ----
  				  XLogRecPtr *PrevPtr);
  static XLogRecPtr WaitXLogInsertionsToFinish(XLogRecPtr upto);
  static void WakeupWaiters(XLogRecPtr EndPos);
+ static char *CompressBackupBlock(char *page, uint32 orig_len, uint32 *len);
  static char *GetXLogBuffer(XLogRecPtr ptr);
  static XLogRecPtr XLogBytePosToRecPtr(uint64 bytepos);
  static XLogRecPtr XLogBytePosToEndRecPtr(uint64 bytepos);
***************
*** 846,851 **** XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata)
--- 848,854 ----
  	static XLogRecord *rechdr;
  	XLogRecPtr	StartPos;
  	XLogRecPtr	EndPos;
+ 	int			fpw;
  
  	if (rechdr == NULL)
  	{
***************
*** 898,908 **** begin:;
  
  	/*
  	 * Decide if we need to do full-page writes in this XLOG record: true if
! 	 * full_page_writes is on or we have a PITR request for it.  Since we
! 	 * don't yet have an insertion slot, fullPageWrites and forcePageWrites
! 	 * could change under us, but we'll recheck them once we have a slot.
  	 */
! 	doPageWrites = Insert->fullPageWrites || Insert->forcePageWrites;
  
  	len = 0;
  	for (rdt = rdata;;)
--- 901,913 ----
  
  	/*
  	 * Decide if we need to do full-page writes in this XLOG record: true if
! 	 * full_page_writes is needed (i.e., on or compress) or we have a PITR
! 	 * request for it.  Since we don't yet have an insertion slot,
! 	 * fullPageWrites and forcePageWrites could change under us, but we'll
! 	 * recheck them once we have a slot.
  	 */
! 	fpw = Insert->fullPageWrites;
! 	doPageWrites = FullPageWritesIsNeeded(fpw) || Insert->forcePageWrites;
  
  	len = 0;
  	for (rdt = rdata;;)
***************
*** 1003,1008 **** begin:;
--- 1008,1026 ----
  		rdt->next = &(dtbuf_rdt2[i]);
  		rdt = rdt->next;
  
+ 		if (fpw <= FULL_PAGE_WRITES_COMPRESS)
+ 		{
+ 			rdt->data = CompressBackupBlock(page, BLCKSZ - bkpb->hole_length, &(rdt->len));
+ 			if (rdt->data != NULL)
+ 			{
+ 				write_len += rdt->len;
+ 				bkpb->hole_length = BLCKSZ - rdt->len;
+ 				bkpb->flags = BKPBLOCK_COMPRESSED;
+ 				rdt->next = NULL;
+ 				continue;
+ 			}
+ 		}
+ 
  		if (bkpb->hole_length == 0)
  		{
  			rdt->data = page;
***************
*** 1133,1144 **** begin:;
  	}
  
  	/*
! 	 * Also check to see if fullPageWrites or forcePageWrites was just turned
! 	 * on; if we weren't already doing full-page writes then go back and
! 	 * recompute. (If it was just turned off, we could recompute the record
! 	 * without full pages, but we choose not to bother.)
  	 */
! 	if ((Insert->fullPageWrites || Insert->forcePageWrites) && !doPageWrites)
  	{
  		/* Oops, must redo it with full-page data. */
  		WALInsertSlotRelease();
--- 1151,1164 ----
  	}
  
  	/*
! 	 * Also check to see if fullPageWrites was just changed on or compress,
! 	 * or if forcePageWrites was just turned on; if we weren't already doing
! 	 * full-page writes then go back and recompute. (If it was just turned off,
! 	 * we could recompute the record without full pages, but we choose not
! 	 * to bother.)
  	 */
! 	if ((FullPageWritesIsNeeded(Insert->fullPageWrites) || Insert->forcePageWrites) &&
! 		!doPageWrites)
  	{
  		/* Oops, must redo it with full-page data. */
  		WALInsertSlotRelease();
***************
*** 2091,2096 **** WaitXLogInsertionsToFinish(XLogRecPtr upto)
--- 2111,2158 ----
  }
  
  /*
+  * 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, uint32 *len)
+ {
+ 	struct varlena *buf;
+ 
+ #define	PGLZ_BLCKSZ	PGLZ_MAX_OUTPUT(BLCKSZ)
+ 
+ 	buf = (struct varlena *) palloc(PGLZ_BLCKSZ);
+ 
+ 	/*
+ 	 * We recheck the actual size even if pglz_compress() reports 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 (pglz_compress(page, BLCKSZ,
+ 					  (PGLZ_Header *) buf, PGLZ_strategy_default) &&
+ 		VARSIZE(buf) < orig_len - 2)
+ 	{
+ 		/* successful compression */
+ 		*len = VARHDRSZ + VARSIZE(buf);
+ 		return (char *) buf;
+ 	}
+ 	else
+ 	{
+ 		/* incompressible data */
+ 		pfree(buf);
+ 		return NULL;
+ 	}
+ }
+ 
+ /*
   * Get a pointer to the right location in the WAL buffer containing the
   * given XLogRecPtr.
   *
***************
*** 2346,2351 **** XLogCheckBuffer(XLogRecData *rdata, bool holdsExclusiveLock,
--- 2408,2414 ----
  		 * The page needs to be backed up, so set up *bkpb
  		 */
  		BufferGetTag(rdata->buffer, &bkpb->node, &bkpb->fork, &bkpb->block);
+ 		bkpb->flags = BKPBLOCK_UNCOMPRESSED;
  
  		if (rdata->buffer_std)
  		{
***************
*** 4307,4313 **** RestoreBackupBlockContents(XLogRecPtr lsn, BkpBlock bkpb, char *blk,
  
  	page = (Page) BufferGetPage(buffer);
  
! 	if (bkpb.hole_length == 0)
  	{
  		memcpy((char *) page, blk, BLCKSZ);
  	}
--- 4370,4381 ----
  
  	page = (Page) BufferGetPage(buffer);
  
! 	if (bkpb.flags == BKPBLOCK_COMPRESSED)
! 	{
! 		/* If it's compressed, decompress it */
! 		pglz_decompress((PGLZ_Header *) blk, (char *) page);
! 	}
! 	else if (bkpb.hole_length == 0)
  	{
  		memcpy((char *) page, blk, BLCKSZ);
  	}
***************
*** 8975,8984 **** UpdateFullPageWrites(void)
  	 * setting it to false, first write the WAL record and then set the global
  	 * flag.
  	 */
! 	if (fullPageWrites)
  	{
  		WALInsertSlotAcquire(true);
! 		Insert->fullPageWrites = true;
  		WALInsertSlotRelease();
  	}
  
--- 9043,9052 ----
  	 * setting it to false, first write the WAL record and then set the global
  	 * flag.
  	 */
! 	if (FullPageWritesIsNeeded(fullPageWrites))
  	{
  		WALInsertSlotAcquire(true);
! 		Insert->fullPageWrites = fullPageWrites;
  		WALInsertSlotRelease();
  	}
  
***************
*** 8991,9007 **** UpdateFullPageWrites(void)
  		XLogRecData rdata;
  
  		rdata.data = (char *) (&fullPageWrites);
! 		rdata.len = sizeof(bool);
  		rdata.buffer = InvalidBuffer;
  		rdata.next = NULL;
  
  		XLogInsert(RM_XLOG_ID, XLOG_FPW_CHANGE, &rdata);
  	}
  
! 	if (!fullPageWrites)
  	{
  		WALInsertSlotAcquire(true);
! 		Insert->fullPageWrites = false;
  		WALInsertSlotRelease();
  	}
  	END_CRIT_SECTION();
--- 9059,9075 ----
  		XLogRecData rdata;
  
  		rdata.data = (char *) (&fullPageWrites);
! 		rdata.len = sizeof(int);
  		rdata.buffer = InvalidBuffer;
  		rdata.next = NULL;
  
  		XLogInsert(RM_XLOG_ID, XLOG_FPW_CHANGE, &rdata);
  	}
  
! 	if (!FullPageWritesIsNeeded(fullPageWrites))
  	{
  		WALInsertSlotAcquire(true);
! 		Insert->fullPageWrites = fullPageWrites;
  		WALInsertSlotRelease();
  	}
  	END_CRIT_SECTION();
***************
*** 9353,9368 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record)
  	{
  		/* use volatile pointer to prevent code rearrangement */
  		volatile XLogCtlData *xlogctl = XLogCtl;
! 		bool		fpw;
  
! 		memcpy(&fpw, XLogRecGetData(record), sizeof(bool));
  
  		/*
  		 * Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
  		 * do_pg_start_backup() and do_pg_stop_backup() can check whether
  		 * full_page_writes has been disabled during online backup.
  		 */
! 		if (!fpw)
  		{
  			SpinLockAcquire(&xlogctl->info_lck);
  			if (xlogctl->lastFpwDisableRecPtr < ReadRecPtr)
--- 9421,9436 ----
  	{
  		/* use volatile pointer to prevent code rearrangement */
  		volatile XLogCtlData *xlogctl = XLogCtl;
! 		int		fpw;
  
! 		memcpy(&fpw, XLogRecGetData(record), sizeof(int));
  
  		/*
  		 * Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
  		 * do_pg_start_backup() and do_pg_stop_backup() can check whether
  		 * full_page_writes has been disabled during online backup.
  		 */
! 		if (!FullPageWritesIsNeeded(fpw))
  		{
  			SpinLockAcquire(&xlogctl->info_lck);
  			if (xlogctl->lastFpwDisableRecPtr < ReadRecPtr)
***************
*** 9686,9692 **** do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
  
  		do
  		{
! 			bool		checkpointfpw;
  
  			/*
  			 * Force a CHECKPOINT.	Aside from being necessary to prevent torn
--- 9754,9760 ----
  
  		do
  		{
! 			int		checkpointfpw;
  
  			/*
  			 * Force a CHECKPOINT.	Aside from being necessary to prevent torn
***************
*** 9737,9743 **** do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
  				recptr = xlogctl->lastFpwDisableRecPtr;
  				SpinLockRelease(&xlogctl->info_lck);
  
! 				if (!checkpointfpw || startpoint <= recptr)
  					ereport(ERROR,
  						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  						   errmsg("WAL generated with full_page_writes=off was replayed "
--- 9805,9811 ----
  				recptr = xlogctl->lastFpwDisableRecPtr;
  				SpinLockRelease(&xlogctl->info_lck);
  
! 				if (!FullPageWritesIsNeeded(checkpointfpw) || startpoint <= recptr)
  					ereport(ERROR,
  						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  						   errmsg("WAL generated with full_page_writes=off was replayed "
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 381,386 **** static const struct config_enum_entry synchronous_commit_options[] = {
--- 381,403 ----
  };
  
  /*
+  * Although only "on", "off", and "compress" are documented, we
+  * accept all the likely variants of "on" and "off".
+  */
+ static const struct config_enum_entry full_page_writes_options[] = {
+ 	{"compress", FULL_PAGE_WRITES_COMPRESS, false},
+ 	{"on", FULL_PAGE_WRITES_ON, false},
+ 	{"off", FULL_PAGE_WRITES_OFF, false},
+ 	{"true", FULL_PAGE_WRITES_ON, true},
+ 	{"false", FULL_PAGE_WRITES_OFF, true},
+ 	{"yes", FULL_PAGE_WRITES_ON, true},
+ 	{"no", FULL_PAGE_WRITES_OFF, true},
+ 	{"1", FULL_PAGE_WRITES_ON, true},
+ 	{"0", FULL_PAGE_WRITES_OFF, true},
+ 	{NULL, 0, false}
+ };
+ 
+ /*
   * Options for enum values stored in other modules
   */
  extern const struct config_enum_entry wal_level_options[];
***************
*** 840,858 **** static struct config_bool ConfigureNamesBool[] =
  		NULL, NULL, NULL
  	},
  	{
- 		{"full_page_writes", PGC_SIGHUP, WAL_SETTINGS,
- 			gettext_noop("Writes full pages to WAL when first modified after a checkpoint."),
- 			gettext_noop("A page write in process during an operating system crash might be "
- 						 "only partially written to disk.  During recovery, the row changes "
- 			  "stored in WAL are not enough to recover.  This option writes "
- 						 "pages when first modified after a checkpoint to WAL so full recovery "
- 						 "is possible.")
- 		},
- 		&fullPageWrites,
- 		true,
- 		NULL, NULL, NULL
- 	},
- 	{
  		{"log_checkpoints", PGC_SIGHUP, LOGGING_WHAT,
  			gettext_noop("Logs each checkpoint."),
  			NULL
--- 857,862 ----
***************
*** 3288,3293 **** static struct config_enum ConfigureNamesEnum[] =
--- 3292,3311 ----
  	},
  
  	{
+ 		{"full_page_writes", PGC_SIGHUP, WAL_SETTINGS,
+ 			gettext_noop("Writes full pages to WAL when first modified after a checkpoint."),
+ 			gettext_noop("A page write in process during an operating system crash might be "
+ 						 "only partially written to disk.  During recovery, the row changes "
+ 			  "stored in WAL are not enough to recover.  This option writes "
+ 						 "pages when first modified after a checkpoint to WAL so full recovery "
+ 						 "is possible.")
+ 		},
+ 		&fullPageWrites,
+ 		FULL_PAGE_WRITES_ON, full_page_writes_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
  			gettext_noop("Enables logging of recovery-related debugging information."),
  			gettext_noop("Each level includes all the levels that follow it. The later"
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 173,179 ****
  					#   fsync
  					#   fsync_writethrough
  					#   open_sync
! #full_page_writes = on			# recover from partial page writes
  #wal_buffers = -1			# min 32kB, -1 sets based on shared_buffers
  					# (change requires restart)
  #wal_writer_delay = 200ms		# 1-10000 milliseconds
--- 173,180 ----
  					#   fsync
  					#   fsync_writethrough
  					#   open_sync
! #full_page_writes = on			# recover from partial page writes;
! 					# off, compress, or on
  #wal_buffers = -1			# min 32kB, -1 sets based on shared_buffers
  					# (change requires restart)
  #wal_writer_delay = 200ms		# 1-10000 milliseconds
*** a/src/bin/pg_controldata/pg_controldata.c
--- b/src/bin/pg_controldata/pg_controldata.c
***************
*** 218,224 **** main(int argc, char *argv[])
  	printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
  		   ControlFile.checkPointCopy.PrevTimeLineID);
  	printf(_("Latest checkpoint's full_page_writes: %s\n"),
! 		   ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
  	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
  		   ControlFile.checkPointCopy.nextXidEpoch,
  		   ControlFile.checkPointCopy.nextXid);
--- 218,224 ----
  	printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
  		   ControlFile.checkPointCopy.PrevTimeLineID);
  	printf(_("Latest checkpoint's full_page_writes: %s\n"),
! 		   FullPageWritesStr(ControlFile.checkPointCopy.fullPageWrites));
  	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
  		   ControlFile.checkPointCopy.nextXidEpoch,
  		   ControlFile.checkPointCopy.nextXid);
*** a/src/bin/pg_resetxlog/pg_resetxlog.c
--- b/src/bin/pg_resetxlog/pg_resetxlog.c
***************
*** 496,502 **** GuessControlValues(void)
  	ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
  	ControlFile.checkPointCopy.ThisTimeLineID = 1;
  	ControlFile.checkPointCopy.PrevTimeLineID = 1;
! 	ControlFile.checkPointCopy.fullPageWrites = false;
  	ControlFile.checkPointCopy.nextXidEpoch = 0;
  	ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
  	ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
--- 496,502 ----
  	ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
  	ControlFile.checkPointCopy.ThisTimeLineID = 1;
  	ControlFile.checkPointCopy.PrevTimeLineID = 1;
! 	ControlFile.checkPointCopy.fullPageWrites = FULL_PAGE_WRITES_OFF;
  	ControlFile.checkPointCopy.nextXidEpoch = 0;
  	ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
  	ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
***************
*** 583,589 **** PrintControlValues(bool guessed)
  	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
  		   ControlFile.checkPointCopy.ThisTimeLineID);
  	printf(_("Latest checkpoint's full_page_writes: %s\n"),
! 		   ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
  	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
  		   ControlFile.checkPointCopy.nextXidEpoch,
  		   ControlFile.checkPointCopy.nextXid);
--- 583,589 ----
  	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
  		   ControlFile.checkPointCopy.ThisTimeLineID);
  	printf(_("Latest checkpoint's full_page_writes: %s\n"),
! 		   FullPageWritesStr(ControlFile.checkPointCopy.fullPageWrites));
  	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
  		   ControlFile.checkPointCopy.nextXidEpoch,
  		   ControlFile.checkPointCopy.nextXid);
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 188,194 **** extern int	XLogArchiveTimeout;
  extern bool XLogArchiveMode;
  extern char *XLogArchiveCommand;
  extern bool EnableHotStandby;
- extern bool fullPageWrites;
  extern bool log_checkpoints;
  extern int	num_xloginsert_slots;
  
--- 188,193 ----
***************
*** 201,206 **** typedef enum WalLevel
--- 200,217 ----
  } WalLevel;
  extern int	wal_level;
  
+ typedef enum FullPageWritesLevel
+ {
+ 	FULL_PAGE_WRITES_OFF = 0,
+ 	FULL_PAGE_WRITES_COMPRESS,
+ 	FULL_PAGE_WRITES_ON
+ } FullPageWritesLevel;
+ extern int	fullPageWrites;
+ #define FullPageWritesIsNeeded(fpw)	(fpw >= FULL_PAGE_WRITES_COMPRESS)
+ #define FullPageWritesStr(fpw)	\
+ 	(fpw == FULL_PAGE_WRITES_ON ? _("on") :	\
+ 	 (fpw == FULL_PAGE_WRITES_OFF ? _("off") : _("compress")))
+ 
  #define XLogArchivingActive()	(XLogArchiveMode && wal_level >= WAL_LEVEL_ARCHIVE)
  #define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0')
  
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 46,57 **** typedef struct BkpBlock
  	RelFileNode node;			/* relation containing block */
  	ForkNumber	fork;			/* fork within the relation */
  	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;
  
  /*
   * Each page of XLOG file has a header like this:
   */
--- 46,61 ----
  	RelFileNode node;			/* relation containing block */
  	ForkNumber	fork;			/* fork within the relation */
  	BlockNumber block;			/* block number */
! 	unsigned	hole_offset:15,	/* number of bytes before "hole" */
! 				flags:2,		/* state of a backup block, see below */
! 				hole_length:15;	/* number of bytes in "hole" */
  
  	/* ACTUAL BLOCK DATA FOLLOWS AT END OF STRUCT */
  } BkpBlock;
  
+ #define BKPBLOCK_UNCOMPRESSED	0	/* uncompressed */
+ #define BKPBLOCK_COMPRESSED		1	/* comperssed */
+ 
  /*
   * Each page of XLOG file has a header like this:
   */
*** a/src/include/catalog/pg_control.h
--- b/src/include/catalog/pg_control.h
***************
*** 35,41 **** typedef struct CheckPoint
  	TimeLineID	ThisTimeLineID; /* current TLI */
  	TimeLineID	PrevTimeLineID; /* previous TLI, if this record begins a new
  								 * timeline (equals ThisTimeLineID otherwise) */
! 	bool		fullPageWrites; /* current full_page_writes */
  	uint32		nextXidEpoch;	/* higher-order bits of nextXid */
  	TransactionId nextXid;		/* next free XID */
  	Oid			nextOid;		/* next free OID */
--- 35,41 ----
  	TimeLineID	ThisTimeLineID; /* current TLI */
  	TimeLineID	PrevTimeLineID; /* previous TLI, if this record begins a new
  								 * timeline (equals ThisTimeLineID otherwise) */
! 	int			fullPageWrites; /* current full_page_writes */
  	uint32		nextXidEpoch;	/* higher-order bits of nextXid */
  	TransactionId nextXid;		/* next free XID */
  	Oid			nextOid;		/* next free OID */
